summaryrefslogtreecommitdiff
path: root/include/llvm/Support
diff options
context:
space:
mode:
Diffstat (limited to 'include/llvm/Support')
-rw-r--r--include/llvm/Support/AArch64TargetParser.def11
-rw-r--r--include/llvm/Support/AMDGPUKernelDescriptor.h139
-rw-r--r--include/llvm/Support/AMDGPUMetadata.h238
-rw-r--r--include/llvm/Support/AMDHSAKernelDescriptor.h185
-rw-r--r--include/llvm/Support/ARMTargetParser.def8
-rw-r--r--include/llvm/Support/AlignOf.h8
-rw-r--r--include/llvm/Support/Allocator.h46
-rw-r--r--include/llvm/Support/AtomicOrdering.h2
-rw-r--r--include/llvm/Support/BinaryByteStream.h24
-rw-r--r--include/llvm/Support/BinaryStream.h18
-rw-r--r--include/llvm/Support/BinaryStreamArray.h2
-rw-r--r--include/llvm/Support/BinaryStreamReader.h2
-rw-r--r--include/llvm/Support/BinaryStreamRef.h4
-rw-r--r--include/llvm/Support/BinaryStreamWriter.h8
-rw-r--r--include/llvm/Support/BlockFrequency.h14
-rw-r--r--include/llvm/Support/BranchProbability.h4
-rw-r--r--include/llvm/Support/CMakeLists.txt14
-rw-r--r--include/llvm/Support/CachePruning.h12
-rw-r--r--include/llvm/Support/Casting.h2
-rw-r--r--include/llvm/Support/CheckedArithmetic.h104
-rw-r--r--include/llvm/Support/CodeGenCWrappers.h62
-rw-r--r--include/llvm/Support/CodeGenCoverage.h7
-rw-r--r--include/llvm/Support/CommandLine.h55
-rw-r--r--include/llvm/Support/Compiler.h79
-rw-r--r--include/llvm/Support/ConvertUTF.h16
-rw-r--r--include/llvm/Support/CrashRecoveryContext.h92
-rw-r--r--include/llvm/Support/DJB.h33
-rw-r--r--include/llvm/Support/DataExtractor.h8
-rw-r--r--include/llvm/Support/DataTypes.h17
-rw-r--r--include/llvm/Support/DataTypes.h.cmake135
-rw-r--r--include/llvm/Support/Debug.h23
-rw-r--r--include/llvm/Support/DebugCounter.h56
-rw-r--r--include/llvm/Support/DynamicLibrary.h8
-rw-r--r--include/llvm/Support/Endian.h2
-rw-r--r--include/llvm/Support/EndianStream.h54
-rw-r--r--include/llvm/Support/Errc.h1
-rw-r--r--include/llvm/Support/Errno.h5
-rw-r--r--include/llvm/Support/Error.h61
-rw-r--r--include/llvm/Support/ErrorHandling.h4
-rw-r--r--include/llvm/Support/ErrorOr.h18
-rw-r--r--include/llvm/Support/FileOutputBuffer.h16
-rw-r--r--include/llvm/Support/FileSystem.h422
-rw-r--r--include/llvm/Support/FormatAdapters.h18
-rw-r--r--include/llvm/Support/FormatVariadic.h13
-rw-r--r--include/llvm/Support/FormatVariadicDetails.h57
-rw-r--r--include/llvm/Support/GenericDomTree.h47
-rw-r--r--include/llvm/Support/GenericDomTreeConstruction.h418
-rw-r--r--include/llvm/Support/GraphWriter.h2
-rw-r--r--include/llvm/Support/Host.h8
-rw-r--r--include/llvm/Support/InitLLVM.h46
-rw-r--r--include/llvm/Support/JSON.h704
-rw-r--r--include/llvm/Support/JamCRC.h2
-rw-r--r--include/llvm/Support/KnownBits.h2
-rw-r--r--include/llvm/Support/LEB128.h17
-rw-r--r--include/llvm/Support/LineIterator.h18
-rw-r--r--include/llvm/Support/LockFileManager.h31
-rw-r--r--include/llvm/Support/LowLevelTypeImpl.h2
-rw-r--r--include/llvm/Support/MD5.h10
-rw-r--r--include/llvm/Support/MachineValueType.h1058
-rw-r--r--include/llvm/Support/MathExtras.h58
-rw-r--r--include/llvm/Support/MemAlloc.h49
-rw-r--r--include/llvm/Support/Memory.h10
-rw-r--r--include/llvm/Support/MemoryBuffer.h79
-rw-r--r--include/llvm/Support/MipsABIFlags.h4
-rw-r--r--include/llvm/Support/Mutex.h13
-rw-r--r--include/llvm/Support/MutexGuard.h2
-rw-r--r--include/llvm/Support/OnDiskHashTable.h47
-rw-r--r--include/llvm/Support/Options.h10
-rw-r--r--include/llvm/Support/Parallel.h10
-rw-r--r--include/llvm/Support/Path.h83
-rw-r--r--include/llvm/Support/PointerLikeTypeTraits.h34
-rw-r--r--include/llvm/Support/Process.h17
-rw-r--r--include/llvm/Support/Program.h64
-rw-r--r--include/llvm/Support/RWMutex.h14
-rw-r--r--include/llvm/Support/Regex.h4
-rw-r--r--include/llvm/Support/SMLoc.h6
-rw-r--r--include/llvm/Support/SaveAndRestore.h12
-rw-r--r--include/llvm/Support/ScaledNumber.h82
-rw-r--r--include/llvm/Support/ScopedPrinter.h10
-rw-r--r--include/llvm/Support/Signals.h20
-rw-r--r--include/llvm/Support/SmallVectorMemoryBuffer.h64
-rw-r--r--include/llvm/Support/SourceMgr.h37
-rw-r--r--include/llvm/Support/StringSaver.h28
-rw-r--r--include/llvm/Support/SystemUtils.h2
-rw-r--r--include/llvm/Support/TargetOpcodes.def482
-rw-r--r--include/llvm/Support/TargetParser.h15
-rw-r--r--include/llvm/Support/TargetRegistry.h112
-rw-r--r--include/llvm/Support/TaskQueue.h139
-rw-r--r--include/llvm/Support/ThreadLocal.h2
-rw-r--r--include/llvm/Support/ThreadPool.h1
-rw-r--r--include/llvm/Support/Threading.h12
-rw-r--r--include/llvm/Support/Timer.h8
-rw-r--r--include/llvm/Support/ToolOutputFile.h4
-rw-r--r--include/llvm/Support/TrailingObjects.h16
-rw-r--r--include/llvm/Support/Unicode.h4
-rw-r--r--include/llvm/Support/UnicodeCharRanges.h26
-rw-r--r--include/llvm/Support/UniqueLock.h2
-rw-r--r--include/llvm/Support/VersionTuple.h154
-rw-r--r--include/llvm/Support/Win64EH.h14
-rw-r--r--include/llvm/Support/WithColor.h67
-rw-r--r--include/llvm/Support/X86DisassemblerDecoderCommon.h475
-rw-r--r--include/llvm/Support/X86TargetParser.def2
-rw-r--r--include/llvm/Support/YAMLParser.h80
-rw-r--r--include/llvm/Support/YAMLTraits.h18
-rw-r--r--include/llvm/Support/raw_ostream.h23
-rw-r--r--include/llvm/Support/type_traits.h47
106 files changed, 5554 insertions, 1380 deletions
diff --git a/include/llvm/Support/AArch64TargetParser.def b/include/llvm/Support/AArch64TargetParser.def
index 30c7924ea5f1..6772e5f9b734 100644
--- a/include/llvm/Support/AArch64TargetParser.def
+++ b/include/llvm/Support/AArch64TargetParser.def
@@ -35,6 +35,11 @@ AARCH64_ARCH("armv8.3-a", ARMV8_3A, "8.3-A", "v8.3a",
(AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
AArch64::AEK_SIMD | AArch64::AEK_RAS | AArch64::AEK_LSE |
AArch64::AEK_RDM | AArch64::AEK_RCPC))
+AARCH64_ARCH("armv8.4-a", ARMV8_4A, "8.4-A", "v8.4a",
+ ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
+ (AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
+ AArch64::AEK_SIMD | AArch64::AEK_RAS | AArch64::AEK_LSE |
+ AArch64::AEK_RDM | AArch64::AEK_RCPC | AArch64::AEK_DOTPROD))
#undef AARCH64_ARCH
#ifndef AARCH64_ARCH_EXT_NAME
@@ -47,6 +52,10 @@ AARCH64_ARCH_EXT_NAME("crc", AArch64::AEK_CRC, "+crc", "-crc")
AARCH64_ARCH_EXT_NAME("lse", AArch64::AEK_LSE, "+lse", "-lse")
AARCH64_ARCH_EXT_NAME("rdm", AArch64::AEK_RDM, "+rdm", "-rdm")
AARCH64_ARCH_EXT_NAME("crypto", AArch64::AEK_CRYPTO, "+crypto","-crypto")
+AARCH64_ARCH_EXT_NAME("sm4", AArch64::AEK_SM4, "+sm4", "-sm4")
+AARCH64_ARCH_EXT_NAME("sha3", AArch64::AEK_SHA3, "+sha3", "-sha3")
+AARCH64_ARCH_EXT_NAME("sha2", AArch64::AEK_SHA2, "+sha2", "-sha2")
+AARCH64_ARCH_EXT_NAME("aes", AArch64::AEK_AES, "+aes", "-aes")
AARCH64_ARCH_EXT_NAME("dotprod", AArch64::AEK_DOTPROD, "+dotprod","-dotprod")
AARCH64_ARCH_EXT_NAME("fp", AArch64::AEK_FP, "+fp-armv8", "-fp-armv8")
AARCH64_ARCH_EXT_NAME("simd", AArch64::AEK_SIMD, "+neon", "-neon")
@@ -82,6 +91,8 @@ AARCH64_CPU_NAME("exynos-m2", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
(AArch64::AEK_CRC))
AARCH64_CPU_NAME("exynos-m3", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
(AArch64::AEK_CRC))
+AARCH64_CPU_NAME("exynos-m4", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+ (AArch64::AEK_CRC))
AARCH64_CPU_NAME("falkor", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
(AArch64::AEK_CRC | AArch64::AEK_RDM))
AARCH64_CPU_NAME("saphira", ARMV8_3A, FK_CRYPTO_NEON_FP_ARMV8, false,
diff --git a/include/llvm/Support/AMDGPUKernelDescriptor.h b/include/llvm/Support/AMDGPUKernelDescriptor.h
deleted file mode 100644
index ce2c0c1c959e..000000000000
--- a/include/llvm/Support/AMDGPUKernelDescriptor.h
+++ /dev/null
@@ -1,139 +0,0 @@
-//===--- AMDGPUKernelDescriptor.h -------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-/// \file
-/// \brief AMDGPU kernel descriptor definitions. For more information, visit
-/// https://llvm.org/docs/AMDGPUUsage.html#kernel-descriptor-for-gfx6-gfx9
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_SUPPORT_AMDGPUKERNELDESCRIPTOR_H
-#define LLVM_SUPPORT_AMDGPUKERNELDESCRIPTOR_H
-
-#include <cstdint>
-
-// Creates enumeration entries used for packing bits into integers. Enumeration
-// entries include bit shift amount, bit width, and bit mask.
-#define AMDGPU_BITS_ENUM_ENTRY(name, shift, width) \
- name ## _SHIFT = (shift), \
- name ## _WIDTH = (width), \
- name = (((1 << (width)) - 1) << (shift)) \
-
-// Gets bits for specified bit mask from specified source.
-#define AMDGPU_BITS_GET(src, mask) \
- ((src & mask) >> mask ## _SHIFT) \
-
-// Sets bits for specified bit mask in specified destination.
-#define AMDGPU_BITS_SET(dst, mask, val) \
- dst &= (~(1 << mask ## _SHIFT) & ~mask); \
- dst |= (((val) << mask ## _SHIFT) & mask) \
-
-namespace llvm {
-namespace AMDGPU {
-namespace HSAKD {
-
-/// \brief Floating point rounding modes.
-enum : uint8_t {
- AMDGPU_FLOAT_ROUND_MODE_NEAR_EVEN = 0,
- AMDGPU_FLOAT_ROUND_MODE_PLUS_INFINITY = 1,
- AMDGPU_FLOAT_ROUND_MODE_MINUS_INFINITY = 2,
- AMDGPU_FLOAT_ROUND_MODE_ZERO = 3,
-};
-
-/// \brief Floating point denorm modes.
-enum : uint8_t {
- AMDGPU_FLOAT_DENORM_MODE_FLUSH_SRC_DST = 0,
- AMDGPU_FLOAT_DENORM_MODE_FLUSH_DST = 1,
- AMDGPU_FLOAT_DENORM_MODE_FLUSH_SRC = 2,
- AMDGPU_FLOAT_DENORM_MODE_FLUSH_NONE = 3,
-};
-
-/// \brief System VGPR workitem IDs.
-enum : uint8_t {
- AMDGPU_SYSTEM_VGPR_WORKITEM_ID_X = 0,
- AMDGPU_SYSTEM_VGPR_WORKITEM_ID_X_Y = 1,
- AMDGPU_SYSTEM_VGPR_WORKITEM_ID_X_Y_Z = 2,
- AMDGPU_SYSTEM_VGPR_WORKITEM_ID_UNDEFINED = 3,
-};
-
-/// \brief Compute program resource register one layout.
-enum ComputePgmRsrc1 {
- AMDGPU_BITS_ENUM_ENTRY(GRANULATED_WORKITEM_VGPR_COUNT, 0, 6),
- AMDGPU_BITS_ENUM_ENTRY(GRANULATED_WAVEFRONT_SGPR_COUNT, 6, 4),
- AMDGPU_BITS_ENUM_ENTRY(PRIORITY, 10, 2),
- AMDGPU_BITS_ENUM_ENTRY(FLOAT_ROUND_MODE_32, 12, 2),
- AMDGPU_BITS_ENUM_ENTRY(FLOAT_ROUND_MODE_16_64, 14, 2),
- AMDGPU_BITS_ENUM_ENTRY(FLOAT_DENORM_MODE_32, 16, 2),
- AMDGPU_BITS_ENUM_ENTRY(FLOAT_DENORM_MODE_16_64, 18, 2),
- AMDGPU_BITS_ENUM_ENTRY(PRIV, 20, 1),
- AMDGPU_BITS_ENUM_ENTRY(ENABLE_DX10_CLAMP, 21, 1),
- AMDGPU_BITS_ENUM_ENTRY(DEBUG_MODE, 22, 1),
- AMDGPU_BITS_ENUM_ENTRY(ENABLE_IEEE_MODE, 23, 1),
- AMDGPU_BITS_ENUM_ENTRY(BULKY, 24, 1),
- AMDGPU_BITS_ENUM_ENTRY(CDBG_USER, 25, 1),
- AMDGPU_BITS_ENUM_ENTRY(FP16_OVFL, 26, 1),
- AMDGPU_BITS_ENUM_ENTRY(RESERVED0, 27, 5),
-};
-
-/// \brief Compute program resource register two layout.
-enum ComputePgmRsrc2 {
- AMDGPU_BITS_ENUM_ENTRY(ENABLE_SGPR_PRIVATE_SEGMENT_WAVE_OFFSET, 0, 1),
- AMDGPU_BITS_ENUM_ENTRY(USER_SGPR_COUNT, 1, 5),
- AMDGPU_BITS_ENUM_ENTRY(ENABLE_TRAP_HANDLER, 6, 1),
- AMDGPU_BITS_ENUM_ENTRY(ENABLE_SGPR_WORKGROUP_ID_X, 7, 1),
- AMDGPU_BITS_ENUM_ENTRY(ENABLE_SGPR_WORKGROUP_ID_Y, 8, 1),
- AMDGPU_BITS_ENUM_ENTRY(ENABLE_SGPR_WORKGROUP_ID_Z, 9, 1),
- AMDGPU_BITS_ENUM_ENTRY(ENABLE_SGPR_WORKGROUP_INFO, 10, 1),
- AMDGPU_BITS_ENUM_ENTRY(ENABLE_VGPR_WORKITEM_ID, 11, 2),
- AMDGPU_BITS_ENUM_ENTRY(ENABLE_EXCEPTION_ADDRESS_WATCH, 13, 1),
- AMDGPU_BITS_ENUM_ENTRY(ENABLE_EXCEPTION_MEMORY, 14, 1),
- AMDGPU_BITS_ENUM_ENTRY(GRANULATED_LDS_SIZE, 15, 9),
- AMDGPU_BITS_ENUM_ENTRY(ENABLE_EXCEPTION_IEEE_754_FP_INVALID_OPERATION, 24, 1),
- AMDGPU_BITS_ENUM_ENTRY(ENABLE_EXCEPTION_FP_DENORMAL_SOURCE, 25, 1),
- AMDGPU_BITS_ENUM_ENTRY(ENABLE_EXCEPTION_IEEE_754_FP_DIVISION_BY_ZERO, 26, 1),
- AMDGPU_BITS_ENUM_ENTRY(ENABLE_EXCEPTION_IEEE_754_FP_OVERFLOW, 27, 1),
- AMDGPU_BITS_ENUM_ENTRY(ENABLE_EXCEPTION_IEEE_754_FP_UNDERFLOW, 28, 1),
- AMDGPU_BITS_ENUM_ENTRY(ENABLE_EXCEPTION_IEEE_754_FP_INEXACT, 29, 1),
- AMDGPU_BITS_ENUM_ENTRY(ENABLE_EXCEPTION_INT_DIVIDE_BY_ZERO, 30, 1),
- AMDGPU_BITS_ENUM_ENTRY(RESERVED1, 31, 1),
-};
-
-/// \brief Kernel descriptor layout. This layout should be kept backwards
-/// compatible as it is consumed by the command processor.
-struct KernelDescriptor final {
- uint32_t GroupSegmentFixedSize;
- uint32_t PrivateSegmentFixedSize;
- uint32_t MaxFlatWorkGroupSize;
- uint64_t IsDynamicCallStack : 1;
- uint64_t IsXNACKEnabled : 1;
- uint64_t Reserved0 : 30;
- int64_t KernelCodeEntryByteOffset;
- uint64_t Reserved1[3];
- uint32_t ComputePgmRsrc1;
- uint32_t ComputePgmRsrc2;
- uint64_t EnableSGPRPrivateSegmentBuffer : 1;
- uint64_t EnableSGPRDispatchPtr : 1;
- uint64_t EnableSGPRQueuePtr : 1;
- uint64_t EnableSGPRKernargSegmentPtr : 1;
- uint64_t EnableSGPRDispatchID : 1;
- uint64_t EnableSGPRFlatScratchInit : 1;
- uint64_t EnableSGPRPrivateSegmentSize : 1;
- uint64_t EnableSGPRGridWorkgroupCountX : 1;
- uint64_t EnableSGPRGridWorkgroupCountY : 1;
- uint64_t EnableSGPRGridWorkgroupCountZ : 1;
- uint64_t Reserved2 : 54;
-
- KernelDescriptor() = default;
-};
-
-} // end namespace HSAKD
-} // end namespace AMDGPU
-} // end namespace llvm
-
-#endif // LLVM_SUPPORT_AMDGPUKERNELDESCRIPTOR_H
diff --git a/include/llvm/Support/AMDGPUMetadata.h b/include/llvm/Support/AMDGPUMetadata.h
index 00039a75c51d..667fb3f3da43 100644
--- a/include/llvm/Support/AMDGPUMetadata.h
+++ b/include/llvm/Support/AMDGPUMetadata.h
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
/// \file
-/// \brief AMDGPU metadata definitions and in-memory representations.
+/// AMDGPU metadata definitions and in-memory representations.
///
//
//===----------------------------------------------------------------------===//
@@ -29,17 +29,17 @@ namespace AMDGPU {
//===----------------------------------------------------------------------===//
namespace HSAMD {
-/// \brief HSA metadata major version.
+/// HSA metadata major version.
constexpr uint32_t VersionMajor = 1;
-/// \brief HSA metadata minor version.
+/// HSA metadata minor version.
constexpr uint32_t VersionMinor = 0;
-/// \brief HSA metadata beginning assembler directive.
+/// HSA metadata beginning assembler directive.
constexpr char AssemblerDirectiveBegin[] = ".amd_amdgpu_hsa_metadata";
-/// \brief HSA metadata ending assembler directive.
+/// HSA metadata ending assembler directive.
constexpr char AssemblerDirectiveEnd[] = ".end_amd_amdgpu_hsa_metadata";
-/// \brief Access qualifiers.
+/// Access qualifiers.
enum class AccessQualifier : uint8_t {
Default = 0,
ReadOnly = 1,
@@ -48,7 +48,7 @@ enum class AccessQualifier : uint8_t {
Unknown = 0xff
};
-/// \brief Address space qualifiers.
+/// Address space qualifiers.
enum class AddressSpaceQualifier : uint8_t {
Private = 0,
Global = 1,
@@ -59,7 +59,7 @@ enum class AddressSpaceQualifier : uint8_t {
Unknown = 0xff
};
-/// \brief Value kinds.
+/// Value kinds.
enum class ValueKind : uint8_t {
ByValue = 0,
GlobalBuffer = 1,
@@ -78,7 +78,7 @@ enum class ValueKind : uint8_t {
Unknown = 0xff
};
-/// \brief Value types.
+/// Value types.
enum class ValueType : uint8_t {
Struct = 0,
I8 = 1,
@@ -106,29 +106,29 @@ namespace Kernel {
namespace Attrs {
namespace Key {
-/// \brief Key for Kernel::Attr::Metadata::mReqdWorkGroupSize.
+/// Key for Kernel::Attr::Metadata::mReqdWorkGroupSize.
constexpr char ReqdWorkGroupSize[] = "ReqdWorkGroupSize";
-/// \brief Key for Kernel::Attr::Metadata::mWorkGroupSizeHint.
+/// Key for Kernel::Attr::Metadata::mWorkGroupSizeHint.
constexpr char WorkGroupSizeHint[] = "WorkGroupSizeHint";
-/// \brief Key for Kernel::Attr::Metadata::mVecTypeHint.
+/// Key for Kernel::Attr::Metadata::mVecTypeHint.
constexpr char VecTypeHint[] = "VecTypeHint";
-/// \brief Key for Kernel::Attr::Metadata::mRuntimeHandle.
+/// Key for Kernel::Attr::Metadata::mRuntimeHandle.
constexpr char RuntimeHandle[] = "RuntimeHandle";
} // end namespace Key
-/// \brief In-memory representation of kernel attributes metadata.
+/// In-memory representation of kernel attributes metadata.
struct Metadata final {
- /// \brief 'reqd_work_group_size' attribute. Optional.
+ /// 'reqd_work_group_size' attribute. Optional.
std::vector<uint32_t> mReqdWorkGroupSize = std::vector<uint32_t>();
- /// \brief 'work_group_size_hint' attribute. Optional.
+ /// 'work_group_size_hint' attribute. Optional.
std::vector<uint32_t> mWorkGroupSizeHint = std::vector<uint32_t>();
- /// \brief 'vec_type_hint' attribute. Optional.
+ /// 'vec_type_hint' attribute. Optional.
std::string mVecTypeHint = std::string();
- /// \brief External symbol created by runtime to store the kernel address
+ /// External symbol created by runtime to store the kernel address
/// for enqueued blocks.
std::string mRuntimeHandle = std::string();
- /// \brief Default constructor.
+ /// Default constructor.
Metadata() = default;
/// \returns True if kernel attributes metadata is empty, false otherwise.
@@ -151,68 +151,68 @@ struct Metadata final {
namespace Arg {
namespace Key {
-/// \brief Key for Kernel::Arg::Metadata::mName.
+/// Key for Kernel::Arg::Metadata::mName.
constexpr char Name[] = "Name";
-/// \brief Key for Kernel::Arg::Metadata::mTypeName.
+/// Key for Kernel::Arg::Metadata::mTypeName.
constexpr char TypeName[] = "TypeName";
-/// \brief Key for Kernel::Arg::Metadata::mSize.
+/// Key for Kernel::Arg::Metadata::mSize.
constexpr char Size[] = "Size";
-/// \brief Key for Kernel::Arg::Metadata::mAlign.
+/// Key for Kernel::Arg::Metadata::mAlign.
constexpr char Align[] = "Align";
-/// \brief Key for Kernel::Arg::Metadata::mValueKind.
+/// Key for Kernel::Arg::Metadata::mValueKind.
constexpr char ValueKind[] = "ValueKind";
-/// \brief Key for Kernel::Arg::Metadata::mValueType.
+/// Key for Kernel::Arg::Metadata::mValueType.
constexpr char ValueType[] = "ValueType";
-/// \brief Key for Kernel::Arg::Metadata::mPointeeAlign.
+/// Key for Kernel::Arg::Metadata::mPointeeAlign.
constexpr char PointeeAlign[] = "PointeeAlign";
-/// \brief Key for Kernel::Arg::Metadata::mAddrSpaceQual.
+/// Key for Kernel::Arg::Metadata::mAddrSpaceQual.
constexpr char AddrSpaceQual[] = "AddrSpaceQual";
-/// \brief Key for Kernel::Arg::Metadata::mAccQual.
+/// Key for Kernel::Arg::Metadata::mAccQual.
constexpr char AccQual[] = "AccQual";
-/// \brief Key for Kernel::Arg::Metadata::mActualAccQual.
+/// Key for Kernel::Arg::Metadata::mActualAccQual.
constexpr char ActualAccQual[] = "ActualAccQual";
-/// \brief Key for Kernel::Arg::Metadata::mIsConst.
+/// Key for Kernel::Arg::Metadata::mIsConst.
constexpr char IsConst[] = "IsConst";
-/// \brief Key for Kernel::Arg::Metadata::mIsRestrict.
+/// Key for Kernel::Arg::Metadata::mIsRestrict.
constexpr char IsRestrict[] = "IsRestrict";
-/// \brief Key for Kernel::Arg::Metadata::mIsVolatile.
+/// Key for Kernel::Arg::Metadata::mIsVolatile.
constexpr char IsVolatile[] = "IsVolatile";
-/// \brief Key for Kernel::Arg::Metadata::mIsPipe.
+/// Key for Kernel::Arg::Metadata::mIsPipe.
constexpr char IsPipe[] = "IsPipe";
} // end namespace Key
-/// \brief In-memory representation of kernel argument metadata.
+/// In-memory representation of kernel argument metadata.
struct Metadata final {
- /// \brief Name. Optional.
+ /// Name. Optional.
std::string mName = std::string();
- /// \brief Type name. Optional.
+ /// Type name. Optional.
std::string mTypeName = std::string();
- /// \brief Size in bytes. Required.
+ /// Size in bytes. Required.
uint32_t mSize = 0;
- /// \brief Alignment in bytes. Required.
+ /// Alignment in bytes. Required.
uint32_t mAlign = 0;
- /// \brief Value kind. Required.
+ /// Value kind. Required.
ValueKind mValueKind = ValueKind::Unknown;
- /// \brief Value type. Required.
+ /// Value type. Required.
ValueType mValueType = ValueType::Unknown;
- /// \brief Pointee alignment in bytes. Optional.
+ /// Pointee alignment in bytes. Optional.
uint32_t mPointeeAlign = 0;
- /// \brief Address space qualifier. Optional.
+ /// Address space qualifier. Optional.
AddressSpaceQualifier mAddrSpaceQual = AddressSpaceQualifier::Unknown;
- /// \brief Access qualifier. Optional.
+ /// Access qualifier. Optional.
AccessQualifier mAccQual = AccessQualifier::Unknown;
- /// \brief Actual access qualifier. Optional.
+ /// Actual access qualifier. Optional.
AccessQualifier mActualAccQual = AccessQualifier::Unknown;
- /// \brief True if 'const' qualifier is specified. Optional.
+ /// True if 'const' qualifier is specified. Optional.
bool mIsConst = false;
- /// \brief True if 'restrict' qualifier is specified. Optional.
+ /// True if 'restrict' qualifier is specified. Optional.
bool mIsRestrict = false;
- /// \brief True if 'volatile' qualifier is specified. Optional.
+ /// True if 'volatile' qualifier is specified. Optional.
bool mIsVolatile = false;
- /// \brief True if 'pipe' qualifier is specified. Optional.
+ /// True if 'pipe' qualifier is specified. Optional.
bool mIsPipe = false;
- /// \brief Default constructor.
+ /// Default constructor.
Metadata() = default;
};
@@ -224,67 +224,67 @@ struct Metadata final {
namespace CodeProps {
namespace Key {
-/// \brief Key for Kernel::CodeProps::Metadata::mKernargSegmentSize.
+/// Key for Kernel::CodeProps::Metadata::mKernargSegmentSize.
constexpr char KernargSegmentSize[] = "KernargSegmentSize";
-/// \brief Key for Kernel::CodeProps::Metadata::mGroupSegmentFixedSize.
+/// Key for Kernel::CodeProps::Metadata::mGroupSegmentFixedSize.
constexpr char GroupSegmentFixedSize[] = "GroupSegmentFixedSize";
-/// \brief Key for Kernel::CodeProps::Metadata::mPrivateSegmentFixedSize.
+/// Key for Kernel::CodeProps::Metadata::mPrivateSegmentFixedSize.
constexpr char PrivateSegmentFixedSize[] = "PrivateSegmentFixedSize";
-/// \brief Key for Kernel::CodeProps::Metadata::mKernargSegmentAlign.
+/// Key for Kernel::CodeProps::Metadata::mKernargSegmentAlign.
constexpr char KernargSegmentAlign[] = "KernargSegmentAlign";
-/// \brief Key for Kernel::CodeProps::Metadata::mWavefrontSize.
+/// Key for Kernel::CodeProps::Metadata::mWavefrontSize.
constexpr char WavefrontSize[] = "WavefrontSize";
-/// \brief Key for Kernel::CodeProps::Metadata::mNumSGPRs.
+/// Key for Kernel::CodeProps::Metadata::mNumSGPRs.
constexpr char NumSGPRs[] = "NumSGPRs";
-/// \brief Key for Kernel::CodeProps::Metadata::mNumVGPRs.
+/// Key for Kernel::CodeProps::Metadata::mNumVGPRs.
constexpr char NumVGPRs[] = "NumVGPRs";
-/// \brief Key for Kernel::CodeProps::Metadata::mMaxFlatWorkGroupSize.
+/// Key for Kernel::CodeProps::Metadata::mMaxFlatWorkGroupSize.
constexpr char MaxFlatWorkGroupSize[] = "MaxFlatWorkGroupSize";
-/// \brief Key for Kernel::CodeProps::Metadata::mIsDynamicCallStack.
+/// Key for Kernel::CodeProps::Metadata::mIsDynamicCallStack.
constexpr char IsDynamicCallStack[] = "IsDynamicCallStack";
-/// \brief Key for Kernel::CodeProps::Metadata::mIsXNACKEnabled.
+/// Key for Kernel::CodeProps::Metadata::mIsXNACKEnabled.
constexpr char IsXNACKEnabled[] = "IsXNACKEnabled";
-/// \brief Key for Kernel::CodeProps::Metadata::mNumSpilledSGPRs.
+/// Key for Kernel::CodeProps::Metadata::mNumSpilledSGPRs.
constexpr char NumSpilledSGPRs[] = "NumSpilledSGPRs";
-/// \brief Key for Kernel::CodeProps::Metadata::mNumSpilledVGPRs.
+/// Key for Kernel::CodeProps::Metadata::mNumSpilledVGPRs.
constexpr char NumSpilledVGPRs[] = "NumSpilledVGPRs";
} // end namespace Key
-/// \brief In-memory representation of kernel code properties metadata.
+/// In-memory representation of kernel code properties metadata.
struct Metadata final {
- /// \brief Size in bytes of the kernarg segment memory. Kernarg segment memory
+ /// Size in bytes of the kernarg segment memory. Kernarg segment memory
/// holds the values of the arguments to the kernel. Required.
uint64_t mKernargSegmentSize = 0;
- /// \brief Size in bytes of the group segment memory required by a workgroup.
+ /// Size in bytes of the group segment memory required by a workgroup.
/// This value does not include any dynamically allocated group segment memory
/// that may be added when the kernel is dispatched. Required.
uint32_t mGroupSegmentFixedSize = 0;
- /// \brief Size in bytes of the private segment memory required by a workitem.
+ /// Size in bytes of the private segment memory required by a workitem.
/// Private segment memory includes arg, spill and private segments. Required.
uint32_t mPrivateSegmentFixedSize = 0;
- /// \brief Maximum byte alignment of variables used by the kernel in the
+ /// Maximum byte alignment of variables used by the kernel in the
/// kernarg memory segment. Required.
uint32_t mKernargSegmentAlign = 0;
- /// \brief Wavefront size. Required.
+ /// Wavefront size. Required.
uint32_t mWavefrontSize = 0;
- /// \brief Total number of SGPRs used by a wavefront. Optional.
+ /// Total number of SGPRs used by a wavefront. Optional.
uint16_t mNumSGPRs = 0;
- /// \brief Total number of VGPRs used by a workitem. Optional.
+ /// Total number of VGPRs used by a workitem. Optional.
uint16_t mNumVGPRs = 0;
- /// \brief Maximum flat work-group size supported by the kernel. Optional.
+ /// Maximum flat work-group size supported by the kernel. Optional.
uint32_t mMaxFlatWorkGroupSize = 0;
- /// \brief True if the generated machine code is using a dynamically sized
+ /// True if the generated machine code is using a dynamically sized
/// call stack. Optional.
bool mIsDynamicCallStack = false;
- /// \brief True if the generated machine code is capable of supporting XNACK.
+ /// True if the generated machine code is capable of supporting XNACK.
/// Optional.
bool mIsXNACKEnabled = false;
- /// \brief Number of SGPRs spilled by a wavefront. Optional.
+ /// Number of SGPRs spilled by a wavefront. Optional.
uint16_t mNumSpilledSGPRs = 0;
- /// \brief Number of VGPRs spilled by a workitem. Optional.
+ /// Number of VGPRs spilled by a workitem. Optional.
uint16_t mNumSpilledVGPRs = 0;
- /// \brief Default constructor.
+ /// Default constructor.
Metadata() = default;
/// \returns True if kernel code properties metadata is empty, false
@@ -308,40 +308,40 @@ struct Metadata final {
namespace DebugProps {
namespace Key {
-/// \brief Key for Kernel::DebugProps::Metadata::mDebuggerABIVersion.
+/// Key for Kernel::DebugProps::Metadata::mDebuggerABIVersion.
constexpr char DebuggerABIVersion[] = "DebuggerABIVersion";
-/// \brief Key for Kernel::DebugProps::Metadata::mReservedNumVGPRs.
+/// Key for Kernel::DebugProps::Metadata::mReservedNumVGPRs.
constexpr char ReservedNumVGPRs[] = "ReservedNumVGPRs";
-/// \brief Key for Kernel::DebugProps::Metadata::mReservedFirstVGPR.
+/// Key for Kernel::DebugProps::Metadata::mReservedFirstVGPR.
constexpr char ReservedFirstVGPR[] = "ReservedFirstVGPR";
-/// \brief Key for Kernel::DebugProps::Metadata::mPrivateSegmentBufferSGPR.
+/// Key for Kernel::DebugProps::Metadata::mPrivateSegmentBufferSGPR.
constexpr char PrivateSegmentBufferSGPR[] = "PrivateSegmentBufferSGPR";
-/// \brief Key for
+/// Key for
/// Kernel::DebugProps::Metadata::mWavefrontPrivateSegmentOffsetSGPR.
constexpr char WavefrontPrivateSegmentOffsetSGPR[] =
"WavefrontPrivateSegmentOffsetSGPR";
} // end namespace Key
-/// \brief In-memory representation of kernel debug properties metadata.
+/// In-memory representation of kernel debug properties metadata.
struct Metadata final {
- /// \brief Debugger ABI version. Optional.
+ /// Debugger ABI version. Optional.
std::vector<uint32_t> mDebuggerABIVersion = std::vector<uint32_t>();
- /// \brief Consecutive number of VGPRs reserved for debugger use. Must be 0 if
+ /// Consecutive number of VGPRs reserved for debugger use. Must be 0 if
/// mDebuggerABIVersion is not set. Optional.
uint16_t mReservedNumVGPRs = 0;
- /// \brief First fixed VGPR reserved. Must be uint16_t(-1) if
+ /// First fixed VGPR reserved. Must be uint16_t(-1) if
/// mDebuggerABIVersion is not set or mReservedFirstVGPR is 0. Optional.
uint16_t mReservedFirstVGPR = uint16_t(-1);
- /// \brief Fixed SGPR of the first of 4 SGPRs used to hold the scratch V# used
+ /// Fixed SGPR of the first of 4 SGPRs used to hold the scratch V# used
/// for the entire kernel execution. Must be uint16_t(-1) if
/// mDebuggerABIVersion is not set or SGPR not used or not known. Optional.
uint16_t mPrivateSegmentBufferSGPR = uint16_t(-1);
- /// \brief Fixed SGPR used to hold the wave scratch offset for the entire
+ /// Fixed SGPR used to hold the wave scratch offset for the entire
/// kernel execution. Must be uint16_t(-1) if mDebuggerABIVersion is not set
/// or SGPR is not used or not known. Optional.
uint16_t mWavefrontPrivateSegmentOffsetSGPR = uint16_t(-1);
- /// \brief Default constructor.
+ /// Default constructor.
Metadata() = default;
/// \returns True if kernel debug properties metadata is empty, false
@@ -360,75 +360,75 @@ struct Metadata final {
} // end namespace DebugProps
namespace Key {
-/// \brief Key for Kernel::Metadata::mName.
+/// Key for Kernel::Metadata::mName.
constexpr char Name[] = "Name";
-/// \brief Key for Kernel::Metadata::mSymbolName.
+/// Key for Kernel::Metadata::mSymbolName.
constexpr char SymbolName[] = "SymbolName";
-/// \brief Key for Kernel::Metadata::mLanguage.
+/// Key for Kernel::Metadata::mLanguage.
constexpr char Language[] = "Language";
-/// \brief Key for Kernel::Metadata::mLanguageVersion.
+/// Key for Kernel::Metadata::mLanguageVersion.
constexpr char LanguageVersion[] = "LanguageVersion";
-/// \brief Key for Kernel::Metadata::mAttrs.
+/// Key for Kernel::Metadata::mAttrs.
constexpr char Attrs[] = "Attrs";
-/// \brief Key for Kernel::Metadata::mArgs.
+/// Key for Kernel::Metadata::mArgs.
constexpr char Args[] = "Args";
-/// \brief Key for Kernel::Metadata::mCodeProps.
+/// Key for Kernel::Metadata::mCodeProps.
constexpr char CodeProps[] = "CodeProps";
-/// \brief Key for Kernel::Metadata::mDebugProps.
+/// Key for Kernel::Metadata::mDebugProps.
constexpr char DebugProps[] = "DebugProps";
} // end namespace Key
-/// \brief In-memory representation of kernel metadata.
+/// In-memory representation of kernel metadata.
struct Metadata final {
- /// \brief Kernel source name. Required.
+ /// Kernel source name. Required.
std::string mName = std::string();
- /// \brief Kernel descriptor name. Required.
+ /// Kernel descriptor name. Required.
std::string mSymbolName = std::string();
- /// \brief Language. Optional.
+ /// Language. Optional.
std::string mLanguage = std::string();
- /// \brief Language version. Optional.
+ /// Language version. Optional.
std::vector<uint32_t> mLanguageVersion = std::vector<uint32_t>();
- /// \brief Attributes metadata. Optional.
+ /// Attributes metadata. Optional.
Attrs::Metadata mAttrs = Attrs::Metadata();
- /// \brief Arguments metadata. Optional.
+ /// Arguments metadata. Optional.
std::vector<Arg::Metadata> mArgs = std::vector<Arg::Metadata>();
- /// \brief Code properties metadata. Optional.
+ /// Code properties metadata. Optional.
CodeProps::Metadata mCodeProps = CodeProps::Metadata();
- /// \brief Debug properties metadata. Optional.
+ /// Debug properties metadata. Optional.
DebugProps::Metadata mDebugProps = DebugProps::Metadata();
- /// \brief Default constructor.
+ /// Default constructor.
Metadata() = default;
};
} // end namespace Kernel
namespace Key {
-/// \brief Key for HSA::Metadata::mVersion.
+/// Key for HSA::Metadata::mVersion.
constexpr char Version[] = "Version";
-/// \brief Key for HSA::Metadata::mPrintf.
+/// Key for HSA::Metadata::mPrintf.
constexpr char Printf[] = "Printf";
-/// \brief Key for HSA::Metadata::mKernels.
+/// Key for HSA::Metadata::mKernels.
constexpr char Kernels[] = "Kernels";
} // end namespace Key
-/// \brief In-memory representation of HSA metadata.
+/// In-memory representation of HSA metadata.
struct Metadata final {
- /// \brief HSA metadata version. Required.
+ /// HSA metadata version. Required.
std::vector<uint32_t> mVersion = std::vector<uint32_t>();
- /// \brief Printf metadata. Optional.
+ /// Printf metadata. Optional.
std::vector<std::string> mPrintf = std::vector<std::string>();
- /// \brief Kernels metadata. Required.
+ /// Kernels metadata. Required.
std::vector<Kernel::Metadata> mKernels = std::vector<Kernel::Metadata>();
- /// \brief Default constructor.
+ /// Default constructor.
Metadata() = default;
};
-/// \brief Converts \p String to \p HSAMetadata.
+/// Converts \p String to \p HSAMetadata.
std::error_code fromString(std::string String, Metadata &HSAMetadata);
-/// \brief Converts \p HSAMetadata to \p String.
+/// Converts \p HSAMetadata to \p String.
std::error_code toString(Metadata HSAMetadata, std::string &String);
} // end namespace HSAMD
@@ -438,10 +438,10 @@ std::error_code toString(Metadata HSAMetadata, std::string &String);
//===----------------------------------------------------------------------===//
namespace PALMD {
-/// \brief PAL metadata assembler directive.
+/// PAL metadata assembler directive.
constexpr char AssemblerDirective[] = ".amd_amdgpu_pal_metadata";
-/// \brief PAL metadata keys.
+/// PAL metadata keys.
enum Key : uint32_t {
LS_NUM_USED_VGPRS = 0x10000021,
HS_NUM_USED_VGPRS = 0x10000022,
@@ -468,10 +468,10 @@ enum Key : uint32_t {
CS_SCRATCH_SIZE = 0x1000004a
};
-/// \brief PAL metadata represented as a vector.
+/// PAL metadata represented as a vector.
typedef std::vector<uint32_t> Metadata;
-/// \brief Converts \p PALMetadata to \p String.
+/// Converts \p PALMetadata to \p String.
std::error_code toString(const Metadata &PALMetadata, std::string &String);
} // end namespace PALMD
diff --git a/include/llvm/Support/AMDHSAKernelDescriptor.h b/include/llvm/Support/AMDHSAKernelDescriptor.h
new file mode 100644
index 000000000000..751699e3a19f
--- /dev/null
+++ b/include/llvm/Support/AMDHSAKernelDescriptor.h
@@ -0,0 +1,185 @@
+//===--- AMDHSAKernelDescriptor.h -----------------------------*- C++ -*---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// AMDHSA kernel descriptor definitions. For more information, visit
+/// https://llvm.org/docs/AMDGPUUsage.html#kernel-descriptor
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_AMDHSAKERNELDESCRIPTOR_H
+#define LLVM_SUPPORT_AMDHSAKERNELDESCRIPTOR_H
+
+#include <cstddef>
+#include <cstdint>
+
+// Gets offset of specified member in specified type.
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE*)0)->MEMBER)
+#endif // offsetof
+
+// Creates enumeration entries used for packing bits into integers. Enumeration
+// entries include bit shift amount, bit width, and bit mask.
+#ifndef AMDHSA_BITS_ENUM_ENTRY
+#define AMDHSA_BITS_ENUM_ENTRY(NAME, SHIFT, WIDTH) \
+ NAME ## _SHIFT = (SHIFT), \
+ NAME ## _WIDTH = (WIDTH), \
+ NAME = (((1 << (WIDTH)) - 1) << (SHIFT))
+#endif // AMDHSA_BITS_ENUM_ENTRY
+
+// Gets bits for specified bit mask from specified source.
+#ifndef AMDHSA_BITS_GET
+#define AMDHSA_BITS_GET(SRC, MSK) ((SRC & MSK) >> MSK ## _SHIFT)
+#endif // AMDHSA_BITS_GET
+
+// Sets bits for specified bit mask in specified destination.
+#ifndef AMDHSA_BITS_SET
+#define AMDHSA_BITS_SET(DST, MSK, VAL) \
+ DST &= ~MSK; \
+ DST |= ((VAL << MSK ## _SHIFT) & MSK)
+#endif // AMDHSA_BITS_SET
+
+namespace llvm {
+namespace amdhsa {
+
+// Floating point rounding modes. Must match hardware definition.
+enum : uint8_t {
+ FLOAT_ROUND_MODE_NEAR_EVEN = 0,
+ FLOAT_ROUND_MODE_PLUS_INFINITY = 1,
+ FLOAT_ROUND_MODE_MINUS_INFINITY = 2,
+ FLOAT_ROUND_MODE_ZERO = 3,
+};
+
+// Floating point denorm modes. Must match hardware definition.
+enum : uint8_t {
+ FLOAT_DENORM_MODE_FLUSH_SRC_DST = 0,
+ FLOAT_DENORM_MODE_FLUSH_DST = 1,
+ FLOAT_DENORM_MODE_FLUSH_SRC = 2,
+ FLOAT_DENORM_MODE_FLUSH_NONE = 3,
+};
+
+// System VGPR workitem IDs. Must match hardware definition.
+enum : uint8_t {
+ SYSTEM_VGPR_WORKITEM_ID_X = 0,
+ SYSTEM_VGPR_WORKITEM_ID_X_Y = 1,
+ SYSTEM_VGPR_WORKITEM_ID_X_Y_Z = 2,
+ SYSTEM_VGPR_WORKITEM_ID_UNDEFINED = 3,
+};
+
+// Compute program resource register 1. Must match hardware definition.
+#define COMPUTE_PGM_RSRC1(NAME, SHIFT, WIDTH) \
+ AMDHSA_BITS_ENUM_ENTRY(COMPUTE_PGM_RSRC1_ ## NAME, SHIFT, WIDTH)
+enum : int32_t {
+ COMPUTE_PGM_RSRC1(GRANULATED_WORKITEM_VGPR_COUNT, 0, 6),
+ COMPUTE_PGM_RSRC1(GRANULATED_WAVEFRONT_SGPR_COUNT, 6, 4),
+ COMPUTE_PGM_RSRC1(PRIORITY, 10, 2),
+ COMPUTE_PGM_RSRC1(FLOAT_ROUND_MODE_32, 12, 2),
+ COMPUTE_PGM_RSRC1(FLOAT_ROUND_MODE_16_64, 14, 2),
+ COMPUTE_PGM_RSRC1(FLOAT_DENORM_MODE_32, 16, 2),
+ COMPUTE_PGM_RSRC1(FLOAT_DENORM_MODE_16_64, 18, 2),
+ COMPUTE_PGM_RSRC1(PRIV, 20, 1),
+ COMPUTE_PGM_RSRC1(ENABLE_DX10_CLAMP, 21, 1),
+ COMPUTE_PGM_RSRC1(DEBUG_MODE, 22, 1),
+ COMPUTE_PGM_RSRC1(ENABLE_IEEE_MODE, 23, 1),
+ COMPUTE_PGM_RSRC1(BULKY, 24, 1),
+ COMPUTE_PGM_RSRC1(CDBG_USER, 25, 1),
+ COMPUTE_PGM_RSRC1(FP16_OVFL, 26, 1), // GFX9+
+ COMPUTE_PGM_RSRC1(RESERVED0, 27, 5),
+};
+#undef COMPUTE_PGM_RSRC1
+
+// Compute program resource register 2. Must match hardware definition.
+#define COMPUTE_PGM_RSRC2(NAME, SHIFT, WIDTH) \
+ AMDHSA_BITS_ENUM_ENTRY(COMPUTE_PGM_RSRC2_ ## NAME, SHIFT, WIDTH)
+enum : int32_t {
+ COMPUTE_PGM_RSRC2(ENABLE_SGPR_PRIVATE_SEGMENT_WAVEFRONT_OFFSET, 0, 1),
+ COMPUTE_PGM_RSRC2(USER_SGPR_COUNT, 1, 5),
+ COMPUTE_PGM_RSRC2(ENABLE_TRAP_HANDLER, 6, 1),
+ COMPUTE_PGM_RSRC2(ENABLE_SGPR_WORKGROUP_ID_X, 7, 1),
+ COMPUTE_PGM_RSRC2(ENABLE_SGPR_WORKGROUP_ID_Y, 8, 1),
+ COMPUTE_PGM_RSRC2(ENABLE_SGPR_WORKGROUP_ID_Z, 9, 1),
+ COMPUTE_PGM_RSRC2(ENABLE_SGPR_WORKGROUP_INFO, 10, 1),
+ COMPUTE_PGM_RSRC2(ENABLE_VGPR_WORKITEM_ID, 11, 2),
+ COMPUTE_PGM_RSRC2(ENABLE_EXCEPTION_ADDRESS_WATCH, 13, 1),
+ COMPUTE_PGM_RSRC2(ENABLE_EXCEPTION_MEMORY, 14, 1),
+ COMPUTE_PGM_RSRC2(GRANULATED_LDS_SIZE, 15, 9),
+ COMPUTE_PGM_RSRC2(ENABLE_EXCEPTION_IEEE_754_FP_INVALID_OPERATION, 24, 1),
+ COMPUTE_PGM_RSRC2(ENABLE_EXCEPTION_FP_DENORMAL_SOURCE, 25, 1),
+ COMPUTE_PGM_RSRC2(ENABLE_EXCEPTION_IEEE_754_FP_DIVISION_BY_ZERO, 26, 1),
+ COMPUTE_PGM_RSRC2(ENABLE_EXCEPTION_IEEE_754_FP_OVERFLOW, 27, 1),
+ COMPUTE_PGM_RSRC2(ENABLE_EXCEPTION_IEEE_754_FP_UNDERFLOW, 28, 1),
+ COMPUTE_PGM_RSRC2(ENABLE_EXCEPTION_IEEE_754_FP_INEXACT, 29, 1),
+ COMPUTE_PGM_RSRC2(ENABLE_EXCEPTION_INT_DIVIDE_BY_ZERO, 30, 1),
+ COMPUTE_PGM_RSRC2(RESERVED0, 31, 1),
+};
+#undef COMPUTE_PGM_RSRC2
+
+// Kernel code properties. Must be kept backwards compatible.
+#define KERNEL_CODE_PROPERTY(NAME, SHIFT, WIDTH) \
+ AMDHSA_BITS_ENUM_ENTRY(KERNEL_CODE_PROPERTY_ ## NAME, SHIFT, WIDTH)
+enum : int32_t {
+ KERNEL_CODE_PROPERTY(ENABLE_SGPR_PRIVATE_SEGMENT_BUFFER, 0, 1),
+ KERNEL_CODE_PROPERTY(ENABLE_SGPR_DISPATCH_PTR, 1, 1),
+ KERNEL_CODE_PROPERTY(ENABLE_SGPR_QUEUE_PTR, 2, 1),
+ KERNEL_CODE_PROPERTY(ENABLE_SGPR_KERNARG_SEGMENT_PTR, 3, 1),
+ KERNEL_CODE_PROPERTY(ENABLE_SGPR_DISPATCH_ID, 4, 1),
+ KERNEL_CODE_PROPERTY(ENABLE_SGPR_FLAT_SCRATCH_INIT, 5, 1),
+ KERNEL_CODE_PROPERTY(ENABLE_SGPR_PRIVATE_SEGMENT_SIZE, 6, 1),
+ KERNEL_CODE_PROPERTY(RESERVED0, 7, 9),
+};
+#undef KERNEL_CODE_PROPERTY
+
+// Kernel descriptor. Must be kept backwards compatible.
+struct kernel_descriptor_t {
+ uint32_t group_segment_fixed_size;
+ uint32_t private_segment_fixed_size;
+ uint8_t reserved0[8];
+ int64_t kernel_code_entry_byte_offset;
+ uint8_t reserved1[24];
+ uint32_t compute_pgm_rsrc1;
+ uint32_t compute_pgm_rsrc2;
+ uint16_t kernel_code_properties;
+ uint8_t reserved2[6];
+};
+
+static_assert(
+ sizeof(kernel_descriptor_t) == 64,
+ "invalid size for kernel_descriptor_t");
+static_assert(
+ offsetof(kernel_descriptor_t, group_segment_fixed_size) == 0,
+ "invalid offset for group_segment_fixed_size");
+static_assert(
+ offsetof(kernel_descriptor_t, private_segment_fixed_size) == 4,
+ "invalid offset for private_segment_fixed_size");
+static_assert(
+ offsetof(kernel_descriptor_t, reserved0) == 8,
+ "invalid offset for reserved0");
+static_assert(
+ offsetof(kernel_descriptor_t, kernel_code_entry_byte_offset) == 16,
+ "invalid offset for kernel_code_entry_byte_offset");
+static_assert(
+ offsetof(kernel_descriptor_t, reserved1) == 24,
+ "invalid offset for reserved1");
+static_assert(
+ offsetof(kernel_descriptor_t, compute_pgm_rsrc1) == 48,
+ "invalid offset for compute_pgm_rsrc1");
+static_assert(
+ offsetof(kernel_descriptor_t, compute_pgm_rsrc2) == 52,
+ "invalid offset for compute_pgm_rsrc2");
+static_assert(
+ offsetof(kernel_descriptor_t, kernel_code_properties) == 56,
+ "invalid offset for kernel_code_properties");
+static_assert(
+ offsetof(kernel_descriptor_t, reserved2) == 58,
+ "invalid offset for reserved2");
+
+} // end namespace amdhsa
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_AMDHSAKERNELDESCRIPTOR_H
diff --git a/include/llvm/Support/ARMTargetParser.def b/include/llvm/Support/ARMTargetParser.def
index 6c8eff1a8f84..78f5410fb733 100644
--- a/include/llvm/Support/ARMTargetParser.def
+++ b/include/llvm/Support/ARMTargetParser.def
@@ -101,6 +101,11 @@ ARM_ARCH("armv8.3-a", ARMV8_3A, "8.3-A", "v8.3a",
ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
(ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC | ARM::AEK_RAS))
+ARM_ARCH("armv8.4-a", ARMV8_4A, "8.4-A", "v8.4a",
+ ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
+ (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC | ARM::AEK_RAS |
+ ARM::AEK_DOTPROD))
ARM_ARCH("armv8-r", ARMV8R, "8-R", "v8r", ARMBuildAttrs::CPUArch::v8_R,
FK_NEON_FP_ARMV8,
(ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB |
@@ -130,6 +135,8 @@ ARM_ARCH_EXT_NAME("invalid", ARM::AEK_INVALID, nullptr, nullptr)
ARM_ARCH_EXT_NAME("none", ARM::AEK_NONE, nullptr, nullptr)
ARM_ARCH_EXT_NAME("crc", ARM::AEK_CRC, "+crc", "-crc")
ARM_ARCH_EXT_NAME("crypto", ARM::AEK_CRYPTO, "+crypto","-crypto")
+ARM_ARCH_EXT_NAME("sha2", ARM::AEK_SHA2, "+sha2", "-sha2")
+ARM_ARCH_EXT_NAME("aes", ARM::AEK_AES, "+aes", "-aes")
ARM_ARCH_EXT_NAME("dotprod", ARM::AEK_DOTPROD, "+dotprod","-dotprod")
ARM_ARCH_EXT_NAME("dsp", ARM::AEK_DSP, "+dsp", "-dsp")
ARM_ARCH_EXT_NAME("fp", ARM::AEK_FP, nullptr, nullptr)
@@ -253,6 +260,7 @@ ARM_CPU_NAME("cyclone", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
ARM_CPU_NAME("exynos-m1", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
ARM_CPU_NAME("exynos-m2", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
ARM_CPU_NAME("exynos-m3", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
+ARM_CPU_NAME("exynos-m4", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
ARM_CPU_NAME("kryo", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
// Non-standard Arch names.
ARM_CPU_NAME("iwmmxt", IWMMXT, FK_NONE, true, ARM::AEK_NONE)
diff --git a/include/llvm/Support/AlignOf.h b/include/llvm/Support/AlignOf.h
index abd19afa22f0..9e7a62b85e34 100644
--- a/include/llvm/Support/AlignOf.h
+++ b/include/llvm/Support/AlignOf.h
@@ -20,7 +20,7 @@
namespace llvm {
/// \struct AlignedCharArray
-/// \brief Helper for building an aligned character array type.
+/// Helper for building an aligned character array type.
///
/// This template is used to explicitly build up a collection of aligned
/// character array types. We have to build these up using a macro and explicit
@@ -34,12 +34,12 @@ namespace llvm {
template<std::size_t Alignment, std::size_t Size>
struct AlignedCharArray {
- LLVM_ALIGNAS(Alignment) char buffer[Size];
+ alignas(Alignment) char buffer[Size];
};
#else // _MSC_VER
-/// \brief Create a type with an aligned char buffer.
+/// Create a type with an aligned char buffer.
template<std::size_t Alignment, std::size_t Size>
struct AlignedCharArray;
@@ -124,7 +124,7 @@ union SizerImpl {
};
} // end namespace detail
-/// \brief This union template exposes a suitably aligned and sized character
+/// This union template exposes a suitably aligned and sized character
/// array member which can hold elements of any of up to ten types.
///
/// These types may be arrays, structs, or any other types. The goal is to
diff --git a/include/llvm/Support/Allocator.h b/include/llvm/Support/Allocator.h
index a94aa8fb1f2a..184ac491b1f1 100644
--- a/include/llvm/Support/Allocator.h
+++ b/include/llvm/Support/Allocator.h
@@ -23,7 +23,9 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MemAlloc.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
@@ -35,7 +37,7 @@
namespace llvm {
-/// \brief CRTP base class providing obvious overloads for the core \c
+/// CRTP base class providing obvious overloads for the core \c
/// Allocate() methods of LLVM-style allocators.
///
/// This base class both documents the full public interface exposed by all
@@ -43,7 +45,7 @@ namespace llvm {
/// set of methods which the derived class must define.
template <typename DerivedT> class AllocatorBase {
public:
- /// \brief Allocate \a Size bytes of \a Alignment aligned memory. This method
+ /// Allocate \a Size bytes of \a Alignment aligned memory. This method
/// must be implemented by \c DerivedT.
void *Allocate(size_t Size, size_t Alignment) {
#ifdef __clang__
@@ -57,7 +59,7 @@ public:
return static_cast<DerivedT *>(this)->Allocate(Size, Alignment);
}
- /// \brief Deallocate \a Ptr to \a Size bytes of memory allocated by this
+ /// Deallocate \a Ptr to \a Size bytes of memory allocated by this
/// allocator.
void Deallocate(const void *Ptr, size_t Size) {
#ifdef __clang__
@@ -74,12 +76,12 @@ public:
// The rest of these methods are helpers that redirect to one of the above
// core methods.
- /// \brief Allocate space for a sequence of objects without constructing them.
+ /// Allocate space for a sequence of objects without constructing them.
template <typename T> T *Allocate(size_t Num = 1) {
return static_cast<T *>(Allocate(Num * sizeof(T), alignof(T)));
}
- /// \brief Deallocate space for a sequence of objects without constructing them.
+ /// Deallocate space for a sequence of objects without constructing them.
template <typename T>
typename std::enable_if<
!std::is_same<typename std::remove_cv<T>::type, void>::value, void>::type
@@ -94,7 +96,7 @@ public:
LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t Size,
size_t /*Alignment*/) {
- return malloc(Size);
+ return safe_malloc(Size);
}
// Pull in base class overloads.
@@ -119,7 +121,7 @@ void printBumpPtrAllocatorStats(unsigned NumSlabs, size_t BytesAllocated,
} // end namespace detail
-/// \brief Allocate memory in an ever growing pool, as if by bump-pointer.
+/// Allocate memory in an ever growing pool, as if by bump-pointer.
///
/// This isn't strictly a bump-pointer allocator as it uses backing slabs of
/// memory rather than relying on a boundless contiguous heap. However, it has
@@ -187,7 +189,7 @@ public:
return *this;
}
- /// \brief Deallocate all but the current slab and reset the current pointer
+ /// Deallocate all but the current slab and reset the current pointer
/// to the beginning of it, freeing all memory allocated so far.
void Reset() {
// Deallocate all but the first slab, and deallocate all custom-sized slabs.
@@ -207,7 +209,7 @@ public:
Slabs.erase(std::next(Slabs.begin()), Slabs.end());
}
- /// \brief Allocate space at the specified alignment.
+ /// Allocate space at the specified alignment.
LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void *
Allocate(size_t Size, size_t Alignment) {
assert(Alignment > 0 && "0-byte alignnment is not allowed. Use 1 instead.");
@@ -302,30 +304,30 @@ public:
}
private:
- /// \brief The current pointer into the current slab.
+ /// The current pointer into the current slab.
///
/// This points to the next free byte in the slab.
char *CurPtr = nullptr;
- /// \brief The end of the current slab.
+ /// The end of the current slab.
char *End = nullptr;
- /// \brief The slabs allocated so far.
+ /// The slabs allocated so far.
SmallVector<void *, 4> Slabs;
- /// \brief Custom-sized slabs allocated for too-large allocation requests.
+ /// Custom-sized slabs allocated for too-large allocation requests.
SmallVector<std::pair<void *, size_t>, 0> CustomSizedSlabs;
- /// \brief How many bytes we've allocated.
+ /// How many bytes we've allocated.
///
/// Used so that we can compute how much space was wasted.
size_t BytesAllocated = 0;
- /// \brief The number of bytes to put between allocations when running under
+ /// The number of bytes to put between allocations when running under
/// a sanitizer.
size_t RedZoneSize = 1;
- /// \brief The allocator instance we use to get slabs of memory.
+ /// The allocator instance we use to get slabs of memory.
AllocatorT Allocator;
static size_t computeSlabSize(unsigned SlabIdx) {
@@ -336,7 +338,7 @@ private:
return SlabSize * ((size_t)1 << std::min<size_t>(30, SlabIdx / 128));
}
- /// \brief Allocate a new slab and move the bump pointers over into the new
+ /// Allocate a new slab and move the bump pointers over into the new
/// slab, modifying CurPtr and End.
void StartNewSlab() {
size_t AllocatedSlabSize = computeSlabSize(Slabs.size());
@@ -351,7 +353,7 @@ private:
End = ((char *)NewSlab) + AllocatedSlabSize;
}
- /// \brief Deallocate a sequence of slabs.
+ /// Deallocate a sequence of slabs.
void DeallocateSlabs(SmallVectorImpl<void *>::iterator I,
SmallVectorImpl<void *>::iterator E) {
for (; I != E; ++I) {
@@ -361,7 +363,7 @@ private:
}
}
- /// \brief Deallocate all memory for custom sized slabs.
+ /// Deallocate all memory for custom sized slabs.
void DeallocateCustomSizedSlabs() {
for (auto &PtrAndSize : CustomSizedSlabs) {
void *Ptr = PtrAndSize.first;
@@ -373,11 +375,11 @@ private:
template <typename T> friend class SpecificBumpPtrAllocator;
};
-/// \brief The standard BumpPtrAllocator which just uses the default template
+/// The standard BumpPtrAllocator which just uses the default template
/// parameters.
typedef BumpPtrAllocatorImpl<> BumpPtrAllocator;
-/// \brief A BumpPtrAllocator that allows only elements of a specific type to be
+/// A BumpPtrAllocator that allows only elements of a specific type to be
/// allocated.
///
/// This allows calling the destructor in DestroyAll() and when the allocator is
@@ -430,7 +432,7 @@ public:
Allocator.Reset();
}
- /// \brief Allocate space for an array of objects without constructing them.
+ /// Allocate space for an array of objects without constructing them.
T *Allocate(size_t num = 1) { return Allocator.Allocate<T>(num); }
};
diff --git a/include/llvm/Support/AtomicOrdering.h b/include/llvm/Support/AtomicOrdering.h
index e93b755aa63b..a679ab30243e 100644
--- a/include/llvm/Support/AtomicOrdering.h
+++ b/include/llvm/Support/AtomicOrdering.h
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief Atomic ordering constants.
+/// Atomic ordering constants.
///
/// These values are used by LLVM to represent atomic ordering for C++11's
/// memory model and more, as detailed in docs/Atomics.rst.
diff --git a/include/llvm/Support/BinaryByteStream.h b/include/llvm/Support/BinaryByteStream.h
index db1ccba1398b..9808d3b72157 100644
--- a/include/llvm/Support/BinaryByteStream.h
+++ b/include/llvm/Support/BinaryByteStream.h
@@ -25,7 +25,7 @@
namespace llvm {
-/// \brief An implementation of BinaryStream which holds its entire data set
+/// An implementation of BinaryStream which holds its entire data set
/// in a single contiguous buffer. BinaryByteStream guarantees that no read
/// operation will ever incur a copy. Note that BinaryByteStream does not
/// own the underlying buffer.
@@ -69,7 +69,7 @@ protected:
ArrayRef<uint8_t> Data;
};
-/// \brief An implementation of BinaryStream whose data is backed by an llvm
+/// An implementation of BinaryStream whose data is backed by an llvm
/// MemoryBuffer object. MemoryBufferByteStream owns the MemoryBuffer in
/// question. As with BinaryByteStream, reading from a MemoryBufferByteStream
/// will never cause a copy.
@@ -83,7 +83,7 @@ public:
std::unique_ptr<MemoryBuffer> MemBuffer;
};
-/// \brief An implementation of BinaryStream which holds its entire data set
+/// An implementation of BinaryStream which holds its entire data set
/// in a single contiguous buffer. As with BinaryByteStream, the mutable
/// version also guarantees that no read operation will ever incur a copy,
/// and similarly it does not own the underlying buffer.
@@ -131,7 +131,7 @@ private:
BinaryByteStream ImmutableStream;
};
-/// \brief An implementation of WritableBinaryStream which can write at its end
+/// An implementation of WritableBinaryStream which can write at its end
/// causing the underlying data to grow. This class owns the underlying data.
class AppendingBinaryByteStream : public WritableBinaryStream {
std::vector<uint8_t> Data;
@@ -193,7 +193,7 @@ public:
Error commit() override { return Error::success(); }
- /// \brief Return the properties of this stream.
+ /// Return the properties of this stream.
virtual BinaryStreamFlags getFlags() const override {
return BSF_Write | BSF_Append;
}
@@ -201,7 +201,7 @@ public:
MutableArrayRef<uint8_t> data() { return Data; }
};
-/// \brief An implementation of WritableBinaryStream backed by an llvm
+/// An implementation of WritableBinaryStream backed by an llvm
/// FileOutputBuffer.
class FileBufferByteStream : public WritableBinaryStream {
private:
@@ -222,6 +222,12 @@ private:
return Error::success();
}
+ /// Returns a pointer to the start of the buffer.
+ uint8_t *getBufferStart() const { return FileBuffer->getBufferStart(); }
+
+ /// Returns a pointer to the end of the buffer.
+ uint8_t *getBufferEnd() const { return FileBuffer->getBufferEnd(); }
+
private:
std::unique_ptr<FileOutputBuffer> FileBuffer;
};
@@ -253,6 +259,12 @@ public:
Error commit() override { return Impl.commit(); }
+ /// Returns a pointer to the start of the buffer.
+ uint8_t *getBufferStart() const { return Impl.getBufferStart(); }
+
+ /// Returns a pointer to the end of the buffer.
+ uint8_t *getBufferEnd() const { return Impl.getBufferEnd(); }
+
private:
StreamImpl Impl;
};
diff --git a/include/llvm/Support/BinaryStream.h b/include/llvm/Support/BinaryStream.h
index d69a03eccfdb..7677214e48ee 100644
--- a/include/llvm/Support/BinaryStream.h
+++ b/include/llvm/Support/BinaryStream.h
@@ -26,7 +26,7 @@ enum BinaryStreamFlags {
LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ BSF_Append)
};
-/// \brief An interface for accessing data in a stream-like format, but which
+/// An interface for accessing data in a stream-like format, but which
/// discourages copying. Instead of specifying a buffer in which to copy
/// data on a read, the API returns an ArrayRef to data owned by the stream's
/// implementation. Since implementations may not necessarily store data in a
@@ -39,21 +39,21 @@ public:
virtual llvm::support::endianness getEndian() const = 0;
- /// \brief Given an offset into the stream and a number of bytes, attempt to
+ /// Given an offset into the stream and a number of bytes, attempt to
/// read the bytes and set the output ArrayRef to point to data owned by the
/// stream.
virtual Error readBytes(uint32_t Offset, uint32_t Size,
ArrayRef<uint8_t> &Buffer) = 0;
- /// \brief Given an offset into the stream, read as much as possible without
+ /// Given an offset into the stream, read as much as possible without
/// copying any data.
virtual Error readLongestContiguousChunk(uint32_t Offset,
ArrayRef<uint8_t> &Buffer) = 0;
- /// \brief Return the number of bytes of data in this stream.
+ /// Return the number of bytes of data in this stream.
virtual uint32_t getLength() = 0;
- /// \brief Return the properties of this stream.
+ /// Return the properties of this stream.
virtual BinaryStreamFlags getFlags() const { return BSF_None; }
protected:
@@ -66,7 +66,7 @@ protected:
}
};
-/// \brief A BinaryStream which can be read from as well as written to. Note
+/// A BinaryStream which can be read from as well as written to. Note
/// that writing to a BinaryStream always necessitates copying from the input
/// buffer to the stream's backing store. Streams are assumed to be buffered
/// so that to be portable it is necessary to call commit() on the stream when
@@ -75,15 +75,15 @@ class WritableBinaryStream : public BinaryStream {
public:
~WritableBinaryStream() override = default;
- /// \brief Attempt to write the given bytes into the stream at the desired
+ /// Attempt to write the given bytes into the stream at the desired
/// offset. This will always necessitate a copy. Cannot shrink or grow the
/// stream, only writes into existing allocated space.
virtual Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) = 0;
- /// \brief For buffered streams, commits changes to the backing store.
+ /// For buffered streams, commits changes to the backing store.
virtual Error commit() = 0;
- /// \brief Return the properties of this stream.
+ /// Return the properties of this stream.
BinaryStreamFlags getFlags() const override { return BSF_Write; }
protected:
diff --git a/include/llvm/Support/BinaryStreamArray.h b/include/llvm/Support/BinaryStreamArray.h
index 3f5562ba7519..d1571cb37fc6 100644
--- a/include/llvm/Support/BinaryStreamArray.h
+++ b/include/llvm/Support/BinaryStreamArray.h
@@ -111,7 +111,7 @@ public:
bool empty() const { return Stream.getLength() == 0; }
- /// \brief given an offset into the array's underlying stream, return an
+ /// given an offset into the array's underlying stream, return an
/// iterator to the record at that offset. This is considered unsafe
/// since the behavior is undefined if \p Offset does not refer to the
/// beginning of a valid record.
diff --git a/include/llvm/Support/BinaryStreamReader.h b/include/llvm/Support/BinaryStreamReader.h
index ae5ebb2c3628..fe77b550c453 100644
--- a/include/llvm/Support/BinaryStreamReader.h
+++ b/include/llvm/Support/BinaryStreamReader.h
@@ -24,7 +24,7 @@
namespace llvm {
-/// \brief Provides read only access to a subclass of `BinaryStream`. Provides
+/// Provides read only access to a subclass of `BinaryStream`. Provides
/// bounds checking and helpers for writing certain common data types such as
/// null-terminated strings, integers in various flavors of endianness, etc.
/// Can be subclassed to provide reading of custom datatypes, although no
diff --git a/include/llvm/Support/BinaryStreamRef.h b/include/llvm/Support/BinaryStreamRef.h
index 5cf355be6fe9..d8dc1392c01c 100644
--- a/include/llvm/Support/BinaryStreamRef.h
+++ b/include/llvm/Support/BinaryStreamRef.h
@@ -147,7 +147,7 @@ protected:
Optional<uint32_t> Length;
};
-/// \brief BinaryStreamRef is to BinaryStream what ArrayRef is to an Array. It
+/// BinaryStreamRef is to BinaryStream what ArrayRef is to an Array. It
/// provides copy-semantics and read only access to a "window" of the underlying
/// BinaryStream. Note that BinaryStreamRef is *not* a BinaryStream. That is to
/// say, it does not inherit and override the methods of BinaryStream. In
@@ -266,7 +266,7 @@ public:
/// Conver this WritableBinaryStreamRef to a read-only BinaryStreamRef.
operator BinaryStreamRef() const;
- /// \brief For buffered streams, commits changes to the backing store.
+ /// For buffered streams, commits changes to the backing store.
Error commit();
};
diff --git a/include/llvm/Support/BinaryStreamWriter.h b/include/llvm/Support/BinaryStreamWriter.h
index a4495a1ce27d..6e8a68a30474 100644
--- a/include/llvm/Support/BinaryStreamWriter.h
+++ b/include/llvm/Support/BinaryStreamWriter.h
@@ -24,7 +24,7 @@
namespace llvm {
-/// \brief Provides write only access to a subclass of `WritableBinaryStream`.
+/// Provides write only access to a subclass of `WritableBinaryStream`.
/// Provides bounds checking and helpers for writing certain common data types
/// such as null-terminated strings, integers in various flavors of endianness,
/// etc. Can be subclassed to provide reading and writing of custom datatypes,
@@ -56,7 +56,7 @@ public:
/// otherwise returns an appropriate error code.
Error writeBytes(ArrayRef<uint8_t> Buffer);
- /// Write the the integer \p Value to the underlying stream in the
+ /// Write the integer \p Value to the underlying stream in the
/// specified endianness. On success, updates the offset so that
/// subsequent writes occur at the next unwritten position.
///
@@ -80,7 +80,7 @@ public:
return writeInteger<U>(static_cast<U>(Num));
}
- /// Write the the string \p Str to the underlying stream followed by a null
+ /// Write the string \p Str to the underlying stream followed by a null
/// terminator. On success, updates the offset so that subsequent writes
/// occur at the next unwritten position. \p Str need not be null terminated
/// on input.
@@ -89,7 +89,7 @@ public:
/// otherwise returns an appropriate error code.
Error writeCString(StringRef Str);
- /// Write the the string \p Str to the underlying stream without a null
+ /// Write the string \p Str to the underlying stream without a null
/// terminator. On success, updates the offset so that subsequent writes
/// occur at the next unwritten position.
///
diff --git a/include/llvm/Support/BlockFrequency.h b/include/llvm/Support/BlockFrequency.h
index 2e75cbdd29c1..4b468f7acb32 100644
--- a/include/llvm/Support/BlockFrequency.h
+++ b/include/llvm/Support/BlockFrequency.h
@@ -28,32 +28,32 @@ class BlockFrequency {
public:
BlockFrequency(uint64_t Freq = 0) : Frequency(Freq) { }
- /// \brief Returns the maximum possible frequency, the saturation value.
+ /// Returns the maximum possible frequency, the saturation value.
static uint64_t getMaxFrequency() { return -1ULL; }
- /// \brief Returns the frequency as a fixpoint number scaled by the entry
+ /// Returns the frequency as a fixpoint number scaled by the entry
/// frequency.
uint64_t getFrequency() const { return Frequency; }
- /// \brief Multiplies with a branch probability. The computation will never
+ /// Multiplies with a branch probability. The computation will never
/// overflow.
BlockFrequency &operator*=(BranchProbability Prob);
BlockFrequency operator*(BranchProbability Prob) const;
- /// \brief Divide by a non-zero branch probability using saturating
+ /// Divide by a non-zero branch probability using saturating
/// arithmetic.
BlockFrequency &operator/=(BranchProbability Prob);
BlockFrequency operator/(BranchProbability Prob) const;
- /// \brief Adds another block frequency using saturating arithmetic.
+ /// Adds another block frequency using saturating arithmetic.
BlockFrequency &operator+=(BlockFrequency Freq);
BlockFrequency operator+(BlockFrequency Freq) const;
- /// \brief Subtracts another block frequency using saturating arithmetic.
+ /// Subtracts another block frequency using saturating arithmetic.
BlockFrequency &operator-=(BlockFrequency Freq);
BlockFrequency operator-(BlockFrequency Freq) const;
- /// \brief Shift block frequency to the right by count digits saturating to 1.
+ /// Shift block frequency to the right by count digits saturating to 1.
BlockFrequency &operator>>=(const unsigned count);
bool operator<(BlockFrequency RHS) const {
diff --git a/include/llvm/Support/BranchProbability.h b/include/llvm/Support/BranchProbability.h
index b403d7fbf117..3a88e71c2480 100644
--- a/include/llvm/Support/BranchProbability.h
+++ b/include/llvm/Support/BranchProbability.h
@@ -73,7 +73,7 @@ public:
void dump() const;
- /// \brief Scale a large integer.
+ /// Scale a large integer.
///
/// Scales \c Num. Guarantees full precision. Returns the floor of the
/// result.
@@ -81,7 +81,7 @@ public:
/// \return \c Num times \c this.
uint64_t scale(uint64_t Num) const;
- /// \brief Scale a large integer by the inverse.
+ /// Scale a large integer by the inverse.
///
/// Scales \c Num by the inverse of \c this. Guarantees full precision.
/// Returns the floor of the result.
diff --git a/include/llvm/Support/CMakeLists.txt b/include/llvm/Support/CMakeLists.txt
index bf662c77351d..bba962a5de10 100644
--- a/include/llvm/Support/CMakeLists.txt
+++ b/include/llvm/Support/CMakeLists.txt
@@ -5,16 +5,16 @@ set(version_inc "${CMAKE_CURRENT_BINARY_DIR}/VCSRevision.h")
set(get_svn_script "${LLVM_CMAKE_PATH}/GenerateVersionFromCVS.cmake")
-file(WRITE "${version_inc}.empty" "")
+file(WRITE "${version_inc}.undef" "#undef LLVM_REVISION\n")
if((DEFINED llvm_vc) AND LLVM_APPEND_VC_REV)
execute_process(COMMAND ${CMAKE_COMMAND} -E compare_files
- "${version_inc}.empty" "${version_inc}"
+ "${version_inc}.undef" "${version_inc}"
RESULT_VARIABLE files_not_equal
OUTPUT_QUIET
ERROR_QUIET)
- # Remove ${version_inc} if it's empty -- toggling LLVM_APPEND_VC_REV
- # from OFF to ON.
+ # Remove ${version_inc} if it doesn't define a revision. This will force it
+ # to be regenerated when toggling LLVM_APPEND_VC_REV from OFF to ON.
if(NOT files_not_equal)
file(REMOVE "${version_inc}")
endif()
@@ -28,11 +28,11 @@ if((DEFINED llvm_vc) AND LLVM_APPEND_VC_REV)
"-DHEADER_FILE=${version_inc}"
-P "${get_svn_script}")
else()
- # Make sure ${version_inc} is an empty file.
+ # Make sure ${version_inc} doesn't define a revision
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
- "${version_inc}.empty" "${version_inc}")
+ "${version_inc}.undef" "${version_inc}")
endif()
-file(REMOVE "${version_inc}.empty")
+file(REMOVE "${version_inc}.undef")
# Mark the generated header as being generated.
set_source_files_properties("${version_inc}"
diff --git a/include/llvm/Support/CachePruning.h b/include/llvm/Support/CachePruning.h
index 327c7df4570f..cf3f8ec67a52 100644
--- a/include/llvm/Support/CachePruning.h
+++ b/include/llvm/Support/CachePruning.h
@@ -37,7 +37,7 @@ struct CachePruningPolicy {
std::chrono::seconds Expiration = std::chrono::hours(7 * 24); // 1w
/// The maximum size for the cache directory, in terms of percentage of the
- /// available space on the the disk. Set to 100 to indicate no limit, 50 to
+ /// available space on the disk. Set to 100 to indicate no limit, 50 to
/// indicate that the cache size will not be left over half the available disk
/// space. A value over 100 will be reduced to 100. A value of 0 disables the
/// percentage size-based pruning.
@@ -52,9 +52,11 @@ struct CachePruningPolicy {
/// the number of files based pruning.
///
/// This defaults to 1000000 because with that many files there are
- /// diminishing returns on the effectiveness of the cache, and some file
- /// systems have a limit on how many files can be contained in a directory
- /// (notably ext4, which is limited to around 6000000 files).
+ /// diminishing returns on the effectiveness of the cache. Some systems have a
+ /// limit on total number of files, and some also limit the number of files
+ /// per directory, such as Linux ext4, with the default setting (block size is
+ /// 4096 and large_dir disabled), there is a per-directory entry limit of
+ /// 508*510*floor(4096/(40+8))~=20M for average filename length of 40.
uint64_t MaxSizeFiles = 1000000;
};
@@ -66,7 +68,7 @@ struct CachePruningPolicy {
Expected<CachePruningPolicy> parseCachePruningPolicy(StringRef PolicyStr);
/// Peform pruning using the supplied policy, returns true if pruning
-/// occured, i.e. if Policy.Interval was expired.
+/// occurred, i.e. if Policy.Interval was expired.
///
/// As a safeguard against data loss if the user specifies the wrong directory
/// as their cache directory, this function will ignore files not matching the
diff --git a/include/llvm/Support/Casting.h b/include/llvm/Support/Casting.h
index baa2a814e9a1..3f21e0f9ebc3 100644
--- a/include/llvm/Support/Casting.h
+++ b/include/llvm/Support/Casting.h
@@ -60,7 +60,7 @@ struct isa_impl {
}
};
-/// \brief Always allow upcasts, and perform no dynamic check for them.
+/// Always allow upcasts, and perform no dynamic check for them.
template <typename To, typename From>
struct isa_impl<
To, From, typename std::enable_if<std::is_base_of<To, From>::value>::type> {
diff --git a/include/llvm/Support/CheckedArithmetic.h b/include/llvm/Support/CheckedArithmetic.h
new file mode 100644
index 000000000000..039c374136ff
--- /dev/null
+++ b/include/llvm/Support/CheckedArithmetic.h
@@ -0,0 +1,104 @@
+//==-- llvm/Support/CheckedArithmetic.h - Safe arithmetical operations *- C++ //
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains generic functions for operating on integers which
+// give the indication on whether the operation has overflown.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CHECKEDARITHMETIC_H
+#define LLVM_SUPPORT_CHECKEDARITHMETIC_H
+
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/Optional.h"
+
+#include <type_traits>
+
+namespace {
+
+/// Utility function to apply a given method of \c APInt \p F to \p LHS and
+/// \p RHS.
+/// \return Empty optional if the operation overflows, or result otherwise.
+template <typename T, typename F>
+typename std::enable_if<std::is_integral<T>::value && sizeof(T) * 8 <= 64,
+ llvm::Optional<T>>::type
+checkedOp(T LHS, T RHS, F Op, bool Signed = true) {
+ llvm::APInt ALHS(/*BitSize=*/sizeof(T) * 8, LHS, Signed);
+ llvm::APInt ARHS(/*BitSize=*/sizeof(T) * 8, RHS, Signed);
+ bool Overflow;
+ llvm::APInt Out = (ALHS.*Op)(ARHS, Overflow);
+ if (Overflow)
+ return llvm::None;
+ return Signed ? Out.getSExtValue() : Out.getZExtValue();
+}
+}
+
+namespace llvm {
+
+/// Add two signed integers \p LHS and \p RHS.
+/// \return Optional of sum if no signed overflow occurred,
+/// \c None otherwise.
+template <typename T>
+typename std::enable_if<std::is_signed<T>::value, llvm::Optional<T>>::type
+checkedAdd(T LHS, T RHS) {
+ return checkedOp(LHS, RHS, &llvm::APInt::sadd_ov);
+}
+
+/// Multiply two signed integers \p LHS and \p RHS.
+/// \return Optional of product if no signed overflow occurred,
+/// \c None otherwise.
+template <typename T>
+typename std::enable_if<std::is_signed<T>::value, llvm::Optional<T>>::type
+checkedMul(T LHS, T RHS) {
+ return checkedOp(LHS, RHS, &llvm::APInt::smul_ov);
+}
+
+/// Multiply A and B, and add C to the resulting product.
+/// \return Optional of result if no signed overflow occurred,
+/// \c None otherwise.
+template <typename T>
+typename std::enable_if<std::is_signed<T>::value, llvm::Optional<T>>::type
+checkedMulAdd(T A, T B, T C) {
+ if (auto Product = checkedMul(A, B))
+ return checkedAdd(*Product, C);
+ return llvm::None;
+}
+
+/// Add two unsigned integers \p LHS and \p RHS.
+/// \return Optional of sum if no unsigned overflow occurred,
+/// \c None otherwise.
+template <typename T>
+typename std::enable_if<std::is_unsigned<T>::value, llvm::Optional<T>>::type
+checkedAddUnsigned(T LHS, T RHS) {
+ return checkedOp(LHS, RHS, &llvm::APInt::uadd_ov, /*Signed=*/false);
+}
+
+/// Multiply two unsigned integers \p LHS and \p RHS.
+/// \return Optional of product if no unsigned overflow occurred,
+/// \c None otherwise.
+template <typename T>
+typename std::enable_if<std::is_unsigned<T>::value, llvm::Optional<T>>::type
+checkedMulUnsigned(T LHS, T RHS) {
+ return checkedOp(LHS, RHS, &llvm::APInt::umul_ov, /*Signed=*/false);
+}
+
+/// Multiply unsigned integers A and B, and add C to the resulting product.
+/// \return Optional of result if no unsigned overflow occurred,
+/// \c None otherwise.
+template <typename T>
+typename std::enable_if<std::is_unsigned<T>::value, llvm::Optional<T>>::type
+checkedMulAddUnsigned(T A, T B, T C) {
+ if (auto Product = checkedMulUnsigned(A, B))
+ return checkedAddUnsigned(*Product, C);
+ return llvm::None;
+}
+
+} // End llvm namespace
+
+#endif
diff --git a/include/llvm/Support/CodeGenCWrappers.h b/include/llvm/Support/CodeGenCWrappers.h
deleted file mode 100644
index 47971e80cefb..000000000000
--- a/include/llvm/Support/CodeGenCWrappers.h
+++ /dev/null
@@ -1,62 +0,0 @@
-//===- llvm/Support/CodeGenCWrappers.h - CodeGen C Wrappers -----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines C bindings wrappers for enums in llvm/Support/CodeGen.h
-// that need them. The wrappers are separated to avoid adding an indirect
-// dependency on llvm/Config/Targets.def to CodeGen.h.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_SUPPORT_CODEGENCWRAPPERS_H
-#define LLVM_SUPPORT_CODEGENCWRAPPERS_H
-
-#include "llvm-c/TargetMachine.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/Support/CodeGen.h"
-#include "llvm/Support/ErrorHandling.h"
-
-namespace llvm {
-
-inline Optional<CodeModel::Model> unwrap(LLVMCodeModel Model, bool &JIT) {
- JIT = false;
- switch (Model) {
- case LLVMCodeModelJITDefault:
- JIT = true;
- LLVM_FALLTHROUGH;
- case LLVMCodeModelDefault:
- return None;
- case LLVMCodeModelSmall:
- return CodeModel::Small;
- case LLVMCodeModelKernel:
- return CodeModel::Kernel;
- case LLVMCodeModelMedium:
- return CodeModel::Medium;
- case LLVMCodeModelLarge:
- return CodeModel::Large;
- }
- return CodeModel::Small;
-}
-
-inline LLVMCodeModel wrap(CodeModel::Model Model) {
- switch (Model) {
- case CodeModel::Small:
- return LLVMCodeModelSmall;
- case CodeModel::Kernel:
- return LLVMCodeModelKernel;
- case CodeModel::Medium:
- return LLVMCodeModelMedium;
- case CodeModel::Large:
- return LLVMCodeModelLarge;
- }
- llvm_unreachable("Bad CodeModel!");
-}
-
-} // end llvm namespace
-
-#endif
diff --git a/include/llvm/Support/CodeGenCoverage.h b/include/llvm/Support/CodeGenCoverage.h
index d5bd837bff28..c863be35b822 100644
--- a/include/llvm/Support/CodeGenCoverage.h
+++ b/include/llvm/Support/CodeGenCoverage.h
@@ -23,15 +23,18 @@ protected:
BitVector RuleCoverage;
public:
+ using const_covered_iterator = BitVector::const_set_bits_iterator;
+
CodeGenCoverage();
void setCovered(uint64_t RuleID);
- bool isCovered(uint64_t RuleID);
+ bool isCovered(uint64_t RuleID) const;
+ iterator_range<const_covered_iterator> covered() const;
bool parse(MemoryBuffer &Buffer, StringRef BackendName);
bool emit(StringRef FilePrefix, StringRef BackendName) const;
void reset();
};
-} // end namespace llvm
+} // namespace llvm
#endif // ifndef LLVM_SUPPORT_CODEGENCOVERAGE_H
diff --git a/include/llvm/Support/CommandLine.h b/include/llvm/Support/CommandLine.h
index d1901db7c68e..799b41fbf8b0 100644
--- a/include/llvm/Support/CommandLine.h
+++ b/include/llvm/Support/CommandLine.h
@@ -30,6 +30,7 @@
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <climits>
#include <cstddef>
@@ -94,7 +95,7 @@ void PrintOptionValues();
// Forward declaration - AddLiteralOption needs to be up here to make gcc happy.
class Option;
-/// \brief Adds a new option for parsing and provides the option it refers to.
+/// Adds a new option for parsing and provides the option it refers to.
///
/// \param O pointer to the option
/// \param Name the string name for the option to handle during parsing
@@ -362,7 +363,10 @@ public:
bool MultiArg = false);
// Prints option name followed by message. Always returns true.
- bool error(const Twine &Message, StringRef ArgName = StringRef());
+ bool error(const Twine &Message, StringRef ArgName = StringRef(), raw_ostream &Errs = llvm::errs());
+ bool error(const Twine &Message, raw_ostream &Errs) {
+ return error(Message, StringRef(), Errs);
+ }
inline int getNumOccurrences() const { return NumOccurrences; }
inline void reset() { NumOccurrences = 0; }
@@ -1770,7 +1774,7 @@ void PrintHelpMessage(bool Hidden = false, bool Categorized = false);
// Public interface for accessing registered options.
//
-/// \brief Use this to get a StringMap to all registered named options
+/// Use this to get a StringMap to all registered named options
/// (e.g. -help). Note \p Map Should be an empty StringMap.
///
/// \return A reference to the StringMap used by the cl APIs to parse options.
@@ -1799,7 +1803,7 @@ void PrintHelpMessage(bool Hidden = false, bool Categorized = false);
/// than just handing around a global list.
StringMap<Option *> &getRegisteredOptions(SubCommand &Sub = *TopLevelSubCommand);
-/// \brief Use this to get all registered SubCommands from the provided parser.
+/// Use this to get all registered SubCommands from the provided parser.
///
/// \return A range of all SubCommand pointers registered with the parser.
///
@@ -1825,7 +1829,7 @@ getRegisteredSubcommands();
// Standalone command line processing utilities.
//
-/// \brief Tokenizes a command line that can contain escapes and quotes.
+/// Tokenizes a command line that can contain escapes and quotes.
//
/// The quoting rules match those used by GCC and other tools that use
/// libiberty's buildargv() or expandargv() utilities, and do not match bash.
@@ -1841,7 +1845,7 @@ void TokenizeGNUCommandLine(StringRef Source, StringSaver &Saver,
SmallVectorImpl<const char *> &NewArgv,
bool MarkEOLs = false);
-/// \brief Tokenizes a Windows command line which may contain quotes and escaped
+/// Tokenizes a Windows command line which may contain quotes and escaped
/// quotes.
///
/// See MSDN docs for CommandLineToArgvW for information on the quoting rules.
@@ -1856,13 +1860,40 @@ void TokenizeWindowsCommandLine(StringRef Source, StringSaver &Saver,
SmallVectorImpl<const char *> &NewArgv,
bool MarkEOLs = false);
-/// \brief String tokenization function type. Should be compatible with either
+/// String tokenization function type. Should be compatible with either
/// Windows or Unix command line tokenizers.
using TokenizerCallback = void (*)(StringRef Source, StringSaver &Saver,
SmallVectorImpl<const char *> &NewArgv,
bool MarkEOLs);
-/// \brief Expand response files on a command line recursively using the given
+/// Tokenizes content of configuration file.
+///
+/// \param [in] Source The string representing content of config file.
+/// \param [in] Saver Delegates back to the caller for saving parsed strings.
+/// \param [out] NewArgv All parsed strings are appended to NewArgv.
+/// \param [in] MarkEOLs Added for compatibility with TokenizerCallback.
+///
+/// It works like TokenizeGNUCommandLine with ability to skip comment lines.
+///
+void tokenizeConfigFile(StringRef Source, StringSaver &Saver,
+ SmallVectorImpl<const char *> &NewArgv,
+ bool MarkEOLs = false);
+
+/// Reads command line options from the given configuration file.
+///
+/// \param [in] CfgFileName Path to configuration file.
+/// \param [in] Saver Objects that saves allocated strings.
+/// \param [out] Argv Array to which the read options are added.
+/// \return true if the file was successfully read.
+///
+/// It reads content of the specified file, tokenizes it and expands "@file"
+/// commands resolving file names in them relative to the directory where
+/// CfgFilename resides.
+///
+bool readConfigFile(StringRef CfgFileName, StringSaver &Saver,
+ SmallVectorImpl<const char *> &Argv);
+
+/// Expand response files on a command line recursively using the given
/// StringSaver and tokenization strategy. Argv should contain the command line
/// before expansion and will be modified in place. If requested, Argv will
/// also be populated with nullptrs indicating where each response file line
@@ -1882,7 +1913,7 @@ bool ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
SmallVectorImpl<const char *> &Argv,
bool MarkEOLs = false, bool RelativeNames = false);
-/// \brief Mark all options not part of this category as cl::ReallyHidden.
+/// Mark all options not part of this category as cl::ReallyHidden.
///
/// \param Category the category of options to keep displaying
///
@@ -1892,7 +1923,7 @@ bool ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
void HideUnrelatedOptions(cl::OptionCategory &Category,
SubCommand &Sub = *TopLevelSubCommand);
-/// \brief Mark all options not part of the categories as cl::ReallyHidden.
+/// Mark all options not part of the categories as cl::ReallyHidden.
///
/// \param Categories the categories of options to keep displaying.
///
@@ -1902,12 +1933,12 @@ void HideUnrelatedOptions(cl::OptionCategory &Category,
void HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *> Categories,
SubCommand &Sub = *TopLevelSubCommand);
-/// \brief Reset all command line options to a state that looks as if they have
+/// Reset all command line options to a state that looks as if they have
/// never appeared on the command line. This is useful for being able to parse
/// a command line multiple times (especially useful for writing tests).
void ResetAllOptionOccurrences();
-/// \brief Reset the command line parser back to its initial state. This
+/// Reset the command line parser back to its initial state. This
/// removes
/// all options, categories, and subcommands and returns the parser to a state
/// where no options are supported.
diff --git a/include/llvm/Support/Compiler.h b/include/llvm/Support/Compiler.h
index b19e37235df5..4de815fe61d7 100644
--- a/include/llvm/Support/Compiler.h
+++ b/include/llvm/Support/Compiler.h
@@ -17,6 +17,9 @@
#include "llvm/Config/llvm-config.h"
+#include <new>
+#include <stddef.h>
+
#if defined(_MSC_VER)
#include <sal.h>
#endif
@@ -42,7 +45,7 @@
#endif
/// \macro LLVM_GNUC_PREREQ
-/// \brief Extend the default __GNUC_PREREQ even if glibc's features.h isn't
+/// Extend the default __GNUC_PREREQ even if glibc's features.h isn't
/// available.
#ifndef LLVM_GNUC_PREREQ
# if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
@@ -58,7 +61,7 @@
#endif
/// \macro LLVM_MSC_PREREQ
-/// \brief Is the compiler MSVC of at least the specified version?
+/// Is the compiler MSVC of at least the specified version?
/// The common \param version values to check for are:
/// * 1900: Microsoft Visual Studio 2015 / 14.0
#ifdef _MSC_VER
@@ -73,7 +76,7 @@
#define LLVM_MSC_PREREQ(version) 0
#endif
-/// \brief Does the compiler support ref-qualifiers for *this?
+/// Does the compiler support ref-qualifiers for *this?
///
/// Sadly, this is separate from just rvalue reference support because GCC
/// and MSVC implemented this later than everything else.
@@ -99,7 +102,7 @@
/// functions, making them private to any shared library they are linked into.
/// On PE/COFF targets, library visibility is the default, so this isn't needed.
#if (__has_attribute(visibility) || LLVM_GNUC_PREREQ(4, 0, 0)) && \
- !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(LLVM_ON_WIN32)
+ !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_WIN32)
#define LLVM_LIBRARY_VISIBILITY __attribute__ ((visibility("hidden")))
#else
#define LLVM_LIBRARY_VISIBILITY
@@ -146,7 +149,7 @@
// FIXME: Provide this for PE/COFF targets.
#if (__has_attribute(weak) || LLVM_GNUC_PREREQ(4, 0, 0)) && \
- (!defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(LLVM_ON_WIN32))
+ (!defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_WIN32))
#define LLVM_ATTRIBUTE_WEAK __attribute__((__weak__))
#else
#define LLVM_ATTRIBUTE_WEAK
@@ -303,7 +306,7 @@
#endif
/// \macro LLVM_ASSUME_ALIGNED
-/// \brief Returns a pointer with an assumed alignment.
+/// Returns a pointer with an assumed alignment.
#if __has_builtin(__builtin_assume_aligned) || LLVM_GNUC_PREREQ(4, 7, 0)
# define LLVM_ASSUME_ALIGNED(p, a) __builtin_assume_aligned(p, a)
#elif defined(LLVM_BUILTIN_UNREACHABLE)
@@ -315,7 +318,7 @@
#endif
/// \macro LLVM_ALIGNAS
-/// \brief Used to specify a minimum alignment for a structure or variable.
+/// Used to specify a minimum alignment for a structure or variable.
#if __GNUC__ && !__has_feature(cxx_alignas) && !LLVM_GNUC_PREREQ(4, 8, 1)
# define LLVM_ALIGNAS(x) __attribute__((aligned(x)))
#else
@@ -323,7 +326,7 @@
#endif
/// \macro LLVM_PACKED
-/// \brief Used to specify a packed structure.
+/// Used to specify a packed structure.
/// LLVM_PACKED(
/// struct A {
/// int i;
@@ -351,7 +354,7 @@
#endif
/// \macro LLVM_PTR_SIZE
-/// \brief A constant integer equivalent to the value of sizeof(void*).
+/// A constant integer equivalent to the value of sizeof(void*).
/// Generally used in combination with LLVM_ALIGNAS or when doing computation in
/// the preprocessor.
#ifdef __SIZEOF_POINTER__
@@ -367,7 +370,7 @@
#endif
/// \macro LLVM_MEMORY_SANITIZER_BUILD
-/// \brief Whether LLVM itself is built with MemorySanitizer instrumentation.
+/// Whether LLVM itself is built with MemorySanitizer instrumentation.
#if __has_feature(memory_sanitizer)
# define LLVM_MEMORY_SANITIZER_BUILD 1
# include <sanitizer/msan_interface.h>
@@ -378,7 +381,7 @@
#endif
/// \macro LLVM_ADDRESS_SANITIZER_BUILD
-/// \brief Whether LLVM itself is built with AddressSanitizer instrumentation.
+/// Whether LLVM itself is built with AddressSanitizer instrumentation.
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
# define LLVM_ADDRESS_SANITIZER_BUILD 1
# include <sanitizer/asan_interface.h>
@@ -389,7 +392,7 @@
#endif
/// \macro LLVM_THREAD_SANITIZER_BUILD
-/// \brief Whether LLVM itself is built with ThreadSanitizer instrumentation.
+/// Whether LLVM itself is built with ThreadSanitizer instrumentation.
#if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__)
# define LLVM_THREAD_SANITIZER_BUILD 1
#else
@@ -432,14 +435,14 @@ void AnnotateIgnoreWritesEnd(const char *file, int line);
#endif
/// \macro LLVM_NO_SANITIZE
-/// \brief Disable a particular sanitizer for a function.
+/// Disable a particular sanitizer for a function.
#if __has_attribute(no_sanitize)
#define LLVM_NO_SANITIZE(KIND) __attribute__((no_sanitize(KIND)))
#else
#define LLVM_NO_SANITIZE(KIND)
#endif
-/// \brief Mark debug helper function definitions like dump() that should not be
+/// Mark debug helper function definitions like dump() that should not be
/// stripped from debug builds.
/// Note that you should also surround dump() functions with
/// `#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)` so they do always
@@ -452,7 +455,7 @@ void AnnotateIgnoreWritesEnd(const char *file, int line);
#endif
/// \macro LLVM_PRETTY_FUNCTION
-/// \brief Gets a user-friendly looking function signature for the current scope
+/// Gets a user-friendly looking function signature for the current scope
/// using the best available method on each platform. The exact format of the
/// resulting string is implementation specific and non-portable, so this should
/// only be used, for example, for logging or diagnostics.
@@ -465,7 +468,7 @@ void AnnotateIgnoreWritesEnd(const char *file, int line);
#endif
/// \macro LLVM_THREAD_LOCAL
-/// \brief A thread-local storage specifier which can be used with globals,
+/// A thread-local storage specifier which can be used with globals,
/// extern globals, and static globals.
///
/// This is essentially an extremely restricted analog to C++11's thread_local
@@ -494,7 +497,7 @@ void AnnotateIgnoreWritesEnd(const char *file, int line);
#endif
/// \macro LLVM_ENABLE_EXCEPTIONS
-/// \brief Whether LLVM is built with exception support.
+/// Whether LLVM is built with exception support.
#if __has_feature(cxx_exceptions)
#define LLVM_ENABLE_EXCEPTIONS 1
#elif defined(__GNUC__) && defined(__EXCEPTIONS)
@@ -503,4 +506,46 @@ void AnnotateIgnoreWritesEnd(const char *file, int line);
#define LLVM_ENABLE_EXCEPTIONS 1
#endif
+namespace llvm {
+
+/// Allocate a buffer of memory with the given size and alignment.
+///
+/// When the compiler supports aligned operator new, this will use it to to
+/// handle even over-aligned allocations.
+///
+/// However, this doesn't make any attempt to leverage the fancier techniques
+/// like posix_memalign due to portability. It is mostly intended to allow
+/// compatibility with platforms that, after aligned allocation was added, use
+/// reduced default alignment.
+inline void *allocate_buffer(size_t Size, size_t Alignment) {
+ return ::operator new(Size
+#if __cpp_aligned_new
+ ,
+ std::align_val_t(Alignment)
+#endif
+ );
+}
+
+/// Deallocate a buffer of memory with the given size and alignment.
+///
+/// If supported, this will used the sized delete operator. Also if supported,
+/// this will pass the alignment to the delete operator.
+///
+/// The pointer must have been allocated with the corresponding new operator,
+/// most likely using the above helper.
+inline void deallocate_buffer(void *Ptr, size_t Size, size_t Alignment) {
+ ::operator delete(Ptr
+#if __cpp_sized_deallocation
+ ,
+ Size
+#endif
+#if __cpp_aligned_new
+ ,
+ std::align_val_t(Alignment)
+#endif
+ );
+}
+
+} // End namespace llvm
+
#endif
diff --git a/include/llvm/Support/ConvertUTF.h b/include/llvm/Support/ConvertUTF.h
index 99ae171aeabb..6ae56c2470bb 100644
--- a/include/llvm/Support/ConvertUTF.h
+++ b/include/llvm/Support/ConvertUTF.h
@@ -92,6 +92,7 @@
#include <cstddef>
#include <string>
+#include <system_error>
// Wrap everything in namespace llvm so that programs can link with llvm and
// their own version of the unicode libraries.
@@ -286,6 +287,21 @@ bool convertUTF16ToUTF8String(ArrayRef<UTF16> Src, std::string &Out);
bool convertUTF8ToUTF16String(StringRef SrcUTF8,
SmallVectorImpl<UTF16> &DstUTF16);
+#if defined(_WIN32)
+namespace sys {
+namespace windows {
+std::error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16);
+/// Convert to UTF16 from the current code page used in the system
+std::error_code CurCPToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16);
+std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
+ SmallVectorImpl<char> &utf8);
+/// Convert from UTF16 to the current code page used in the system
+std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len,
+ SmallVectorImpl<char> &utf8);
+} // namespace windows
+} // namespace sys
+#endif
+
} /* end namespace llvm */
#endif
diff --git a/include/llvm/Support/CrashRecoveryContext.h b/include/llvm/Support/CrashRecoveryContext.h
index 6cbc331d2731..7b3fd4f882e4 100644
--- a/include/llvm/Support/CrashRecoveryContext.h
+++ b/include/llvm/Support/CrashRecoveryContext.h
@@ -15,7 +15,7 @@
namespace llvm {
class CrashRecoveryContextCleanup;
-/// \brief Crash recovery helper object.
+/// Crash recovery helper object.
///
/// This class implements support for running operations in a safe context so
/// that crashes (memory errors, stack overflow, assertion violations) can be
@@ -27,6 +27,7 @@ class CrashRecoveryContextCleanup;
/// CrashRecoveryContext::Enable(), and then executing unsafe operations via a
/// CrashRecoveryContext object. For example:
///
+/// \code
/// void actual_work(void *);
///
/// void foo() {
@@ -38,6 +39,11 @@ class CrashRecoveryContextCleanup;
///
/// ... no crash was detected ...
/// }
+/// \endcode
+///
+/// To assist recovery the class allows specifying set of actions that will be
+/// executed in any case, whether crash occurs or not. These actions may be used
+/// to reclaim resources in the case of crash.
class CrashRecoveryContext {
void *Impl;
CrashRecoveryContextCleanup *head;
@@ -46,24 +52,27 @@ public:
CrashRecoveryContext() : Impl(nullptr), head(nullptr) {}
~CrashRecoveryContext();
+ /// Register cleanup handler, which is used when the recovery context is
+ /// finished.
+ /// The recovery context owns the handler.
void registerCleanup(CrashRecoveryContextCleanup *cleanup);
+
void unregisterCleanup(CrashRecoveryContextCleanup *cleanup);
- /// \brief Enable crash recovery.
+ /// Enable crash recovery.
static void Enable();
- /// \brief Disable crash recovery.
+ /// Disable crash recovery.
static void Disable();
- /// \brief Return the active context, if the code is currently executing in a
+ /// Return the active context, if the code is currently executing in a
/// thread which is in a protected context.
static CrashRecoveryContext *GetCurrent();
- /// \brief Return true if the current thread is recovering from a
- /// crash.
+ /// Return true if the current thread is recovering from a crash.
static bool isRecoveringFromCrash();
- /// \brief Execute the provide callback function (with the given arguments) in
+ /// Execute the provided callback function (with the given arguments) in
/// a protected context.
///
/// \return True if the function completed successfully, and false if the
@@ -75,7 +84,7 @@ public:
return RunSafely([&]() { Fn(UserData); });
}
- /// \brief Execute the provide callback function (with the given arguments) in
+ /// Execute the provide callback function (with the given arguments) in
/// a protected context which is run in another thread (optionally with a
/// requested stack size).
///
@@ -89,11 +98,18 @@ public:
return RunSafelyOnThread([&]() { Fn(UserData); }, RequestedStackSize);
}
- /// \brief Explicitly trigger a crash recovery in the current process, and
+ /// Explicitly trigger a crash recovery in the current process, and
/// return failure from RunSafely(). This function does not return.
void HandleCrash();
};
+/// Abstract base class of cleanup handlers.
+///
+/// Derived classes override method recoverResources, which makes actual work on
+/// resource recovery.
+///
+/// Cleanup handlers are stored in a double list, which is owned and managed by
+/// a crash recovery context.
class CrashRecoveryContextCleanup {
protected:
CrashRecoveryContext *context;
@@ -115,7 +131,18 @@ private:
CrashRecoveryContextCleanup *prev, *next;
};
-template<typename DERIVED, typename T>
+/// Base class of cleanup handler that controls recovery of resources of the
+/// given type.
+///
+/// \tparam Derived Class that uses this class as a base.
+/// \tparam T Type of controlled resource.
+///
+/// This class serves as a base for its template parameter as implied by
+/// Curiously Recurring Template Pattern.
+///
+/// This class factors out creation of a cleanup handler. The latter requires
+/// knowledge of the current recovery context, which is provided by this class.
+template<typename Derived, typename T>
class CrashRecoveryContextCleanupBase : public CrashRecoveryContextCleanup {
protected:
T *resource;
@@ -123,15 +150,20 @@ protected:
: CrashRecoveryContextCleanup(context), resource(resource) {}
public:
- static DERIVED *create(T *x) {
+ /// Creates cleanup handler.
+ /// \param x Pointer to the resource recovered by this handler.
+ /// \return New handler or null if the method was called outside a recovery
+ /// context.
+ static Derived *create(T *x) {
if (x) {
if (CrashRecoveryContext *context = CrashRecoveryContext::GetCurrent())
- return new DERIVED(context, x);
+ return new Derived(context, x);
}
return nullptr;
}
};
+/// Cleanup handler that reclaims resource by calling destructor on it.
template <typename T>
class CrashRecoveryContextDestructorCleanup : public
CrashRecoveryContextCleanupBase<CrashRecoveryContextDestructorCleanup<T>, T> {
@@ -146,6 +178,7 @@ public:
}
};
+/// Cleanup handler that reclaims resource by calling 'delete' on it.
template <typename T>
class CrashRecoveryContextDeleteCleanup : public
CrashRecoveryContextCleanupBase<CrashRecoveryContextDeleteCleanup<T>, T> {
@@ -157,10 +190,10 @@ public:
void recoverResources() override { delete this->resource; }
};
+/// Cleanup handler that reclaims resource by calling its method 'Release'.
template <typename T>
class CrashRecoveryContextReleaseRefCleanup : public
- CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, T>
-{
+ CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, T> {
public:
CrashRecoveryContextReleaseRefCleanup(CrashRecoveryContext *context,
T *resource)
@@ -170,6 +203,37 @@ public:
void recoverResources() override { this->resource->Release(); }
};
+/// Helper class for managing resource cleanups.
+///
+/// \tparam T Type of resource been reclaimed.
+/// \tparam Cleanup Class that defines how the resource is reclaimed.
+///
+/// Clients create objects of this type in the code executed in a crash recovery
+/// context to ensure that the resource will be reclaimed even in the case of
+/// crash. For example:
+///
+/// \code
+/// void actual_work(void *) {
+/// ...
+/// std::unique_ptr<Resource> R(new Resource());
+/// CrashRecoveryContextCleanupRegistrar D(R.get());
+/// ...
+/// }
+///
+/// void foo() {
+/// CrashRecoveryContext CRC;
+///
+/// if (!CRC.RunSafely(actual_work, 0)) {
+/// ... a crash was detected, report error to user ...
+/// }
+/// \endcode
+///
+/// If the code of `actual_work` in the example above does not crash, the
+/// destructor of CrashRecoveryContextCleanupRegistrar removes cleanup code from
+/// the current CrashRecoveryContext and the resource is reclaimed by the
+/// destructor of std::unique_ptr. If crash happens, destructors are not called
+/// and the resource is reclaimed by cleanup object registered in the recovery
+/// context by the constructor of CrashRecoveryContextCleanupRegistrar.
template <typename T, typename Cleanup = CrashRecoveryContextDeleteCleanup<T> >
class CrashRecoveryContextCleanupRegistrar {
CrashRecoveryContextCleanup *cleanup;
diff --git a/include/llvm/Support/DJB.h b/include/llvm/Support/DJB.h
new file mode 100644
index 000000000000..e03111473362
--- /dev/null
+++ b/include/llvm/Support/DJB.h
@@ -0,0 +1,33 @@
+//===-- llvm/Support/DJB.h ---DJB Hash --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains support for the DJ Bernstein hash function.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_DJB_H
+#define LLVM_SUPPORT_DJB_H
+
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+
+/// The Bernstein hash function used by the DWARF accelerator tables.
+inline uint32_t djbHash(StringRef Buffer, uint32_t H = 5381) {
+ for (unsigned char C : Buffer.bytes())
+ H = (H << 5) + H + C;
+ return H;
+}
+
+/// Computes the Bernstein hash after folding the input according to the Dwarf 5
+/// standard case folding rules.
+uint32_t caseFoldingDjbHash(StringRef Buffer, uint32_t H = 5381);
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_DJB_H
diff --git a/include/llvm/Support/DataExtractor.h b/include/llvm/Support/DataExtractor.h
index 31447882a919..3a6ada6c77df 100644
--- a/include/llvm/Support/DataExtractor.h
+++ b/include/llvm/Support/DataExtractor.h
@@ -51,13 +51,13 @@ public:
DataExtractor(StringRef Data, bool IsLittleEndian, uint8_t AddressSize)
: Data(Data), IsLittleEndian(IsLittleEndian), AddressSize(AddressSize) {}
- /// \brief Get the data pointed to by this extractor.
+ /// Get the data pointed to by this extractor.
StringRef getData() const { return Data; }
- /// \brief Get the endianness for this extractor.
+ /// Get the endianness for this extractor.
bool isLittleEndian() const { return IsLittleEndian; }
- /// \brief Get the address size for this extractor.
+ /// Get the address size for this extractor.
uint8_t getAddressSize() const { return AddressSize; }
- /// \brief Set the address size for this extractor.
+ /// Set the address size for this extractor.
void setAddressSize(uint8_t Size) { AddressSize = Size; }
/// Extract a C string from \a *offset_ptr.
diff --git a/include/llvm/Support/DataTypes.h b/include/llvm/Support/DataTypes.h
new file mode 100644
index 000000000000..ad60a5b3f300
--- /dev/null
+++ b/include/llvm/Support/DataTypes.h
@@ -0,0 +1,17 @@
+//===-- llvm/Support/DataTypes.h - Define fixed size types ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Due to layering constraints (Support depends on llvm-c) this is a thin
+// wrapper around the implementation that lives in llvm-c, though most clients
+// can/should think of this as being provided by Support for simplicity (not
+// many clients are aware of their dependency on llvm-c).
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-c/DataTypes.h"
diff --git a/include/llvm/Support/DataTypes.h.cmake b/include/llvm/Support/DataTypes.h.cmake
deleted file mode 100644
index a58e2e454b7d..000000000000
--- a/include/llvm/Support/DataTypes.h.cmake
+++ /dev/null
@@ -1,135 +0,0 @@
-/*===-- include/Support/DataTypes.h - Define fixed size types -----*- C -*-===*\
-|* *|
-|* The LLVM Compiler Infrastructure *|
-|* *|
-|* This file is distributed under the University of Illinois Open Source *|
-|* License. See LICENSE.TXT for details. *|
-|* *|
-|*===----------------------------------------------------------------------===*|
-|* *|
-|* This file contains definitions to figure out the size of _HOST_ data types.*|
-|* This file is important because different host OS's define different macros,*|
-|* which makes portability tough. This file exports the following *|
-|* definitions: *|
-|* *|
-|* [u]int(32|64)_t : typedefs for signed and unsigned 32/64 bit system types*|
-|* [U]INT(8|16|32|64)_(MIN|MAX) : Constants for the min and max values. *|
-|* *|
-|* No library is required when using these functions. *|
-|* *|
-|*===----------------------------------------------------------------------===*/
-
-/* Please leave this file C-compatible. */
-
-#ifndef SUPPORT_DATATYPES_H
-#define SUPPORT_DATATYPES_H
-
-#cmakedefine HAVE_INTTYPES_H ${HAVE_INTTYPES_H}
-#cmakedefine HAVE_STDINT_H ${HAVE_STDINT_H}
-#cmakedefine HAVE_UINT64_T ${HAVE_UINT64_T}
-#cmakedefine HAVE_U_INT64_T ${HAVE_U_INT64_T}
-
-#ifdef __cplusplus
-#include <cmath>
-#else
-#include <math.h>
-#endif
-
-#ifdef __cplusplus
-#include <cinttypes>
-#else
-#ifdef HAVE_INTTYPES_H
-#include <inttypes.h>
-#endif
-#endif
-
-#ifdef __cplusplus
-#include <cstdint>
-#else
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#else
-#error "Compiler must provide an implementation of stdint.h"
-#endif
-#endif
-
-#ifndef _MSC_VER
-
-#if !defined(UINT32_MAX)
-# error "The standard header <cstdint> is not C++11 compliant. Must #define "\
- "__STDC_LIMIT_MACROS before #including Support/DataTypes.h"
-#endif
-
-#if !defined(UINT32_C)
-# error "The standard header <cstdint> is not C++11 compliant. Must #define "\
- "__STDC_CONSTANT_MACROS before #including Support/DataTypes.h"
-#endif
-
-/* Note that <inttypes.h> includes <stdint.h>, if this is a C99 system. */
-#include <sys/types.h>
-
-#ifdef _AIX
-// GCC is strict about defining large constants: they must have LL modifier.
-#undef INT64_MAX
-#undef INT64_MIN
-#endif
-
-/* Handle incorrect definition of uint64_t as u_int64_t */
-#ifndef HAVE_UINT64_T
-#ifdef HAVE_U_INT64_T
-typedef u_int64_t uint64_t;
-#else
-# error "Don't have a definition for uint64_t on this platform"
-#endif
-#endif
-
-#else /* _MSC_VER */
-#ifdef __cplusplus
-#include <cstddef>
-#include <cstdlib>
-#else
-#include <stddef.h>
-#include <stdlib.h>
-#endif
-#include <sys/types.h>
-
-#if defined(_WIN64)
-typedef signed __int64 ssize_t;
-#else
-typedef signed int ssize_t;
-#endif /* _WIN64 */
-
-#ifndef HAVE_INTTYPES_H
-#define PRId64 "I64d"
-#define PRIi64 "I64i"
-#define PRIo64 "I64o"
-#define PRIu64 "I64u"
-#define PRIx64 "I64x"
-#define PRIX64 "I64X"
-
-#define PRId32 "d"
-#define PRIi32 "i"
-#define PRIo32 "o"
-#define PRIu32 "u"
-#define PRIx32 "x"
-#define PRIX32 "X"
-#endif /* HAVE_INTTYPES_H */
-
-#endif /* _MSC_VER */
-
-/* Set defaults for constants which we cannot find. */
-#if !defined(INT64_MAX)
-# define INT64_MAX 9223372036854775807LL
-#endif
-#if !defined(INT64_MIN)
-# define INT64_MIN ((-INT64_MAX)-1)
-#endif
-#if !defined(UINT64_MAX)
-# define UINT64_MAX 0xffffffffffffffffULL
-#endif
-
-#ifndef HUGE_VALF
-#define HUGE_VALF (float)HUGE_VAL
-#endif
-
-#endif /* SUPPORT_DATATYPES_H */
diff --git a/include/llvm/Support/Debug.h b/include/llvm/Support/Debug.h
index 48e9e1bc167d..980abfb0e8da 100644
--- a/include/llvm/Support/Debug.h
+++ b/include/llvm/Support/Debug.h
@@ -11,17 +11,18 @@
// code, without it being enabled all of the time, and without having to add
// command line options to enable it.
//
-// In particular, just wrap your code with the DEBUG() macro, and it will be
-// enabled automatically if you specify '-debug' on the command-line.
-// DEBUG() requires the DEBUG_TYPE macro to be defined. Set it to "foo" specify
-// that your debug code belongs to class "foo". Be careful that you only do
-// this after including Debug.h and not around any #include of headers. Headers
-// should define and undef the macro acround the code that needs to use the
-// DEBUG() macro. Then, on the command line, you can specify '-debug-only=foo'
-// to enable JUST the debug information for the foo class.
+// In particular, just wrap your code with the LLVM_DEBUG() macro, and it will
+// be enabled automatically if you specify '-debug' on the command-line.
+// LLVM_DEBUG() requires the DEBUG_TYPE macro to be defined. Set it to "foo"
+// specify that your debug code belongs to class "foo". Be careful that you only
+// do this after including Debug.h and not around any #include of headers.
+// Headers should define and undef the macro acround the code that needs to use
+// the LLVM_DEBUG() macro. Then, on the command line, you can specify
+// '-debug-only=foo' to enable JUST the debug information for the foo class.
//
// When compiling without assertions, the -debug-* options and all code in
-// DEBUG() statements disappears, so it does not affect the runtime of the code.
+// LLVM_DEBUG() statements disappears, so it does not affect the runtime of the
+// code.
//
//===----------------------------------------------------------------------===//
@@ -113,9 +114,9 @@ raw_ostream &dbgs();
// debug build, then the code specified as the option to the macro will be
// executed. Otherwise it will not be. Example:
//
-// DEBUG(dbgs() << "Bitset contains: " << Bitset << "\n");
+// LLVM_DEBUG(dbgs() << "Bitset contains: " << Bitset << "\n");
//
-#define DEBUG(X) DEBUG_WITH_TYPE(DEBUG_TYPE, X)
+#define LLVM_DEBUG(X) DEBUG_WITH_TYPE(DEBUG_TYPE, X)
} // end namespace llvm
diff --git a/include/llvm/Support/DebugCounter.h b/include/llvm/Support/DebugCounter.h
index 52e1bd71a2f2..250fc6bb1f5c 100644
--- a/include/llvm/Support/DebugCounter.h
+++ b/include/llvm/Support/DebugCounter.h
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
/// \file
-/// \brief This file provides an implementation of debug counters. Debug
+/// This file provides an implementation of debug counters. Debug
/// counters are a tool that let you narrow down a miscompilation to a specific
/// thing happening.
///
@@ -55,7 +55,7 @@ namespace llvm {
class DebugCounter {
public:
- /// \brief Returns a reference to the singleton instance.
+ /// Returns a reference to the singleton instance.
static DebugCounter &instance();
// Used by the command line option parser to push a new value it parsed.
@@ -77,23 +77,19 @@ public:
auto &Us = instance();
auto Result = Us.Counters.find(CounterName);
if (Result != Us.Counters.end()) {
- auto &CounterPair = Result->second;
- // We only execute while the skip (first) is zero and the count (second)
- // is non-zero.
+ auto &CounterInfo = Result->second;
+ ++CounterInfo.Count;
+
+ // We only execute while the Skip is not smaller than Count,
+ // and the StopAfter + Skip is larger than Count.
// Negative counters always execute.
- if (CounterPair.first < 0)
+ if (CounterInfo.Skip < 0)
return true;
- if (CounterPair.first != 0) {
- --CounterPair.first;
+ if (CounterInfo.Skip >= CounterInfo.Count)
return false;
- }
- if (CounterPair.second < 0)
- return true;
- if (CounterPair.second != 0) {
- --CounterPair.second;
+ if (CounterInfo.StopAfter < 0)
return true;
- }
- return false;
+ return CounterInfo.StopAfter + CounterInfo.Skip >= CounterInfo.Count;
}
// Didn't find the counter, should we warn?
return true;
@@ -104,21 +100,21 @@ public:
// the command line). This will return true even if those values are
// currently in a state where the counter will always execute.
static bool isCounterSet(unsigned ID) {
- return instance().Counters.count(ID);
+ return instance().Counters[ID].IsSet;
}
- // Return the skip and count for a counter. This only works for set counters.
- static std::pair<int, int> getCounterValue(unsigned ID) {
+ // Return the Count for a counter. This only works for set counters.
+ static int64_t getCounterValue(unsigned ID) {
auto &Us = instance();
auto Result = Us.Counters.find(ID);
assert(Result != Us.Counters.end() && "Asking about a non-set counter");
- return Result->second;
+ return Result->second.Count;
}
- // Set a registered counter to a given value.
- static void setCounterValue(unsigned ID, const std::pair<int, int> &Val) {
+ // Set a registered counter to a given Count value.
+ static void setCounterValue(unsigned ID, int64_t Count) {
auto &Us = instance();
- Us.Counters[ID] = Val;
+ Us.Counters[ID].Count = Count;
}
// Dump or print the current counter set into llvm::dbgs().
@@ -136,7 +132,7 @@ public:
// Return the name and description of the counter with the given ID.
std::pair<std::string, std::string> getCounterInfo(unsigned ID) const {
- return std::make_pair(RegisteredCounters[ID], CounterDesc.lookup(ID));
+ return std::make_pair(RegisteredCounters[ID], Counters.lookup(ID).Desc);
}
// Iterate through the registered counters
@@ -149,11 +145,19 @@ public:
private:
unsigned addCounter(const std::string &Name, const std::string &Desc) {
unsigned Result = RegisteredCounters.insert(Name);
- CounterDesc[Result] = Desc;
+ Counters[Result] = {};
+ Counters[Result].Desc = Desc;
return Result;
}
- DenseMap<unsigned, std::pair<long, long>> Counters;
- DenseMap<unsigned, std::string> CounterDesc;
+ // Struct to store counter info.
+ struct CounterInfo {
+ int64_t Count = 0;
+ int64_t Skip = 0;
+ int64_t StopAfter = -1;
+ bool IsSet = false;
+ std::string Desc;
+ };
+ DenseMap<unsigned, CounterInfo> Counters;
CounterVector RegisteredCounters;
};
diff --git a/include/llvm/Support/DynamicLibrary.h b/include/llvm/Support/DynamicLibrary.h
index 469d5dfad062..9563b483f6d5 100644
--- a/include/llvm/Support/DynamicLibrary.h
+++ b/include/llvm/Support/DynamicLibrary.h
@@ -64,7 +64,7 @@ namespace sys {
/// if the library fails to load.
///
/// It is safe to call this function multiple times for the same library.
- /// @brief Open a dynamic library permanently.
+ /// Open a dynamic library permanently.
static DynamicLibrary getPermanentLibrary(const char *filename,
std::string *errMsg = nullptr);
@@ -110,10 +110,10 @@ namespace sys {
/// search permanently loaded libraries (getPermanentLibrary()) as well
/// as explicitly registered symbols (AddSymbol()).
/// @throws std::string on error.
- /// @brief Search through libraries for address of a symbol
+ /// Search through libraries for address of a symbol
static void *SearchForAddressOfSymbol(const char *symbolName);
- /// @brief Convenience function for C++ophiles.
+ /// Convenience function for C++ophiles.
static void *SearchForAddressOfSymbol(const std::string &symbolName) {
return SearchForAddressOfSymbol(symbolName.c_str());
}
@@ -121,7 +121,7 @@ namespace sys {
/// This functions permanently adds the symbol \p symbolName with the
/// value \p symbolValue. These symbols are searched before any
/// libraries.
- /// @brief Add searchable symbol/value pair.
+ /// Add searchable symbol/value pair.
static void AddSymbol(StringRef symbolName, void *symbolValue);
class HandleSet;
diff --git a/include/llvm/Support/Endian.h b/include/llvm/Support/Endian.h
index f50d9b502daf..a4d3f4ff793d 100644
--- a/include/llvm/Support/Endian.h
+++ b/include/llvm/Support/Endian.h
@@ -34,7 +34,7 @@ enum {aligned = 0, unaligned = 1};
namespace detail {
-/// \brief ::value is either alignment, or alignof(T) if alignment is 0.
+/// ::value is either alignment, or alignof(T) if alignment is 0.
template<class T, int alignment>
struct PickAlignment {
enum { value = alignment == 0 ? alignof(T) : alignment };
diff --git a/include/llvm/Support/EndianStream.h b/include/llvm/Support/EndianStream.h
index 43ecd4a5c97e..9742e253ad3e 100644
--- a/include/llvm/Support/EndianStream.h
+++ b/include/llvm/Support/EndianStream.h
@@ -23,44 +23,44 @@ namespace llvm {
namespace support {
namespace endian {
-/// Adapter to write values to a stream in a particular byte order.
-template <endianness endian> struct Writer {
- raw_ostream &OS;
- Writer(raw_ostream &OS) : OS(OS) {}
- template <typename value_type> void write(ArrayRef<value_type> Vals) {
- for (value_type V : Vals)
- write(V);
- }
- template <typename value_type> void write(value_type Val) {
- Val = byte_swap<value_type, endian>(Val);
- OS.write((const char *)&Val, sizeof(value_type));
- }
-};
-template <>
-template <>
-inline void Writer<little>::write<float>(float Val) {
- write(FloatToBits(Val));
+template <typename value_type>
+inline void write(raw_ostream &os, value_type value, endianness endian) {
+ value = byte_swap<value_type>(value, endian);
+ os.write((const char *)&value, sizeof(value_type));
}
template <>
-template <>
-inline void Writer<little>::write<double>(double Val) {
- write(DoubleToBits(Val));
+inline void write<float>(raw_ostream &os, float value, endianness endian) {
+ write(os, FloatToBits(value), endian);
}
template <>
-template <>
-inline void Writer<big>::write<float>(float Val) {
- write(FloatToBits(Val));
+inline void write<double>(raw_ostream &os, double value,
+ endianness endian) {
+ write(os, DoubleToBits(value), endian);
}
-template <>
-template <>
-inline void Writer<big>::write<double>(double Val) {
- write(DoubleToBits(Val));
+template <typename value_type>
+inline void write(raw_ostream &os, ArrayRef<value_type> vals,
+ endianness endian) {
+ for (value_type v : vals)
+ write(os, v, endian);
}
+/// Adapter to write values to a stream in a particular byte order.
+struct Writer {
+ raw_ostream &OS;
+ endianness Endian;
+ Writer(raw_ostream &OS, endianness Endian) : OS(OS), Endian(Endian) {}
+ template <typename value_type> void write(ArrayRef<value_type> Val) {
+ endian::write(OS, Val, Endian);
+ }
+ template <typename value_type> void write(value_type Val) {
+ endian::write(OS, Val, Endian);
+ }
+};
+
} // end namespace endian
} // end namespace support
diff --git a/include/llvm/Support/Errc.h b/include/llvm/Support/Errc.h
index 80bfe2ac2ee5..dce42782a0d3 100644
--- a/include/llvm/Support/Errc.h
+++ b/include/llvm/Support/Errc.h
@@ -63,6 +63,7 @@ enum class errc {
no_such_process = int(std::errc::no_such_process),
not_a_directory = int(std::errc::not_a_directory),
not_enough_memory = int(std::errc::not_enough_memory),
+ not_supported = int(std::errc::not_supported),
operation_not_permitted = int(std::errc::operation_not_permitted),
permission_denied = int(std::errc::permission_denied),
read_only_file_system = int(std::errc::read_only_file_system),
diff --git a/include/llvm/Support/Errno.h b/include/llvm/Support/Errno.h
index 35dc1ea7cf84..8069c3639df3 100644
--- a/include/llvm/Support/Errno.h
+++ b/include/llvm/Support/Errno.h
@@ -34,9 +34,10 @@ template <typename FailT, typename Fun, typename... Args>
inline auto RetryAfterSignal(const FailT &Fail, const Fun &F,
const Args &... As) -> decltype(F(As...)) {
decltype(F(As...)) Res;
- do
+ do {
+ errno = 0;
Res = F(As...);
- while (Res == Fail && errno == EINTR);
+ } while (Res == Fail && errno == EINTR);
return Res;
}
diff --git a/include/llvm/Support/Error.h b/include/llvm/Support/Error.h
index 8567af392fb0..8015cab45a06 100644
--- a/include/llvm/Support/Error.h
+++ b/include/llvm/Support/Error.h
@@ -24,6 +24,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
@@ -302,6 +303,14 @@ private:
return Tmp;
}
+ friend raw_ostream &operator<<(raw_ostream &OS, const Error &E) {
+ if (auto P = E.getPtr())
+ P->log(OS);
+ else
+ OS << "success";
+ return OS;
+ }
+
ErrorInfoBase *Payload = nullptr;
};
@@ -421,7 +430,7 @@ template <class T> class LLVM_NODISCARD Expected {
static const bool isRef = std::is_reference<T>::value;
- using wrap = ReferenceStorage<typename std::remove_reference<T>::type>;
+ using wrap = std::reference_wrapper<typename std::remove_reference<T>::type>;
using error_type = std::unique_ptr<ErrorInfoBase>;
@@ -505,7 +514,7 @@ public:
getErrorStorage()->~error_type();
}
- /// \brief Return false if there is an error.
+ /// Return false if there is an error.
explicit operator bool() {
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
Unchecked = HasError;
@@ -513,24 +522,24 @@ public:
return !HasError;
}
- /// \brief Returns a reference to the stored T value.
+ /// Returns a reference to the stored T value.
reference get() {
assertIsChecked();
return *getStorage();
}
- /// \brief Returns a const reference to the stored T value.
+ /// Returns a const reference to the stored T value.
const_reference get() const {
assertIsChecked();
return const_cast<Expected<T> *>(this)->get();
}
- /// \brief Check that this Expected<T> is an error of type ErrT.
+ /// Check that this Expected<T> is an error of type ErrT.
template <typename ErrT> bool errorIsA() const {
return HasError && (*getErrorStorage())->template isA<ErrT>();
}
- /// \brief Take ownership of the stored error.
+ /// Take ownership of the stored error.
/// After calling this the Expected<T> is in an indeterminate state that can
/// only be safely destructed. No further calls (beside the destructor) should
/// be made on the Expected<T> vaule.
@@ -541,25 +550,25 @@ public:
return HasError ? Error(std::move(*getErrorStorage())) : Error::success();
}
- /// \brief Returns a pointer to the stored T value.
+ /// Returns a pointer to the stored T value.
pointer operator->() {
assertIsChecked();
return toPointer(getStorage());
}
- /// \brief Returns a const pointer to the stored T value.
+ /// Returns a const pointer to the stored T value.
const_pointer operator->() const {
assertIsChecked();
return toPointer(getStorage());
}
- /// \brief Returns a reference to the stored T value.
+ /// Returns a reference to the stored T value.
reference operator*() {
assertIsChecked();
return *getStorage();
}
- /// \brief Returns a const reference to the stored T value.
+ /// Returns a const reference to the stored T value.
const_reference operator*() const {
assertIsChecked();
return *getStorage();
@@ -882,16 +891,16 @@ Error handleErrors(Error E, HandlerTs &&... Hs) {
return handleErrorImpl(std::move(Payload), std::forward<HandlerTs>(Hs)...);
}
-/// Behaves the same as handleErrors, except that it requires that all
-/// errors be handled by the given handlers. If any unhandled error remains
-/// after the handlers have run, report_fatal_error() will be called.
+/// Behaves the same as handleErrors, except that by contract all errors
+/// *must* be handled by the given handlers (i.e. there must be no remaining
+/// errors after running the handlers, or llvm_unreachable is called).
template <typename... HandlerTs>
void handleAllErrors(Error E, HandlerTs &&... Handlers) {
cantFail(handleErrors(std::move(E), std::forward<HandlerTs>(Handlers)...));
}
/// Check that E is a non-error, then drop it.
-/// If E is an error report_fatal_error will be called.
+/// If E is an error, llvm_unreachable will be called.
inline void handleAllErrors(Error E) {
cantFail(std::move(E));
}
@@ -963,6 +972,18 @@ inline void consumeError(Error Err) {
handleAllErrors(std::move(Err), [](const ErrorInfoBase &) {});
}
+/// Helper for converting an Error to a bool.
+///
+/// This method returns true if Err is in an error state, or false if it is
+/// in a success state. Puts Err in a checked state in both cases (unlike
+/// Error::operator bool(), which only does this for success states).
+inline bool errorToBool(Error Err) {
+ bool IsError = static_cast<bool>(Err);
+ if (IsError)
+ consumeError(std::move(Err));
+ return IsError;
+}
+
/// Helper for Errors used as out-parameters.
///
/// This helper is for use with the Error-as-out-parameter idiom, where an error
@@ -1101,6 +1122,18 @@ private:
std::error_code EC;
};
+/// Create formatted StringError object.
+template <typename... Ts>
+Error createStringError(std::error_code EC, char const *Fmt,
+ const Ts &... Vals) {
+ std::string Buffer;
+ raw_string_ostream Stream(Buffer);
+ Stream << format(Fmt, Vals...);
+ return make_error<StringError>(Stream.str(), EC);
+}
+
+Error createStringError(std::error_code EC, char const *Msg);
+
/// Helper for check-and-exit error handling.
///
/// For tool use only. NOT FOR USE IN LIBRARY CODE.
diff --git a/include/llvm/Support/ErrorHandling.h b/include/llvm/Support/ErrorHandling.h
index b45f6348390e..39cbfed2436a 100644
--- a/include/llvm/Support/ErrorHandling.h
+++ b/include/llvm/Support/ErrorHandling.h
@@ -100,6 +100,8 @@ void install_bad_alloc_error_handler(fatal_error_handler_t handler,
/// Restores default bad alloc error handling behavior.
void remove_bad_alloc_error_handler();
+void install_out_of_memory_new_handler();
+
/// Reports a bad alloc error, calling any user defined bad alloc
/// error handler. In contrast to the generic 'report_fatal_error'
/// functions, this function is expected to return, e.g. the user
@@ -110,7 +112,7 @@ void remove_bad_alloc_error_handler();
/// in the unwind chain.
///
/// If no error handler is installed (default), then a bad_alloc exception
-/// is thrown if LLVM is compiled with exception support, otherwise an assertion
+/// is thrown, if LLVM is compiled with exception support, otherwise an assertion
/// is called.
void report_bad_alloc_error(const char *Reason, bool GenCrashDiag = true);
diff --git a/include/llvm/Support/ErrorOr.h b/include/llvm/Support/ErrorOr.h
index 061fb65db465..e6ce764ad822 100644
--- a/include/llvm/Support/ErrorOr.h
+++ b/include/llvm/Support/ErrorOr.h
@@ -24,19 +24,7 @@
namespace llvm {
-/// \brief Stores a reference that can be changed.
-template <typename T>
-class ReferenceStorage {
- T *Storage;
-
-public:
- ReferenceStorage(T &Ref) : Storage(&Ref) {}
-
- operator T &() const { return *Storage; }
- T &get() const { return *Storage; }
-};
-
-/// \brief Represents either an error or a value T.
+/// Represents either an error or a value T.
///
/// ErrorOr<T> is a pointer-like class that represents the result of an
/// operation. The result is either an error, or a value of type T. This is
@@ -71,7 +59,7 @@ class ErrorOr {
static const bool isRef = std::is_reference<T>::value;
- using wrap = ReferenceStorage<typename std::remove_reference<T>::type>;
+ using wrap = std::reference_wrapper<typename std::remove_reference<T>::type>;
public:
using storage_type = typename std::conditional<isRef, wrap, T>::type;
@@ -161,7 +149,7 @@ public:
getStorage()->~storage_type();
}
- /// \brief Return false if there is an error.
+ /// Return false if there is an error.
explicit operator bool() const {
return !HasError;
}
diff --git a/include/llvm/Support/FileOutputBuffer.h b/include/llvm/Support/FileOutputBuffer.h
index 6aed423a01e3..ee8cbb730878 100644
--- a/include/llvm/Support/FileOutputBuffer.h
+++ b/include/llvm/Support/FileOutputBuffer.h
@@ -30,13 +30,25 @@ namespace llvm {
/// not committed, the file will be deleted in the FileOutputBuffer destructor.
class FileOutputBuffer {
public:
- enum {
- F_executable = 1 /// set the 'x' bit on the resulting file
+ enum {
+ /// set the 'x' bit on the resulting file
+ F_executable = 1,
+
+ /// the contents of the new file are initialized from the file that exists
+ /// at the location (if present). This allows in-place modification of an
+ /// existing file.
+ F_modify = 2
};
/// Factory method to create an OutputBuffer object which manages a read/write
/// buffer of the specified size. When committed, the buffer will be written
/// to the file at the specified path.
+ ///
+ /// When F_modify is specified and \p FilePath refers to an existing on-disk
+ /// file \p Size may be set to -1, in which case the entire file is used.
+ /// Otherwise, the file shrinks or grows as necessary based on the value of
+ /// \p Size. It is an error to specify F_modify and Size=-1 if \p FilePath
+ /// does not exist.
static Expected<std::unique_ptr<FileOutputBuffer>>
create(StringRef FilePath, size_t Size, unsigned Flags = 0);
diff --git a/include/llvm/Support/FileSystem.h b/include/llvm/Support/FileSystem.h
index b1683ba5ddb3..02db4596bf1c 100644
--- a/include/llvm/Support/FileSystem.h
+++ b/include/llvm/Support/FileSystem.h
@@ -30,6 +30,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Chrono.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
@@ -53,6 +54,15 @@ namespace llvm {
namespace sys {
namespace fs {
+#if defined(_WIN32)
+// A Win32 HANDLE is a typedef of void*
+using file_t = void *;
+#else
+using file_t = int;
+#endif
+
+extern const file_t kInvalidFile;
+
/// An enumeration for the file system's view of the type.
enum class file_type {
status_error,
@@ -153,7 +163,7 @@ protected:
uid_t fs_st_uid = 0;
gid_t fs_st_gid = 0;
off_t fs_st_size = 0;
- #elif defined (LLVM_ON_WIN32)
+ #elif defined (_WIN32)
uint32_t LastAccessedTimeHigh = 0;
uint32_t LastAccessedTimeLow = 0;
uint32_t LastWriteTimeHigh = 0;
@@ -174,7 +184,7 @@ public:
uid_t UID, gid_t GID, off_t Size)
: fs_st_atime(ATime), fs_st_mtime(MTime), fs_st_uid(UID), fs_st_gid(GID),
fs_st_size(Size), Type(Type), Perms(Perms) {}
-#elif defined(LLVM_ON_WIN32)
+#elif defined(_WIN32)
basic_file_status(file_type Type, perms Perms, uint32_t LastAccessTimeHigh,
uint32_t LastAccessTimeLow, uint32_t LastWriteTimeHigh,
uint32_t LastWriteTimeLow, uint32_t FileSizeHigh,
@@ -196,7 +206,7 @@ public:
uint32_t getUser() const { return fs_st_uid; }
uint32_t getGroup() const { return fs_st_gid; }
uint64_t getSize() const { return fs_st_size; }
- #elif defined (LLVM_ON_WIN32)
+ #elif defined (_WIN32)
uint32_t getUser() const {
return 9999; // Not applicable to Windows, so...
}
@@ -223,7 +233,7 @@ class file_status : public basic_file_status {
dev_t fs_st_dev = 0;
nlink_t fs_st_nlinks = 0;
ino_t fs_st_ino = 0;
- #elif defined (LLVM_ON_WIN32)
+ #elif defined (_WIN32)
uint32_t NumLinks = 0;
uint32_t VolumeSerialNumber = 0;
uint32_t FileIndexHigh = 0;
@@ -240,7 +250,7 @@ public:
time_t ATime, time_t MTime, uid_t UID, gid_t GID, off_t Size)
: basic_file_status(Type, Perms, ATime, MTime, UID, GID, Size),
fs_st_dev(Dev), fs_st_nlinks(Links), fs_st_ino(Ino) {}
- #elif defined(LLVM_ON_WIN32)
+ #elif defined(_WIN32)
file_status(file_type Type, perms Perms, uint32_t LinkCount,
uint32_t LastAccessTimeHigh, uint32_t LastAccessTimeLow,
uint32_t LastWriteTimeHigh, uint32_t LastWriteTimeLow,
@@ -262,7 +272,7 @@ public:
/// @name Physical Operators
/// @{
-/// @brief Make \a path an absolute path.
+/// Make \a path an absolute path.
///
/// Makes \a path absolute using the \a current_directory if it is not already.
/// An empty \a path will result in the \a current_directory.
@@ -276,7 +286,7 @@ public:
std::error_code make_absolute(const Twine &current_directory,
SmallVectorImpl<char> &path);
-/// @brief Make \a path an absolute path.
+/// Make \a path an absolute path.
///
/// Makes \a path absolute using the current directory if it is not already. An
/// empty \a path will result in the current directory.
@@ -289,7 +299,7 @@ std::error_code make_absolute(const Twine &current_directory,
/// platform-specific error_code.
std::error_code make_absolute(SmallVectorImpl<char> &path);
-/// @brief Create all the non-existent directories in path.
+/// Create all the non-existent directories in path.
///
/// @param path Directories to create.
/// @returns errc::success if is_directory(path), otherwise a platform
@@ -299,7 +309,7 @@ std::error_code create_directories(const Twine &path,
bool IgnoreExisting = true,
perms Perms = owner_all | group_all);
-/// @brief Create the directory in path.
+/// Create the directory in path.
///
/// @param path Directory to create.
/// @returns errc::success if is_directory(path), otherwise a platform
@@ -308,7 +318,7 @@ std::error_code create_directories(const Twine &path,
std::error_code create_directory(const Twine &path, bool IgnoreExisting = true,
perms Perms = owner_all | group_all);
-/// @brief Create a link from \a from to \a to.
+/// Create a link from \a from to \a to.
///
/// The link may be a soft or a hard link, depending on the platform. The caller
/// may not assume which one. Currently on windows it creates a hard link since
@@ -329,7 +339,7 @@ std::error_code create_link(const Twine &to, const Twine &from);
/// specific error_code.
std::error_code create_hard_link(const Twine &to, const Twine &from);
-/// @brief Collapse all . and .. patterns, resolve all symlinks, and optionally
+/// Collapse all . and .. patterns, resolve all symlinks, and optionally
/// expand ~ expressions to the user's home directory.
///
/// @param path The path to resolve.
@@ -339,21 +349,21 @@ std::error_code create_hard_link(const Twine &to, const Twine &from);
std::error_code real_path(const Twine &path, SmallVectorImpl<char> &output,
bool expand_tilde = false);
-/// @brief Get the current path.
+/// Get the current path.
///
/// @param result Holds the current path on return.
/// @returns errc::success if the current path has been stored in result,
/// otherwise a platform-specific error_code.
std::error_code current_path(SmallVectorImpl<char> &result);
-/// @brief Set the current path.
+/// Set the current path.
///
/// @param path The path to set.
/// @returns errc::success if the current path was successfully set,
/// otherwise a platform-specific error_code.
std::error_code set_current_path(const Twine &path);
-/// @brief Remove path. Equivalent to POSIX remove().
+/// Remove path. Equivalent to POSIX remove().
///
/// @param path Input path.
/// @returns errc::success if path has been removed or didn't exist, otherwise a
@@ -361,14 +371,14 @@ std::error_code set_current_path(const Twine &path);
/// returns error if the file didn't exist.
std::error_code remove(const Twine &path, bool IgnoreNonExisting = true);
-/// @brief Recursively delete a directory.
+/// Recursively delete a directory.
///
/// @param path Input path.
/// @returns errc::success if path has been removed or didn't exist, otherwise a
/// platform-specific error code.
std::error_code remove_directories(const Twine &path, bool IgnoreErrors = true);
-/// @brief Rename \a from to \a to.
+/// Rename \a from to \a to.
///
/// Files are renamed as if by POSIX rename(), except that on Windows there may
/// be a short interval of time during which the destination file does not
@@ -378,13 +388,19 @@ std::error_code remove_directories(const Twine &path, bool IgnoreErrors = true);
/// @param to The path to rename to. This is created.
std::error_code rename(const Twine &from, const Twine &to);
-/// @brief Copy the contents of \a From to \a To.
+/// Copy the contents of \a From to \a To.
///
/// @param From The path to copy from.
/// @param To The path to copy to. This is created.
std::error_code copy_file(const Twine &From, const Twine &To);
-/// @brief Resize path to size. File is resized as if by POSIX truncate().
+/// Copy the contents of \a From to \a To.
+///
+/// @param From The path to copy from.
+/// @param ToFD The open file descriptor of the destination file.
+std::error_code copy_file(const Twine &From, int ToFD);
+
+/// Resize path to size. File is resized as if by POSIX truncate().
///
/// @param FD Input file descriptor.
/// @param Size Size to resize to.
@@ -392,21 +408,21 @@ std::error_code copy_file(const Twine &From, const Twine &To);
/// platform-specific error_code.
std::error_code resize_file(int FD, uint64_t Size);
-/// @brief Compute an MD5 hash of a file's contents.
+/// Compute an MD5 hash of a file's contents.
///
/// @param FD Input file descriptor.
/// @returns An MD5Result with the hash computed, if successful, otherwise a
/// std::error_code.
ErrorOr<MD5::MD5Result> md5_contents(int FD);
-/// @brief Version of compute_md5 that doesn't require an open file descriptor.
+/// Version of compute_md5 that doesn't require an open file descriptor.
ErrorOr<MD5::MD5Result> md5_contents(const Twine &Path);
/// @}
/// @name Physical Observers
/// @{
-/// @brief Does file exist?
+/// Does file exist?
///
/// @param status A basic_file_status previously returned from stat.
/// @returns True if the file represented by status exists, false if it does
@@ -415,14 +431,14 @@ bool exists(const basic_file_status &status);
enum class AccessMode { Exist, Write, Execute };
-/// @brief Can the file be accessed?
+/// Can the file be accessed?
///
/// @param Path Input path.
/// @returns errc::success if the path can be accessed, otherwise a
/// platform-specific error_code.
std::error_code access(const Twine &Path, AccessMode Mode);
-/// @brief Does file exist?
+/// Does file exist?
///
/// @param Path Input path.
/// @returns True if it exists, false otherwise.
@@ -430,13 +446,13 @@ inline bool exists(const Twine &Path) {
return !access(Path, AccessMode::Exist);
}
-/// @brief Can we execute this file?
+/// Can we execute this file?
///
/// @param Path Input path.
/// @returns True if we can execute it, false otherwise.
bool can_execute(const Twine &Path);
-/// @brief Can we write this file?
+/// Can we write this file?
///
/// @param Path Input path.
/// @returns True if we can write to it, false otherwise.
@@ -444,7 +460,7 @@ inline bool can_write(const Twine &Path) {
return !access(Path, AccessMode::Write);
}
-/// @brief Do file_status's represent the same thing?
+/// Do file_status's represent the same thing?
///
/// @param A Input file_status.
/// @param B Input file_status.
@@ -455,7 +471,7 @@ inline bool can_write(const Twine &Path) {
/// otherwise.
bool equivalent(file_status A, file_status B);
-/// @brief Do paths represent the same thing?
+/// Do paths represent the same thing?
///
/// assert(status_known(A) || status_known(B));
///
@@ -467,14 +483,14 @@ bool equivalent(file_status A, file_status B);
/// platform-specific error_code.
std::error_code equivalent(const Twine &A, const Twine &B, bool &result);
-/// @brief Simpler version of equivalent for clients that don't need to
+/// Simpler version of equivalent for clients that don't need to
/// differentiate between an error and false.
inline bool equivalent(const Twine &A, const Twine &B) {
bool result;
return !equivalent(A, B, result) && result;
}
-/// @brief Is the file mounted on a local filesystem?
+/// Is the file mounted on a local filesystem?
///
/// @param path Input path.
/// @param result Set to true if \a path is on fixed media such as a hard disk,
@@ -483,24 +499,24 @@ inline bool equivalent(const Twine &A, const Twine &B) {
/// platform specific error_code.
std::error_code is_local(const Twine &path, bool &result);
-/// @brief Version of is_local accepting an open file descriptor.
+/// Version of is_local accepting an open file descriptor.
std::error_code is_local(int FD, bool &result);
-/// @brief Simpler version of is_local for clients that don't need to
+/// Simpler version of is_local for clients that don't need to
/// differentiate between an error and false.
inline bool is_local(const Twine &Path) {
bool Result;
return !is_local(Path, Result) && Result;
}
-/// @brief Simpler version of is_local accepting an open file descriptor for
+/// Simpler version of is_local accepting an open file descriptor for
/// clients that don't need to differentiate between an error and false.
inline bool is_local(int FD) {
bool Result;
return !is_local(FD, Result) && Result;
}
-/// @brief Does status represent a directory?
+/// Does status represent a directory?
///
/// @param Path The path to get the type of.
/// @param Follow For symbolic links, indicates whether to return the file type
@@ -508,13 +524,13 @@ inline bool is_local(int FD) {
/// @returns A value from the file_type enumeration indicating the type of file.
file_type get_file_type(const Twine &Path, bool Follow = true);
-/// @brief Does status represent a directory?
+/// Does status represent a directory?
///
/// @param status A basic_file_status previously returned from status.
/// @returns status.type() == file_type::directory_file.
bool is_directory(const basic_file_status &status);
-/// @brief Is path a directory?
+/// Is path a directory?
///
/// @param path Input path.
/// @param result Set to true if \a path is a directory (after following
@@ -523,20 +539,20 @@ bool is_directory(const basic_file_status &status);
/// platform-specific error_code.
std::error_code is_directory(const Twine &path, bool &result);
-/// @brief Simpler version of is_directory for clients that don't need to
+/// Simpler version of is_directory for clients that don't need to
/// differentiate between an error and false.
inline bool is_directory(const Twine &Path) {
bool Result;
return !is_directory(Path, Result) && Result;
}
-/// @brief Does status represent a regular file?
+/// Does status represent a regular file?
///
/// @param status A basic_file_status previously returned from status.
/// @returns status_known(status) && status.type() == file_type::regular_file.
bool is_regular_file(const basic_file_status &status);
-/// @brief Is path a regular file?
+/// Is path a regular file?
///
/// @param path Input path.
/// @param result Set to true if \a path is a regular file (after following
@@ -545,7 +561,7 @@ bool is_regular_file(const basic_file_status &status);
/// platform-specific error_code.
std::error_code is_regular_file(const Twine &path, bool &result);
-/// @brief Simpler version of is_regular_file for clients that don't need to
+/// Simpler version of is_regular_file for clients that don't need to
/// differentiate between an error and false.
inline bool is_regular_file(const Twine &Path) {
bool Result;
@@ -554,13 +570,13 @@ inline bool is_regular_file(const Twine &Path) {
return Result;
}
-/// @brief Does status represent a symlink file?
+/// Does status represent a symlink file?
///
/// @param status A basic_file_status previously returned from status.
/// @returns status_known(status) && status.type() == file_type::symlink_file.
bool is_symlink_file(const basic_file_status &status);
-/// @brief Is path a symlink file?
+/// Is path a symlink file?
///
/// @param path Input path.
/// @param result Set to true if \a path is a symlink file, false if it is not.
@@ -569,7 +585,7 @@ bool is_symlink_file(const basic_file_status &status);
/// platform-specific error_code.
std::error_code is_symlink_file(const Twine &path, bool &result);
-/// @brief Simpler version of is_symlink_file for clients that don't need to
+/// Simpler version of is_symlink_file for clients that don't need to
/// differentiate between an error and false.
inline bool is_symlink_file(const Twine &Path) {
bool Result;
@@ -578,14 +594,14 @@ inline bool is_symlink_file(const Twine &Path) {
return Result;
}
-/// @brief Does this status represent something that exists but is not a
+/// Does this status represent something that exists but is not a
/// directory or regular file?
///
/// @param status A basic_file_status previously returned from status.
/// @returns exists(s) && !is_regular_file(s) && !is_directory(s)
bool is_other(const basic_file_status &status);
-/// @brief Is path something that exists but is not a directory,
+/// Is path something that exists but is not a directory,
/// regular file, or symlink?
///
/// @param path Input path.
@@ -595,7 +611,7 @@ bool is_other(const basic_file_status &status);
/// platform-specific error_code.
std::error_code is_other(const Twine &path, bool &result);
-/// @brief Get file status as if by POSIX stat().
+/// Get file status as if by POSIX stat().
///
/// @param path Input path.
/// @param result Set to the file status.
@@ -606,10 +622,10 @@ std::error_code is_other(const Twine &path, bool &result);
std::error_code status(const Twine &path, file_status &result,
bool follow = true);
-/// @brief A version for when a file descriptor is already available.
+/// A version for when a file descriptor is already available.
std::error_code status(int FD, file_status &Result);
-/// @brief Set file permissions.
+/// Set file permissions.
///
/// @param Path File to set permissions on.
/// @param Permissions New file permissions.
@@ -620,7 +636,7 @@ std::error_code status(int FD, file_status &Result);
/// Otherwise, the file will be marked as read-only.
std::error_code setPermissions(const Twine &Path, perms Permissions);
-/// @brief Get file permissions.
+/// Get file permissions.
///
/// @param Path File to get permissions from.
/// @returns the permissions if they were successfully retrieved, otherwise a
@@ -630,7 +646,7 @@ std::error_code setPermissions(const Twine &Path, perms Permissions);
/// will be returned.
ErrorOr<perms> getPermissions(const Twine &Path);
-/// @brief Get file size.
+/// Get file size.
///
/// @param Path Input path.
/// @param Result Set to the size of the file in \a Path.
@@ -645,20 +661,20 @@ inline std::error_code file_size(const Twine &Path, uint64_t &Result) {
return std::error_code();
}
-/// @brief Set the file modification and access time.
+/// Set the file modification and access time.
///
/// @returns errc::success if the file times were successfully set, otherwise a
/// platform-specific error_code or errc::function_not_supported on
/// platforms where the functionality isn't available.
std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time);
-/// @brief Is status available?
+/// Is status available?
///
/// @param s Input file status.
/// @returns True if status() != status_error.
bool status_known(const basic_file_status &s);
-/// @brief Is status available?
+/// Is status available?
///
/// @param path Input path.
/// @param result Set to true if status() != status_error.
@@ -666,30 +682,58 @@ bool status_known(const basic_file_status &s);
/// platform-specific error_code.
std::error_code status_known(const Twine &path, bool &result);
-enum OpenFlags : unsigned {
- F_None = 0,
+enum CreationDisposition : unsigned {
+ /// CD_CreateAlways - When opening a file:
+ /// * If it already exists, truncate it.
+ /// * If it does not already exist, create a new file.
+ CD_CreateAlways = 0,
+
+ /// CD_CreateNew - When opening a file:
+ /// * If it already exists, fail.
+ /// * If it does not already exist, create a new file.
+ CD_CreateNew = 1,
+
+ /// CD_OpenAlways - When opening a file:
+ /// * If it already exists, open the file with the offset set to 0.
+ /// * If it does not already exist, fail.
+ CD_OpenExisting = 2,
+
+ /// CD_OpenAlways - When opening a file:
+ /// * If it already exists, open the file with the offset set to 0.
+ /// * If it does not already exist, create a new file.
+ CD_OpenAlways = 3,
+};
- /// F_Excl - When opening a file, this flag makes raw_fd_ostream
- /// report an error if the file already exists.
- F_Excl = 1,
+enum FileAccess : unsigned {
+ FA_Read = 1,
+ FA_Write = 2,
+};
- /// F_Append - When opening a file, if it already exists append to the
- /// existing file instead of returning an error. This may not be specified
- /// with F_Excl.
- F_Append = 2,
+enum OpenFlags : unsigned {
+ OF_None = 0,
+ F_None = 0, // For compatibility
/// The file should be opened in text mode on platforms that make this
/// distinction.
- F_Text = 4,
+ OF_Text = 1,
+ F_Text = 1, // For compatibility
- /// Open the file for read and write.
- F_RW = 8,
+ /// The file should be opened in append mode.
+ OF_Append = 2,
+ F_Append = 2, // For compatibility
/// Delete the file on close. Only makes a difference on windows.
- F_Delete = 16
+ OF_Delete = 4,
+
+ /// When a child process is launched, this file should remain open in the
+ /// child process.
+ OF_ChildInherit = 8,
+
+ /// Force files Atime to be updated on access. Only makes a difference on windows.
+ OF_UpdateAtime = 16,
};
-/// @brief Create a uniquely named file.
+/// Create a uniquely named file.
///
/// Generates a unique path suitable for a temporary file and then opens it as a
/// file. The name is based on \a model with '%' replaced by a random char in
@@ -712,12 +756,13 @@ enum OpenFlags : unsigned {
/// otherwise a platform-specific error_code.
std::error_code createUniqueFile(const Twine &Model, int &ResultFD,
SmallVectorImpl<char> &ResultPath,
- unsigned Mode = all_read | all_write,
- sys::fs::OpenFlags Flags = sys::fs::F_RW);
+ unsigned Mode = all_read | all_write);
-/// @brief Simpler version for clients that don't want an open file.
+/// Simpler version for clients that don't want an open file. An empty
+/// file will still be created.
std::error_code createUniqueFile(const Twine &Model,
- SmallVectorImpl<char> &ResultPath);
+ SmallVectorImpl<char> &ResultPath,
+ unsigned Mode = all_read | all_write);
/// Represents a temporary file.
///
@@ -757,7 +802,7 @@ public:
~TempFile();
};
-/// @brief Create a file in the system temporary directory.
+/// Create a file in the system temporary directory.
///
/// The filename is of the form prefix-random_chars.suffix. Since the directory
/// is not know to the caller, Prefix and Suffix cannot have path separators.
@@ -767,16 +812,38 @@ public:
/// running the assembler.
std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
int &ResultFD,
- SmallVectorImpl<char> &ResultPath,
- sys::fs::OpenFlags Flags = sys::fs::F_RW);
+ SmallVectorImpl<char> &ResultPath);
-/// @brief Simpler version for clients that don't want an open file.
+/// Simpler version for clients that don't want an open file. An empty
+/// file will still be created.
std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
SmallVectorImpl<char> &ResultPath);
std::error_code createUniqueDirectory(const Twine &Prefix,
SmallVectorImpl<char> &ResultPath);
+/// Get a unique name, not currently exisiting in the filesystem. Subject
+/// to race conditions, prefer to use createUniqueFile instead.
+///
+/// Similar to createUniqueFile, but instead of creating a file only
+/// checks if it exists. This function is subject to race conditions, if you
+/// want to use the returned name to actually create a file, use
+/// createUniqueFile instead.
+std::error_code getPotentiallyUniqueFileName(const Twine &Model,
+ SmallVectorImpl<char> &ResultPath);
+
+/// Get a unique temporary file name, not currently exisiting in the
+/// filesystem. Subject to race conditions, prefer to use createTemporaryFile
+/// instead.
+///
+/// Similar to createTemporaryFile, but instead of creating a file only
+/// checks if it exists. This function is subject to race conditions, if you
+/// want to use the returned name to actually create a file, use
+/// createTemporaryFile instead.
+std::error_code
+getPotentiallyUniqueTempFileName(const Twine &Prefix, StringRef Suffix,
+ SmallVectorImpl<char> &ResultPath);
+
inline OpenFlags operator|(OpenFlags A, OpenFlags B) {
return OpenFlags(unsigned(A) | unsigned(B));
}
@@ -786,15 +853,181 @@ inline OpenFlags &operator|=(OpenFlags &A, OpenFlags B) {
return A;
}
-std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
- OpenFlags Flags, unsigned Mode = 0666);
+inline FileAccess operator|(FileAccess A, FileAccess B) {
+ return FileAccess(unsigned(A) | unsigned(B));
+}
+
+inline FileAccess &operator|=(FileAccess &A, FileAccess B) {
+ A = A | B;
+ return A;
+}
+
+/// @brief Opens a file with the specified creation disposition, access mode,
+/// and flags and returns a file descriptor.
+///
+/// The caller is responsible for closing the file descriptor once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param ResultFD If the file could be opened successfully, its descriptor
+/// is stored in this location. Otherwise, this is set to -1.
+/// @param Disp Value specifying the existing-file behavior.
+/// @param Access Value specifying whether to open the file in read, write, or
+/// read-write mode.
+/// @param Flags Additional flags.
+/// @param Mode The access permissions of the file, represented in octal.
+/// @returns errc::success if \a Name has been opened, otherwise a
+/// platform-specific error_code.
+std::error_code openFile(const Twine &Name, int &ResultFD,
+ CreationDisposition Disp, FileAccess Access,
+ OpenFlags Flags, unsigned Mode = 0666);
+
+/// @brief Opens a file with the specified creation disposition, access mode,
+/// and flags and returns a platform-specific file object.
+///
+/// The caller is responsible for closing the file object once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param Disp Value specifying the existing-file behavior.
+/// @param Access Value specifying whether to open the file in read, write, or
+/// read-write mode.
+/// @param Flags Additional flags.
+/// @param Mode The access permissions of the file, represented in octal.
+/// @returns errc::success if \a Name has been opened, otherwise a
+/// platform-specific error_code.
+Expected<file_t> openNativeFile(const Twine &Name, CreationDisposition Disp,
+ FileAccess Access, OpenFlags Flags,
+ unsigned Mode = 0666);
+
+/// @brief Opens the file with the given name in a write-only or read-write
+/// mode, returning its open file descriptor. If the file does not exist, it
+/// is created.
+///
+/// The caller is responsible for closing the file descriptor once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param ResultFD If the file could be opened successfully, its descriptor
+/// is stored in this location. Otherwise, this is set to -1.
+/// @param Flags Additional flags used to determine whether the file should be
+/// opened in, for example, read-write or in write-only mode.
+/// @param Mode The access permissions of the file, represented in octal.
+/// @returns errc::success if \a Name has been opened, otherwise a
+/// platform-specific error_code.
+inline std::error_code
+openFileForWrite(const Twine &Name, int &ResultFD,
+ CreationDisposition Disp = CD_CreateAlways,
+ OpenFlags Flags = OF_None, unsigned Mode = 0666) {
+ return openFile(Name, ResultFD, Disp, FA_Write, Flags, Mode);
+}
+
+/// @brief Opens the file with the given name in a write-only or read-write
+/// mode, returning its open file descriptor. If the file does not exist, it
+/// is created.
+///
+/// The caller is responsible for closing the freeing the file once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param Flags Additional flags used to determine whether the file should be
+/// opened in, for example, read-write or in write-only mode.
+/// @param Mode The access permissions of the file, represented in octal.
+/// @returns a platform-specific file descriptor if \a Name has been opened,
+/// otherwise an error object.
+inline Expected<file_t> openNativeFileForWrite(const Twine &Name,
+ CreationDisposition Disp,
+ OpenFlags Flags,
+ unsigned Mode = 0666) {
+ return openNativeFile(Name, Disp, FA_Write, Flags, Mode);
+}
+
+/// @brief Opens the file with the given name in a write-only or read-write
+/// mode, returning its open file descriptor. If the file does not exist, it
+/// is created.
+///
+/// The caller is responsible for closing the file descriptor once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param ResultFD If the file could be opened successfully, its descriptor
+/// is stored in this location. Otherwise, this is set to -1.
+/// @param Flags Additional flags used to determine whether the file should be
+/// opened in, for example, read-write or in write-only mode.
+/// @param Mode The access permissions of the file, represented in octal.
+/// @returns errc::success if \a Name has been opened, otherwise a
+/// platform-specific error_code.
+inline std::error_code openFileForReadWrite(const Twine &Name, int &ResultFD,
+ CreationDisposition Disp,
+ OpenFlags Flags,
+ unsigned Mode = 0666) {
+ return openFile(Name, ResultFD, Disp, FA_Write | FA_Read, Flags, Mode);
+}
+/// @brief Opens the file with the given name in a write-only or read-write
+/// mode, returning its open file descriptor. If the file does not exist, it
+/// is created.
+///
+/// The caller is responsible for closing the freeing the file once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param Flags Additional flags used to determine whether the file should be
+/// opened in, for example, read-write or in write-only mode.
+/// @param Mode The access permissions of the file, represented in octal.
+/// @returns a platform-specific file descriptor if \a Name has been opened,
+/// otherwise an error object.
+inline Expected<file_t> openNativeFileForReadWrite(const Twine &Name,
+ CreationDisposition Disp,
+ OpenFlags Flags,
+ unsigned Mode = 0666) {
+ return openNativeFile(Name, Disp, FA_Write | FA_Read, Flags, Mode);
+}
+
+/// @brief Opens the file with the given name in a read-only mode, returning
+/// its open file descriptor.
+///
+/// The caller is responsible for closing the file descriptor once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param ResultFD If the file could be opened successfully, its descriptor
+/// is stored in this location. Otherwise, this is set to -1.
+/// @param RealPath If nonnull, extra work is done to determine the real path
+/// of the opened file, and that path is stored in this
+/// location.
+/// @returns errc::success if \a Name has been opened, otherwise a
+/// platform-specific error_code.
std::error_code openFileForRead(const Twine &Name, int &ResultFD,
+ OpenFlags Flags = OF_None,
SmallVectorImpl<char> *RealPath = nullptr);
+/// @brief Opens the file with the given name in a read-only mode, returning
+/// its open file descriptor.
+///
+/// The caller is responsible for closing the freeing the file once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param RealPath If nonnull, extra work is done to determine the real path
+/// of the opened file, and that path is stored in this
+/// location.
+/// @returns a platform-specific file descriptor if \a Name has been opened,
+/// otherwise an error object.
+Expected<file_t>
+openNativeFileForRead(const Twine &Name, OpenFlags Flags = OF_None,
+ SmallVectorImpl<char> *RealPath = nullptr);
+
+/// @brief Close the file object. This should be used instead of ::close for
+/// portability.
+///
+/// @param F On input, this is the file to close. On output, the file is
+/// set to kInvalidFile.
+void closeFile(file_t &F);
+
std::error_code getUniqueID(const Twine Path, UniqueID &Result);
-/// @brief Get disk space usage information.
+/// Get disk space usage information.
///
/// Note: Users must be careful about "Time Of Check, Time Of Use" kind of bug.
/// Note: Windows reports results according to the quota allocated to the user.
@@ -819,6 +1052,10 @@ private:
/// Platform-specific mapping state.
size_t Size;
void *Mapping;
+#ifdef _WIN32
+ void *FileHandle;
+#endif
+ mapmode Mode;
std::error_code init(int FD, uint64_t Offset, mapmode Mode);
@@ -924,14 +1161,16 @@ public:
SmallString<128> path_storage;
ec = detail::directory_iterator_construct(
*State, path.toStringRef(path_storage), FollowSymlinks);
+ update_error_code_for_current_entry(ec);
}
explicit directory_iterator(const directory_entry &de, std::error_code &ec,
bool follow_symlinks = true)
: FollowSymlinks(follow_symlinks) {
State = std::make_shared<detail::DirIterState>();
- ec =
- detail::directory_iterator_construct(*State, de.path(), FollowSymlinks);
+ ec = detail::directory_iterator_construct(
+ *State, de.path(), FollowSymlinks);
+ update_error_code_for_current_entry(ec);
}
/// Construct end iterator.
@@ -940,6 +1179,7 @@ public:
// No operator++ because we need error_code.
directory_iterator &increment(std::error_code &ec) {
ec = directory_iterator_increment(*State);
+ update_error_code_for_current_entry(ec);
return *this;
}
@@ -961,6 +1201,24 @@ public:
}
// Other members as required by
// C++ Std, 24.1.1 Input iterators [input.iterators]
+
+private:
+ // Checks if current entry is valid and populates error code. For example,
+ // current entry may not exist due to broken symbol links.
+ void update_error_code_for_current_entry(std::error_code &ec) {
+ // Bail out if error has already occured earlier to avoid overwriting it.
+ if (ec)
+ return;
+
+ // Empty directory entry is used to mark the end of an interation, it's not
+ // an error.
+ if (State->CurrentEntry == directory_entry())
+ return;
+
+ ErrorOr<basic_file_status> status = State->CurrentEntry.status();
+ if (!status)
+ ec = status.getError();
+ }
};
namespace detail {
@@ -998,11 +1256,9 @@ public:
if (State->HasNoPushRequest)
State->HasNoPushRequest = false;
else {
- ErrorOr<basic_file_status> st = State->Stack.top()->status();
- if (!st) return *this;
- if (is_directory(*st)) {
+ ErrorOr<basic_file_status> status = State->Stack.top()->status();
+ if (status && is_directory(*status)) {
State->Stack.push(directory_iterator(*State->Stack.top(), ec, Follow));
- if (ec) return *this;
if (State->Stack.top() != end_itr) {
++State->Level;
return *this;
diff --git a/include/llvm/Support/FormatAdapters.h b/include/llvm/Support/FormatAdapters.h
index 197beb7363df..8320eaad39a9 100644
--- a/include/llvm/Support/FormatAdapters.h
+++ b/include/llvm/Support/FormatAdapters.h
@@ -12,6 +12,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/FormatCommon.h"
#include "llvm/Support/FormatVariadicDetails.h"
#include "llvm/Support/raw_ostream.h"
@@ -19,7 +20,7 @@
namespace llvm {
template <typename T> class FormatAdapter : public detail::format_adapter {
protected:
- explicit FormatAdapter(T &&Item) : Item(Item) {}
+ explicit FormatAdapter(T &&Item) : Item(std::forward<T>(Item)) {}
T Item;
};
@@ -71,6 +72,14 @@ public:
}
}
};
+
+class ErrorAdapter : public FormatAdapter<Error> {
+public:
+ ErrorAdapter(Error &&Item) : FormatAdapter(std::move(Item)) {}
+ ErrorAdapter(ErrorAdapter &&) = default;
+ ~ErrorAdapter() { consumeError(std::move(Item)); }
+ void format(llvm::raw_ostream &Stream, StringRef Style) { Stream << Item; }
+};
}
template <typename T>
@@ -88,6 +97,13 @@ template <typename T>
detail::RepeatAdapter<T> fmt_repeat(T &&Item, size_t Count) {
return detail::RepeatAdapter<T>(std::forward<T>(Item), Count);
}
+
+// llvm::Error values must be consumed before being destroyed.
+// Wrapping an error in fmt_consume explicitly indicates that the formatv_object
+// should take ownership and consume it.
+inline detail::ErrorAdapter fmt_consume(Error &&Item) {
+ return detail::ErrorAdapter(std::move(Item));
+}
}
#endif
diff --git a/include/llvm/Support/FormatVariadic.h b/include/llvm/Support/FormatVariadic.h
index 8c08a7d9488f..b0f582513e07 100644
--- a/include/llvm/Support/FormatVariadic.h
+++ b/include/llvm/Support/FormatVariadic.h
@@ -118,7 +118,7 @@ public:
auto W = Adapters[R.Index];
- FmtAlign Align(*W, R.Where, R.Align);
+ FmtAlign Align(*W, R.Where, R.Align, R.Pad);
Align.format(S, R.Options);
}
}
@@ -168,7 +168,7 @@ public:
}
};
-// \brief Format text given a format string and replacement parameters.
+// Format text given a format string and replacement parameters.
//
// ===General Description===
//
@@ -237,6 +237,8 @@ public:
// for type T containing a method whose signature is:
// void format(const T &Obj, raw_ostream &Stream, StringRef Options)
// Then this method is invoked as described in Step 1.
+// 3. If an appropriate operator<< for raw_ostream exists, it will be used.
+// For this to work, (raw_ostream& << const T&) must return raw_ostream&.
//
// If a match cannot be found through either of the above methods, a compiler
// error is generated.
@@ -258,13 +260,6 @@ inline auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object<decltype(
std::make_tuple(detail::build_format_adapter(std::forward<Ts>(Vals))...));
}
-// Allow a formatv_object to be formatted (no options supported).
-template <typename T> struct format_provider<formatv_object<T>> {
- static void format(const formatv_object<T> &V, raw_ostream &OS, StringRef) {
- OS << V;
- }
-};
-
} // end namespace llvm
#endif // LLVM_SUPPORT_FORMATVARIADIC_H
diff --git a/include/llvm/Support/FormatVariadicDetails.h b/include/llvm/Support/FormatVariadicDetails.h
index 9b60462209dc..56dda430efda 100644
--- a/include/llvm/Support/FormatVariadicDetails.h
+++ b/include/llvm/Support/FormatVariadicDetails.h
@@ -17,6 +17,7 @@
namespace llvm {
template <typename T, typename Enable = void> struct format_provider {};
+class Error;
namespace detail {
class format_adapter {
@@ -38,6 +39,17 @@ public:
}
};
+template <typename T>
+class stream_operator_format_adapter : public format_adapter {
+ T Item;
+
+public:
+ explicit stream_operator_format_adapter(T &&Item)
+ : Item(std::forward<T>(Item)) {}
+
+ void format(llvm::raw_ostream &S, StringRef Options) override { S << Item; }
+};
+
template <typename T> class missing_format_adapter;
// Test if format_provider<T> is defined on T and contains a member function
@@ -59,6 +71,23 @@ public:
(sizeof(test<llvm::format_provider<Decayed>>(nullptr)) == 1);
};
+// Test if raw_ostream& << T -> raw_ostream& is findable via ADL.
+template <class T> class has_StreamOperator {
+public:
+ using ConstRefT = const typename std::decay<T>::type &;
+
+ template <typename U>
+ static char test(typename std::enable_if<
+ std::is_same<decltype(std::declval<llvm::raw_ostream &>()
+ << std::declval<U>()),
+ llvm::raw_ostream &>::value,
+ int *>::type);
+
+ template <typename U> static double test(...);
+
+ static bool const value = (sizeof(test<ConstRefT>(nullptr)) == 1);
+};
+
// Simple template that decides whether a type T should use the member-function
// based format() invocation.
template <typename T>
@@ -77,15 +106,24 @@ struct uses_format_provider
bool, !uses_format_member<T>::value && has_FormatProvider<T>::value> {
};
+// Simple template that decides whether a type T should use the operator<<
+// based format() invocation. This takes last priority.
+template <typename T>
+struct uses_stream_operator
+ : public std::integral_constant<bool, !uses_format_member<T>::value &&
+ !uses_format_provider<T>::value &&
+ has_StreamOperator<T>::value> {};
+
// Simple template that decides whether a type T has neither a member-function
// nor format_provider based implementation that it can use. Mostly used so
// that the compiler spits out a nice diagnostic when a type with no format
// implementation can be located.
template <typename T>
struct uses_missing_provider
- : public std::integral_constant<bool,
- !uses_format_member<T>::value &&
- !uses_format_provider<T>::value> {};
+ : public std::integral_constant<bool, !uses_format_member<T>::value &&
+ !uses_format_provider<T>::value &&
+ !uses_stream_operator<T>::value> {
+};
template <typename T>
typename std::enable_if<uses_format_member<T>::value, T>::type
@@ -101,6 +139,19 @@ build_format_adapter(T &&Item) {
}
template <typename T>
+typename std::enable_if<uses_stream_operator<T>::value,
+ stream_operator_format_adapter<T>>::type
+build_format_adapter(T &&Item) {
+ // If the caller passed an Error by value, then stream_operator_format_adapter
+ // would be responsible for consuming it.
+ // Make the caller opt into this by calling fmt_consume().
+ static_assert(
+ !std::is_same<llvm::Error, typename std::remove_cv<T>::type>::value,
+ "llvm::Error-by-value must be wrapped in fmt_consume() for formatv");
+ return stream_operator_format_adapter<T>(std::forward<T>(Item));
+}
+
+template <typename T>
typename std::enable_if<uses_missing_provider<T>::value,
missing_format_adapter<T>>::type
build_format_adapter(T &&Item) {
diff --git a/include/llvm/Support/GenericDomTree.h b/include/llvm/Support/GenericDomTree.h
index 635c87a106f0..115abc23e2c6 100644
--- a/include/llvm/Support/GenericDomTree.h
+++ b/include/llvm/Support/GenericDomTree.h
@@ -50,9 +50,9 @@ template <typename DomTreeT>
struct SemiNCAInfo;
} // namespace DomTreeBuilder
-/// \brief Base class for the actual dominator tree node.
+/// Base class for the actual dominator tree node.
template <class NodeT> class DomTreeNodeBase {
- friend struct PostDominatorTree;
+ friend class PostDominatorTree;
friend class DominatorTreeBase<NodeT, false>;
friend class DominatorTreeBase<NodeT, true>;
friend struct DomTreeBuilder::SemiNCAInfo<DominatorTreeBase<NodeT, false>>;
@@ -234,10 +234,10 @@ void ApplyUpdates(DomTreeT &DT,
ArrayRef<typename DomTreeT::UpdateType> Updates);
template <typename DomTreeT>
-bool Verify(const DomTreeT &DT);
+bool Verify(const DomTreeT &DT, typename DomTreeT::VerificationLevel VL);
} // namespace DomTreeBuilder
-/// \brief Core dominator tree base class.
+/// Core dominator tree base class.
///
/// This class is a generic template over graph nodes. It is instantiated for
/// various graphs in the LLVM IR or in the code generator.
@@ -259,7 +259,9 @@ class DominatorTreeBase {
static constexpr UpdateKind Insert = UpdateKind::Insert;
static constexpr UpdateKind Delete = UpdateKind::Delete;
- protected:
+ enum class VerificationLevel { Fast, Basic, Full };
+
+protected:
// Dominators always have a single root, postdominators can have more.
SmallVector<NodeT *, IsPostDom ? 4 : 1> Roots;
@@ -316,6 +318,12 @@ class DominatorTreeBase {
bool compare(const DominatorTreeBase &Other) const {
if (Parent != Other.Parent) return true;
+ if (Roots.size() != Other.Roots.size())
+ return true;
+
+ if (!std::is_permutation(Roots.begin(), Roots.end(), Other.Roots.begin()))
+ return true;
+
const DomTreeNodeMapType &OtherDomTreeNodes = Other.DomTreeNodes;
if (DomTreeNodes.size() != OtherDomTreeNodes.size())
return true;
@@ -343,7 +351,7 @@ class DominatorTreeBase {
/// block. This is the same as using operator[] on this class. The result
/// may (but is not required to) be null for a forward (backwards)
/// statically unreachable block.
- DomTreeNodeBase<NodeT> *getNode(NodeT *BB) const {
+ DomTreeNodeBase<NodeT> *getNode(const NodeT *BB) const {
auto I = DomTreeNodes.find(BB);
if (I != DomTreeNodes.end())
return I->second.get();
@@ -351,7 +359,9 @@ class DominatorTreeBase {
}
/// See getNode.
- DomTreeNodeBase<NodeT> *operator[](NodeT *BB) const { return getNode(BB); }
+ DomTreeNodeBase<NodeT> *operator[](const NodeT *BB) const {
+ return getNode(BB);
+ }
/// getRootNode - This returns the entry node for the CFG of the function. If
/// this tree represents the post-dominance relations for a function, however,
@@ -750,10 +760,25 @@ public:
DomTreeBuilder::Calculate(*this);
}
- /// verify - check parent and sibling property
- bool verify() const { return DomTreeBuilder::Verify(*this); }
+ /// verify - checks if the tree is correct. There are 3 level of verification:
+ /// - Full -- verifies if the tree is correct by making sure all the
+ /// properties (including the parent and the sibling property)
+ /// hold.
+ /// Takes O(N^3) time.
+ ///
+ /// - Basic -- checks if the tree is correct, but compares it to a freshly
+ /// constructed tree instead of checking the sibling property.
+ /// Takes O(N^2) time.
+ ///
+ /// - Fast -- checks basic tree structure and compares it with a freshly
+ /// constructed tree.
+ /// Takes O(N^2) time worst case, but is faster in practise (same
+ /// as tree construction).
+ bool verify(VerificationLevel VL = VerificationLevel::Full) const {
+ return DomTreeBuilder::Verify(*this, VL);
+ }
- protected:
+protected:
void addRoot(NodeT *BB) { this->Roots.push_back(BB); }
void reset() {
@@ -835,7 +860,7 @@ public:
return IDom != nullptr;
}
- /// \brief Wipe this tree's state without releasing any resources.
+ /// Wipe this tree's state without releasing any resources.
///
/// This is essentially a post-move helper only. It leaves the object in an
/// assignable and destroyable state, but otherwise invalid.
diff --git a/include/llvm/Support/GenericDomTreeConstruction.h b/include/llvm/Support/GenericDomTreeConstruction.h
index 8f801662d0fb..103ff8ca476a 100644
--- a/include/llvm/Support/GenericDomTreeConstruction.h
+++ b/include/llvm/Support/GenericDomTreeConstruction.h
@@ -82,8 +82,8 @@ struct SemiNCAInfo {
// Note that these children are from the future relative to what the
// DominatorTree knows about -- using them to gets us some snapshot of the
// CFG from the past (relative to the state of the CFG).
- DenseMap<NodePtr, SmallDenseSet<NodePtrAndKind, 4>> FutureSuccessors;
- DenseMap<NodePtr, SmallDenseSet<NodePtrAndKind, 4>> FuturePredecessors;
+ DenseMap<NodePtr, SmallVector<NodePtrAndKind, 4>> FutureSuccessors;
+ DenseMap<NodePtr, SmallVector<NodePtrAndKind, 4>> FuturePredecessors;
// Remembers if the whole tree was recalculated at some point during the
// current batch update.
bool IsRecalculated = false;
@@ -146,15 +146,15 @@ struct SemiNCAInfo {
assert(llvm::find(Res, Child) != Res.end()
&& "Expected child not found in the CFG");
Res.erase(std::remove(Res.begin(), Res.end(), Child), Res.end());
- DEBUG(dbgs() << "\tHiding edge " << BlockNamePrinter(N) << " -> "
- << BlockNamePrinter(Child) << "\n");
+ LLVM_DEBUG(dbgs() << "\tHiding edge " << BlockNamePrinter(N) << " -> "
+ << BlockNamePrinter(Child) << "\n");
} else {
// If there's an deletion in the future, it means that the edge cannot
// exist in the current CFG, but existed in it before.
assert(llvm::find(Res, Child) == Res.end() &&
"Unexpected child found in the CFG");
- DEBUG(dbgs() << "\tShowing virtual edge " << BlockNamePrinter(N)
- << " -> " << BlockNamePrinter(Child) << "\n");
+ LLVM_DEBUG(dbgs() << "\tShowing virtual edge " << BlockNamePrinter(N)
+ << " -> " << BlockNamePrinter(Child) << "\n");
Res.push_back(Child);
}
}
@@ -387,7 +387,7 @@ struct SemiNCAInfo {
SNCA.addVirtualRoot();
unsigned Num = 1;
- DEBUG(dbgs() << "\t\tLooking for trivial roots\n");
+ LLVM_DEBUG(dbgs() << "\t\tLooking for trivial roots\n");
// Step #1: Find all the trivial roots that are going to will definitely
// remain tree roots.
@@ -404,14 +404,14 @@ struct SemiNCAInfo {
Roots.push_back(N);
// Run DFS not to walk this part of CFG later.
Num = SNCA.runDFS(N, Num, AlwaysDescend, 1);
- DEBUG(dbgs() << "Found a new trivial root: " << BlockNamePrinter(N)
- << "\n");
- DEBUG(dbgs() << "Last visited node: "
- << BlockNamePrinter(SNCA.NumToNode[Num]) << "\n");
+ LLVM_DEBUG(dbgs() << "Found a new trivial root: " << BlockNamePrinter(N)
+ << "\n");
+ LLVM_DEBUG(dbgs() << "Last visited node: "
+ << BlockNamePrinter(SNCA.NumToNode[Num]) << "\n");
}
}
- DEBUG(dbgs() << "\t\tLooking for non-trivial roots\n");
+ LLVM_DEBUG(dbgs() << "\t\tLooking for non-trivial roots\n");
// Step #2: Find all non-trivial root candidates. Those are CFG nodes that
// are reverse-unreachable were not visited by previous DFS walks (i.e. CFG
@@ -431,8 +431,8 @@ struct SemiNCAInfo {
SmallPtrSet<NodePtr, 4> ConnectToExitBlock;
for (const NodePtr I : nodes(DT.Parent)) {
if (SNCA.NodeToInfo.count(I) == 0) {
- DEBUG(dbgs() << "\t\t\tVisiting node " << BlockNamePrinter(I)
- << "\n");
+ LLVM_DEBUG(dbgs()
+ << "\t\t\tVisiting node " << BlockNamePrinter(I) << "\n");
// Find the furthest away we can get by following successors, then
// follow them in reverse. This gives us some reasonable answer about
// the post-dom tree inside any infinite loop. In particular, it
@@ -443,47 +443,49 @@ struct SemiNCAInfo {
// the lowest and highest points in the infinite loop. In theory, it
// would be nice to give the canonical backedge for the loop, but it's
// expensive and does not always lead to a minimal set of roots.
- DEBUG(dbgs() << "\t\t\tRunning forward DFS\n");
+ LLVM_DEBUG(dbgs() << "\t\t\tRunning forward DFS\n");
const unsigned NewNum = SNCA.runDFS<true>(I, Num, AlwaysDescend, Num);
const NodePtr FurthestAway = SNCA.NumToNode[NewNum];
- DEBUG(dbgs() << "\t\t\tFound a new furthest away node "
- << "(non-trivial root): "
- << BlockNamePrinter(FurthestAway) << "\n");
+ LLVM_DEBUG(dbgs() << "\t\t\tFound a new furthest away node "
+ << "(non-trivial root): "
+ << BlockNamePrinter(FurthestAway) << "\n");
ConnectToExitBlock.insert(FurthestAway);
Roots.push_back(FurthestAway);
- DEBUG(dbgs() << "\t\t\tPrev DFSNum: " << Num << ", new DFSNum: "
- << NewNum << "\n\t\t\tRemoving DFS info\n");
+ LLVM_DEBUG(dbgs() << "\t\t\tPrev DFSNum: " << Num << ", new DFSNum: "
+ << NewNum << "\n\t\t\tRemoving DFS info\n");
for (unsigned i = NewNum; i > Num; --i) {
const NodePtr N = SNCA.NumToNode[i];
- DEBUG(dbgs() << "\t\t\t\tRemoving DFS info for "
- << BlockNamePrinter(N) << "\n");
+ LLVM_DEBUG(dbgs() << "\t\t\t\tRemoving DFS info for "
+ << BlockNamePrinter(N) << "\n");
SNCA.NodeToInfo.erase(N);
SNCA.NumToNode.pop_back();
}
const unsigned PrevNum = Num;
- DEBUG(dbgs() << "\t\t\tRunning reverse DFS\n");
+ LLVM_DEBUG(dbgs() << "\t\t\tRunning reverse DFS\n");
Num = SNCA.runDFS(FurthestAway, Num, AlwaysDescend, 1);
for (unsigned i = PrevNum + 1; i <= Num; ++i)
- DEBUG(dbgs() << "\t\t\t\tfound node "
- << BlockNamePrinter(SNCA.NumToNode[i]) << "\n");
+ LLVM_DEBUG(dbgs() << "\t\t\t\tfound node "
+ << BlockNamePrinter(SNCA.NumToNode[i]) << "\n");
}
}
}
- DEBUG(dbgs() << "Total: " << Total << ", Num: " << Num << "\n");
- DEBUG(dbgs() << "Discovered CFG nodes:\n");
- DEBUG(for (size_t i = 0; i <= Num; ++i) dbgs()
- << i << ": " << BlockNamePrinter(SNCA.NumToNode[i]) << "\n");
+ LLVM_DEBUG(dbgs() << "Total: " << Total << ", Num: " << Num << "\n");
+ LLVM_DEBUG(dbgs() << "Discovered CFG nodes:\n");
+ LLVM_DEBUG(for (size_t i = 0; i <= Num; ++i) dbgs()
+ << i << ": " << BlockNamePrinter(SNCA.NumToNode[i]) << "\n");
assert((Total + 1 == Num) && "Everything should have been visited");
// Step #3: If we found some non-trivial roots, make them non-redundant.
if (HasNonTrivialRoots) RemoveRedundantRoots(DT, BUI, Roots);
- DEBUG(dbgs() << "Found roots: ");
- DEBUG(for (auto *Root : Roots) dbgs() << BlockNamePrinter(Root) << " ");
- DEBUG(dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << "Found roots: ");
+ LLVM_DEBUG(for (auto *Root
+ : Roots) dbgs()
+ << BlockNamePrinter(Root) << " ");
+ LLVM_DEBUG(dbgs() << "\n");
return Roots;
}
@@ -499,7 +501,7 @@ struct SemiNCAInfo {
static void RemoveRedundantRoots(const DomTreeT &DT, BatchUpdatePtr BUI,
RootsT &Roots) {
assert(IsPostDom && "This function is for postdominators only");
- DEBUG(dbgs() << "Removing redundant roots\n");
+ LLVM_DEBUG(dbgs() << "Removing redundant roots\n");
SemiNCAInfo SNCA(BUI);
@@ -507,8 +509,8 @@ struct SemiNCAInfo {
auto &Root = Roots[i];
// Trivial roots are always non-redundant.
if (!HasForwardSuccessors(Root, BUI)) continue;
- DEBUG(dbgs() << "\tChecking if " << BlockNamePrinter(Root)
- << " remains a root\n");
+ LLVM_DEBUG(dbgs() << "\tChecking if " << BlockNamePrinter(Root)
+ << " remains a root\n");
SNCA.clear();
// Do a forward walk looking for the other roots.
const unsigned Num = SNCA.runDFS<true>(Root, 0, AlwaysDescend, 0);
@@ -520,9 +522,9 @@ struct SemiNCAInfo {
// root from the set of roots, as it is reverse-reachable from the other
// one.
if (llvm::find(Roots, N) != Roots.end()) {
- DEBUG(dbgs() << "\tForward DFS walk found another root "
- << BlockNamePrinter(N) << "\n\tRemoving root "
- << BlockNamePrinter(Root) << "\n");
+ LLVM_DEBUG(dbgs() << "\tForward DFS walk found another root "
+ << BlockNamePrinter(N) << "\n\tRemoving root "
+ << BlockNamePrinter(Root) << "\n");
std::swap(Root, Roots.back());
Roots.pop_back();
@@ -563,7 +565,8 @@ struct SemiNCAInfo {
SNCA.runSemiNCA(DT);
if (BUI) {
BUI->IsRecalculated = true;
- DEBUG(dbgs() << "DomTree recalculated, skipping future batch updates\n");
+ LLVM_DEBUG(
+ dbgs() << "DomTree recalculated, skipping future batch updates\n");
}
if (DT.Roots.empty()) return;
@@ -585,8 +588,8 @@ struct SemiNCAInfo {
// Loop over all of the discovered blocks in the function...
for (size_t i = 1, e = NumToNode.size(); i != e; ++i) {
NodePtr W = NumToNode[i];
- DEBUG(dbgs() << "\tdiscovered a new reachable node "
- << BlockNamePrinter(W) << "\n");
+ LLVM_DEBUG(dbgs() << "\tdiscovered a new reachable node "
+ << BlockNamePrinter(W) << "\n");
// Don't replace this with 'count', the insertion side effect is important
if (DT.DomTreeNodes[W]) continue; // Haven't calculated this node yet?
@@ -628,7 +631,7 @@ struct SemiNCAInfo {
DecreasingLevel>
Bucket; // Queue of tree nodes sorted by level in descending order.
SmallDenseSet<TreeNodePtr, 8> Affected;
- SmallDenseSet<TreeNodePtr, 8> Visited;
+ SmallDenseMap<TreeNodePtr, unsigned, 8> Visited;
SmallVector<TreeNodePtr, 8> AffectedQueue;
SmallVector<TreeNodePtr, 8> VisitedNotAffectedQueue;
};
@@ -638,8 +641,8 @@ struct SemiNCAInfo {
assert((From || IsPostDom) &&
"From has to be a valid CFG node or a virtual root");
assert(To && "Cannot be a nullptr");
- DEBUG(dbgs() << "Inserting edge " << BlockNamePrinter(From) << " -> "
- << BlockNamePrinter(To) << "\n");
+ LLVM_DEBUG(dbgs() << "Inserting edge " << BlockNamePrinter(From) << " -> "
+ << BlockNamePrinter(To) << "\n");
TreeNodePtr FromTN = DT.getNode(From);
if (!FromTN) {
@@ -678,8 +681,8 @@ struct SemiNCAInfo {
if (RIt == DT.Roots.end())
return false; // To is not a root, nothing to update.
- DEBUG(dbgs() << "\t\tAfter the insertion, " << BlockNamePrinter(To)
- << " is no longer a root\n\t\tRebuilding the tree!!!\n");
+ LLVM_DEBUG(dbgs() << "\t\tAfter the insertion, " << BlockNamePrinter(To)
+ << " is no longer a root\n\t\tRebuilding the tree!!!\n");
CalculateFromScratch(DT, BUI);
return true;
@@ -698,32 +701,28 @@ struct SemiNCAInfo {
return;
// Recalculate the set of roots.
- DT.Roots = FindRoots(DT, BUI);
- for (const NodePtr R : DT.Roots) {
- const TreeNodePtr TN = DT.getNode(R);
- // A CFG node was selected as a tree root, but the corresponding tree node
- // is not connected to the virtual root. This is because the incremental
- // algorithm does not really know or use the set of roots and can make a
- // different (implicit) decision about which nodes within an infinite loop
- // becomes a root.
- if (DT.isVirtualRoot(TN->getIDom())) {
- DEBUG(dbgs() << "Root " << BlockNamePrinter(R)
- << " is not virtual root's child\n"
- << "The entire tree needs to be rebuilt\n");
- // It should be possible to rotate the subtree instead of recalculating
- // the whole tree, but this situation happens extremely rarely in
- // practice.
- CalculateFromScratch(DT, BUI);
- return;
- }
+ auto Roots = FindRoots(DT, BUI);
+ if (DT.Roots.size() != Roots.size() ||
+ !std::is_permutation(DT.Roots.begin(), DT.Roots.end(), Roots.begin())) {
+ // The roots chosen in the CFG have changed. This is because the
+ // incremental algorithm does not really know or use the set of roots and
+ // can make a different (implicit) decision about which node within an
+ // infinite loop becomes a root.
+
+ LLVM_DEBUG(dbgs() << "Roots are different in updated trees\n"
+ << "The entire tree needs to be rebuilt\n");
+ // It may be possible to update the tree without recalculating it, but
+ // we do not know yet how to do it, and it happens rarely in practise.
+ CalculateFromScratch(DT, BUI);
+ return;
}
}
// Handles insertion to a node already in the dominator tree.
static void InsertReachable(DomTreeT &DT, const BatchUpdatePtr BUI,
const TreeNodePtr From, const TreeNodePtr To) {
- DEBUG(dbgs() << "\tReachable " << BlockNamePrinter(From->getBlock())
- << " -> " << BlockNamePrinter(To->getBlock()) << "\n");
+ LLVM_DEBUG(dbgs() << "\tReachable " << BlockNamePrinter(From->getBlock())
+ << " -> " << BlockNamePrinter(To->getBlock()) << "\n");
if (IsPostDom && UpdateRootsBeforeInsertion(DT, BUI, From, To)) return;
// DT.findNCD expects both pointers to be valid. When From is a virtual
// root, then its CFG block pointer is a nullptr, so we have to 'compute'
@@ -736,7 +735,7 @@ struct SemiNCAInfo {
const TreeNodePtr NCD = DT.getNode(NCDBlock);
assert(NCD);
- DEBUG(dbgs() << "\t\tNCA == " << BlockNamePrinter(NCD) << "\n");
+ LLVM_DEBUG(dbgs() << "\t\tNCA == " << BlockNamePrinter(NCD) << "\n");
const TreeNodePtr ToIDom = To->getIDom();
// Nothing affected -- NCA property holds.
@@ -745,22 +744,26 @@ struct SemiNCAInfo {
// Identify and collect affected nodes.
InsertionInfo II;
- DEBUG(dbgs() << "Marking " << BlockNamePrinter(To) << " as affected\n");
+ LLVM_DEBUG(dbgs() << "Marking " << BlockNamePrinter(To)
+ << " as affected\n");
II.Affected.insert(To);
const unsigned ToLevel = To->getLevel();
- DEBUG(dbgs() << "Putting " << BlockNamePrinter(To) << " into a Bucket\n");
+ LLVM_DEBUG(dbgs() << "Putting " << BlockNamePrinter(To)
+ << " into a Bucket\n");
II.Bucket.push({ToLevel, To});
while (!II.Bucket.empty()) {
const TreeNodePtr CurrentNode = II.Bucket.top().second;
+ const unsigned CurrentLevel = CurrentNode->getLevel();
II.Bucket.pop();
- DEBUG(dbgs() << "\tAdding to Visited and AffectedQueue: "
- << BlockNamePrinter(CurrentNode) << "\n");
- II.Visited.insert(CurrentNode);
+ LLVM_DEBUG(dbgs() << "\tAdding to Visited and AffectedQueue: "
+ << BlockNamePrinter(CurrentNode) << "\n");
+
+ II.Visited.insert({CurrentNode, CurrentLevel});
II.AffectedQueue.push_back(CurrentNode);
// Discover and collect affected successors of the current node.
- VisitInsertion(DT, BUI, CurrentNode, CurrentNode->getLevel(), NCD, II);
+ VisitInsertion(DT, BUI, CurrentNode, CurrentLevel, NCD, II);
}
// Finish by updating immediate dominators and levels.
@@ -772,13 +775,17 @@ struct SemiNCAInfo {
const TreeNodePtr TN, const unsigned RootLevel,
const TreeNodePtr NCD, InsertionInfo &II) {
const unsigned NCDLevel = NCD->getLevel();
- DEBUG(dbgs() << "Visiting " << BlockNamePrinter(TN) << "\n");
+ LLVM_DEBUG(dbgs() << "Visiting " << BlockNamePrinter(TN) << ", RootLevel "
+ << RootLevel << "\n");
SmallVector<TreeNodePtr, 8> Stack = {TN};
assert(TN->getBlock() && II.Visited.count(TN) && "Preconditions!");
+ SmallPtrSet<TreeNodePtr, 8> Processed;
+
do {
TreeNodePtr Next = Stack.pop_back_val();
+ LLVM_DEBUG(dbgs() << " Next: " << BlockNamePrinter(Next) << "\n");
for (const NodePtr Succ :
ChildrenGetter<IsPostDom>::Get(Next->getBlock(), BUI)) {
@@ -786,40 +793,54 @@ struct SemiNCAInfo {
assert(SuccTN && "Unreachable successor found at reachable insertion");
const unsigned SuccLevel = SuccTN->getLevel();
- DEBUG(dbgs() << "\tSuccessor " << BlockNamePrinter(Succ)
- << ", level = " << SuccLevel << "\n");
+ LLVM_DEBUG(dbgs() << "\tSuccessor " << BlockNamePrinter(Succ)
+ << ", level = " << SuccLevel << "\n");
+
+ // Do not process the same node multiple times.
+ if (Processed.count(Next) > 0)
+ continue;
// Succ dominated by subtree From -- not affected.
// (Based on the lemma 2.5 from the second paper.)
if (SuccLevel > RootLevel) {
- DEBUG(dbgs() << "\t\tDominated by subtree From\n");
- if (II.Visited.count(SuccTN) != 0)
- continue;
+ LLVM_DEBUG(dbgs() << "\t\tDominated by subtree From\n");
+ if (II.Visited.count(SuccTN) != 0) {
+ LLVM_DEBUG(dbgs() << "\t\t\talready visited at level "
+ << II.Visited[SuccTN] << "\n\t\t\tcurrent level "
+ << RootLevel << ")\n");
+
+ // A node can be necessary to visit again if we see it again at
+ // a lower level than before.
+ if (II.Visited[SuccTN] >= RootLevel)
+ continue;
+ }
- DEBUG(dbgs() << "\t\tMarking visited not affected "
- << BlockNamePrinter(Succ) << "\n");
- II.Visited.insert(SuccTN);
+ LLVM_DEBUG(dbgs() << "\t\tMarking visited not affected "
+ << BlockNamePrinter(Succ) << "\n");
+ II.Visited.insert({SuccTN, RootLevel});
II.VisitedNotAffectedQueue.push_back(SuccTN);
Stack.push_back(SuccTN);
} else if ((SuccLevel > NCDLevel + 1) &&
II.Affected.count(SuccTN) == 0) {
- DEBUG(dbgs() << "\t\tMarking affected and adding "
- << BlockNamePrinter(Succ) << " to a Bucket\n");
+ LLVM_DEBUG(dbgs() << "\t\tMarking affected and adding "
+ << BlockNamePrinter(Succ) << " to a Bucket\n");
II.Affected.insert(SuccTN);
II.Bucket.push({SuccLevel, SuccTN});
}
}
+
+ Processed.insert(Next);
} while (!Stack.empty());
}
// Updates immediate dominators and levels after insertion.
static void UpdateInsertion(DomTreeT &DT, const BatchUpdatePtr BUI,
const TreeNodePtr NCD, InsertionInfo &II) {
- DEBUG(dbgs() << "Updating NCD = " << BlockNamePrinter(NCD) << "\n");
+ LLVM_DEBUG(dbgs() << "Updating NCD = " << BlockNamePrinter(NCD) << "\n");
for (const TreeNodePtr TN : II.AffectedQueue) {
- DEBUG(dbgs() << "\tIDom(" << BlockNamePrinter(TN)
- << ") = " << BlockNamePrinter(NCD) << "\n");
+ LLVM_DEBUG(dbgs() << "\tIDom(" << BlockNamePrinter(TN)
+ << ") = " << BlockNamePrinter(NCD) << "\n");
TN->setIDom(NCD);
}
@@ -828,12 +849,13 @@ struct SemiNCAInfo {
}
static void UpdateLevelsAfterInsertion(InsertionInfo &II) {
- DEBUG(dbgs() << "Updating levels for visited but not affected nodes\n");
+ LLVM_DEBUG(
+ dbgs() << "Updating levels for visited but not affected nodes\n");
for (const TreeNodePtr TN : II.VisitedNotAffectedQueue) {
- DEBUG(dbgs() << "\tlevel(" << BlockNamePrinter(TN) << ") = ("
- << BlockNamePrinter(TN->getIDom()) << ") "
- << TN->getIDom()->getLevel() << " + 1\n");
+ LLVM_DEBUG(dbgs() << "\tlevel(" << BlockNamePrinter(TN) << ") = ("
+ << BlockNamePrinter(TN->getIDom()) << ") "
+ << TN->getIDom()->getLevel() << " + 1\n");
TN->UpdateLevel();
}
}
@@ -841,23 +863,24 @@ struct SemiNCAInfo {
// Handles insertion to previously unreachable nodes.
static void InsertUnreachable(DomTreeT &DT, const BatchUpdatePtr BUI,
const TreeNodePtr From, const NodePtr To) {
- DEBUG(dbgs() << "Inserting " << BlockNamePrinter(From)
- << " -> (unreachable) " << BlockNamePrinter(To) << "\n");
+ LLVM_DEBUG(dbgs() << "Inserting " << BlockNamePrinter(From)
+ << " -> (unreachable) " << BlockNamePrinter(To) << "\n");
// Collect discovered edges to already reachable nodes.
SmallVector<std::pair<NodePtr, TreeNodePtr>, 8> DiscoveredEdgesToReachable;
// Discover and connect nodes that became reachable with the insertion.
ComputeUnreachableDominators(DT, BUI, To, From, DiscoveredEdgesToReachable);
- DEBUG(dbgs() << "Inserted " << BlockNamePrinter(From)
- << " -> (prev unreachable) " << BlockNamePrinter(To) << "\n");
+ LLVM_DEBUG(dbgs() << "Inserted " << BlockNamePrinter(From)
+ << " -> (prev unreachable) " << BlockNamePrinter(To)
+ << "\n");
// Used the discovered edges and inset discovered connecting (incoming)
// edges.
for (const auto &Edge : DiscoveredEdgesToReachable) {
- DEBUG(dbgs() << "\tInserting discovered connecting edge "
- << BlockNamePrinter(Edge.first) << " -> "
- << BlockNamePrinter(Edge.second) << "\n");
+ LLVM_DEBUG(dbgs() << "\tInserting discovered connecting edge "
+ << BlockNamePrinter(Edge.first) << " -> "
+ << BlockNamePrinter(Edge.second) << "\n");
InsertReachable(DT, BUI, DT.getNode(Edge.first), Edge.second);
}
}
@@ -885,14 +908,14 @@ struct SemiNCAInfo {
SNCA.runSemiNCA(DT);
SNCA.attachNewSubtree(DT, Incoming);
- DEBUG(dbgs() << "After adding unreachable nodes\n");
+ LLVM_DEBUG(dbgs() << "After adding unreachable nodes\n");
}
static void DeleteEdge(DomTreeT &DT, const BatchUpdatePtr BUI,
const NodePtr From, const NodePtr To) {
assert(From && To && "Cannot disconnect nullptrs");
- DEBUG(dbgs() << "Deleting edge " << BlockNamePrinter(From) << " -> "
- << BlockNamePrinter(To) << "\n");
+ LLVM_DEBUG(dbgs() << "Deleting edge " << BlockNamePrinter(From) << " -> "
+ << BlockNamePrinter(To) << "\n");
#ifndef NDEBUG
// Ensure that the edge was in fact deleted from the CFG before informing
@@ -912,29 +935,30 @@ struct SemiNCAInfo {
const TreeNodePtr ToTN = DT.getNode(To);
if (!ToTN) {
- DEBUG(dbgs() << "\tTo (" << BlockNamePrinter(To)
- << ") already unreachable -- there is no edge to delete\n");
+ LLVM_DEBUG(
+ dbgs() << "\tTo (" << BlockNamePrinter(To)
+ << ") already unreachable -- there is no edge to delete\n");
return;
}
const NodePtr NCDBlock = DT.findNearestCommonDominator(From, To);
const TreeNodePtr NCD = DT.getNode(NCDBlock);
- // To dominates From -- nothing to do.
- if (ToTN == NCD) return;
-
- DT.DFSInfoValid = false;
+ // If To dominates From -- nothing to do.
+ if (ToTN != NCD) {
+ DT.DFSInfoValid = false;
- const TreeNodePtr ToIDom = ToTN->getIDom();
- DEBUG(dbgs() << "\tNCD " << BlockNamePrinter(NCD) << ", ToIDom "
- << BlockNamePrinter(ToIDom) << "\n");
+ const TreeNodePtr ToIDom = ToTN->getIDom();
+ LLVM_DEBUG(dbgs() << "\tNCD " << BlockNamePrinter(NCD) << ", ToIDom "
+ << BlockNamePrinter(ToIDom) << "\n");
- // To remains reachable after deletion.
- // (Based on the caption under Figure 4. from the second paper.)
- if (FromTN != ToIDom || HasProperSupport(DT, BUI, ToTN))
- DeleteReachable(DT, BUI, FromTN, ToTN);
- else
- DeleteUnreachable(DT, BUI, ToTN);
+ // To remains reachable after deletion.
+ // (Based on the caption under Figure 4. from the second paper.)
+ if (FromTN != ToIDom || HasProperSupport(DT, BUI, ToTN))
+ DeleteReachable(DT, BUI, FromTN, ToTN);
+ else
+ DeleteUnreachable(DT, BUI, ToTN);
+ }
if (IsPostDom) UpdateRootsAfterUpdate(DT, BUI);
}
@@ -943,9 +967,9 @@ struct SemiNCAInfo {
static void DeleteReachable(DomTreeT &DT, const BatchUpdatePtr BUI,
const TreeNodePtr FromTN,
const TreeNodePtr ToTN) {
- DEBUG(dbgs() << "Deleting reachable " << BlockNamePrinter(FromTN) << " -> "
- << BlockNamePrinter(ToTN) << "\n");
- DEBUG(dbgs() << "\tRebuilding subtree\n");
+ LLVM_DEBUG(dbgs() << "Deleting reachable " << BlockNamePrinter(FromTN)
+ << " -> " << BlockNamePrinter(ToTN) << "\n");
+ LLVM_DEBUG(dbgs() << "\tRebuilding subtree\n");
// Find the top of the subtree that needs to be rebuilt.
// (Based on the lemma 2.6 from the second paper.)
@@ -958,7 +982,7 @@ struct SemiNCAInfo {
// Top of the subtree to rebuild is the root node. Rebuild the tree from
// scratch.
if (!PrevIDomSubTree) {
- DEBUG(dbgs() << "The entire tree needs to be rebuilt\n");
+ LLVM_DEBUG(dbgs() << "The entire tree needs to be rebuilt\n");
CalculateFromScratch(DT, BUI);
return;
}
@@ -969,11 +993,12 @@ struct SemiNCAInfo {
return DT.getNode(To)->getLevel() > Level;
};
- DEBUG(dbgs() << "\tTop of subtree: " << BlockNamePrinter(ToIDomTN) << "\n");
+ LLVM_DEBUG(dbgs() << "\tTop of subtree: " << BlockNamePrinter(ToIDomTN)
+ << "\n");
SemiNCAInfo SNCA(BUI);
SNCA.runDFS(ToIDom, 0, DescendBelow, 0);
- DEBUG(dbgs() << "\tRunning Semi-NCA\n");
+ LLVM_DEBUG(dbgs() << "\tRunning Semi-NCA\n");
SNCA.runSemiNCA(DT, Level);
SNCA.reattachExistingSubtree(DT, PrevIDomSubTree);
}
@@ -982,19 +1007,20 @@ struct SemiNCAInfo {
// explained on the page 7 of the second paper.
static bool HasProperSupport(DomTreeT &DT, const BatchUpdatePtr BUI,
const TreeNodePtr TN) {
- DEBUG(dbgs() << "IsReachableFromIDom " << BlockNamePrinter(TN) << "\n");
+ LLVM_DEBUG(dbgs() << "IsReachableFromIDom " << BlockNamePrinter(TN)
+ << "\n");
for (const NodePtr Pred :
ChildrenGetter<!IsPostDom>::Get(TN->getBlock(), BUI)) {
- DEBUG(dbgs() << "\tPred " << BlockNamePrinter(Pred) << "\n");
+ LLVM_DEBUG(dbgs() << "\tPred " << BlockNamePrinter(Pred) << "\n");
if (!DT.getNode(Pred)) continue;
const NodePtr Support =
DT.findNearestCommonDominator(TN->getBlock(), Pred);
- DEBUG(dbgs() << "\tSupport " << BlockNamePrinter(Support) << "\n");
+ LLVM_DEBUG(dbgs() << "\tSupport " << BlockNamePrinter(Support) << "\n");
if (Support != TN->getBlock()) {
- DEBUG(dbgs() << "\t" << BlockNamePrinter(TN)
- << " is reachable from support "
- << BlockNamePrinter(Support) << "\n");
+ LLVM_DEBUG(dbgs() << "\t" << BlockNamePrinter(TN)
+ << " is reachable from support "
+ << BlockNamePrinter(Support) << "\n");
return true;
}
}
@@ -1006,8 +1032,8 @@ struct SemiNCAInfo {
// (Based on the lemma 2.7 from the second paper.)
static void DeleteUnreachable(DomTreeT &DT, const BatchUpdatePtr BUI,
const TreeNodePtr ToTN) {
- DEBUG(dbgs() << "Deleting unreachable subtree " << BlockNamePrinter(ToTN)
- << "\n");
+ LLVM_DEBUG(dbgs() << "Deleting unreachable subtree "
+ << BlockNamePrinter(ToTN) << "\n");
assert(ToTN);
assert(ToTN->getBlock());
@@ -1015,8 +1041,9 @@ struct SemiNCAInfo {
// Deletion makes a region reverse-unreachable and creates a new root.
// Simulate that by inserting an edge from the virtual root to ToTN and
// adding it as a new root.
- DEBUG(dbgs() << "\tDeletion made a region reverse-unreachable\n");
- DEBUG(dbgs() << "\tAdding new root " << BlockNamePrinter(ToTN) << "\n");
+ LLVM_DEBUG(dbgs() << "\tDeletion made a region reverse-unreachable\n");
+ LLVM_DEBUG(dbgs() << "\tAdding new root " << BlockNamePrinter(ToTN)
+ << "\n");
DT.Roots.push_back(ToTN->getBlock());
InsertReachable(DT, BUI, DT.getNode(nullptr), ToTN);
return;
@@ -1053,15 +1080,15 @@ struct SemiNCAInfo {
const TreeNodePtr NCD = DT.getNode(NCDBlock);
assert(NCD);
- DEBUG(dbgs() << "Processing affected node " << BlockNamePrinter(TN)
- << " with NCD = " << BlockNamePrinter(NCD)
- << ", MinNode =" << BlockNamePrinter(MinNode) << "\n");
+ LLVM_DEBUG(dbgs() << "Processing affected node " << BlockNamePrinter(TN)
+ << " with NCD = " << BlockNamePrinter(NCD)
+ << ", MinNode =" << BlockNamePrinter(MinNode) << "\n");
if (NCD != TN && NCD->getLevel() < MinNode->getLevel()) MinNode = NCD;
}
// Root reached, rebuild the whole tree from scratch.
if (!MinNode->getIDom()) {
- DEBUG(dbgs() << "The entire tree needs to be rebuilt\n");
+ LLVM_DEBUG(dbgs() << "The entire tree needs to be rebuilt\n");
CalculateFromScratch(DT, BUI);
return;
}
@@ -1071,7 +1098,7 @@ struct SemiNCAInfo {
for (unsigned i = LastDFSNum; i > 0; --i) {
const NodePtr N = SNCA.NumToNode[i];
const TreeNodePtr TN = DT.getNode(N);
- DEBUG(dbgs() << "Erasing node " << BlockNamePrinter(TN) << "\n");
+ LLVM_DEBUG(dbgs() << "Erasing node " << BlockNamePrinter(TN) << "\n");
EraseNode(DT, TN);
}
@@ -1079,8 +1106,8 @@ struct SemiNCAInfo {
// The affected subtree start at the To node -- there's no extra work to do.
if (MinNode == ToTN) return;
- DEBUG(dbgs() << "DeleteUnreachable: running DFS with MinNode = "
- << BlockNamePrinter(MinNode) << "\n");
+ LLVM_DEBUG(dbgs() << "DeleteUnreachable: running DFS with MinNode = "
+ << BlockNamePrinter(MinNode) << "\n");
const unsigned MinLevel = MinNode->getLevel();
const TreeNodePtr PrevIDom = MinNode->getIDom();
assert(PrevIDom);
@@ -1093,8 +1120,8 @@ struct SemiNCAInfo {
};
SNCA.runDFS(MinNode->getBlock(), 0, DescendBelow, 0);
- DEBUG(dbgs() << "Previous IDom(MinNode) = " << BlockNamePrinter(PrevIDom)
- << "\nRunning Semi-NCA\n");
+ LLVM_DEBUG(dbgs() << "Previous IDom(MinNode) = "
+ << BlockNamePrinter(PrevIDom) << "\nRunning Semi-NCA\n");
// Rebuild the remaining part of affected subtree.
SNCA.runSemiNCA(DT, MinLevel);
@@ -1149,15 +1176,15 @@ struct SemiNCAInfo {
// predecessors. Note that these sets will only decrease size over time, as
// the next CFG snapshots slowly approach the actual (current) CFG.
for (UpdateT &U : BUI.Updates) {
- BUI.FutureSuccessors[U.getFrom()].insert({U.getTo(), U.getKind()});
- BUI.FuturePredecessors[U.getTo()].insert({U.getFrom(), U.getKind()});
+ BUI.FutureSuccessors[U.getFrom()].push_back({U.getTo(), U.getKind()});
+ BUI.FuturePredecessors[U.getTo()].push_back({U.getFrom(), U.getKind()});
}
- DEBUG(dbgs() << "About to apply " << NumLegalized << " updates\n");
- DEBUG(if (NumLegalized < 32) for (const auto &U
- : reverse(BUI.Updates)) dbgs()
- << '\t' << U << "\n");
- DEBUG(dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << "About to apply " << NumLegalized << " updates\n");
+ LLVM_DEBUG(if (NumLegalized < 32) for (const auto &U
+ : reverse(BUI.Updates)) dbgs()
+ << '\t' << U << "\n");
+ LLVM_DEBUG(dbgs() << "\n");
// If the DominatorTree was recalculated at some point, stop the batch
// updates. Full recalculations ignore batch updates and look at the actual
@@ -1185,7 +1212,7 @@ struct SemiNCAInfo {
// minimizes the amount of work needed done during incremental updates.
static void LegalizeUpdates(ArrayRef<UpdateT> AllUpdates,
SmallVectorImpl<UpdateT> &Result) {
- DEBUG(dbgs() << "Legalizing " << AllUpdates.size() << " updates\n");
+ LLVM_DEBUG(dbgs() << "Legalizing " << AllUpdates.size() << " updates\n");
// Count the total number of inserions of each edge.
// Each insertion adds 1 and deletion subtracts 1. The end number should be
// one of {-1 (deletion), 0 (NOP), +1 (insertion)}. Otherwise, the sequence
@@ -1225,26 +1252,31 @@ struct SemiNCAInfo {
Operations[{U.getTo(), U.getFrom()}] = int(i);
}
- std::sort(Result.begin(), Result.end(),
- [&Operations](const UpdateT &A, const UpdateT &B) {
- return Operations[{A.getFrom(), A.getTo()}] >
- Operations[{B.getFrom(), B.getTo()}];
- });
+ llvm::sort(Result.begin(), Result.end(),
+ [&Operations](const UpdateT &A, const UpdateT &B) {
+ return Operations[{A.getFrom(), A.getTo()}] >
+ Operations[{B.getFrom(), B.getTo()}];
+ });
}
static void ApplyNextUpdate(DomTreeT &DT, BatchUpdateInfo &BUI) {
assert(!BUI.Updates.empty() && "No updates to apply!");
UpdateT CurrentUpdate = BUI.Updates.pop_back_val();
- DEBUG(dbgs() << "Applying update: " << CurrentUpdate << "\n");
+ LLVM_DEBUG(dbgs() << "Applying update: " << CurrentUpdate << "\n");
// Move to the next snapshot of the CFG by removing the reverse-applied
- // current update.
+ // current update. Since updates are performed in the same order they are
+ // legalized it's sufficient to pop the last item here.
auto &FS = BUI.FutureSuccessors[CurrentUpdate.getFrom()];
- FS.erase({CurrentUpdate.getTo(), CurrentUpdate.getKind()});
+ assert(FS.back().getPointer() == CurrentUpdate.getTo() &&
+ FS.back().getInt() == CurrentUpdate.getKind());
+ FS.pop_back();
if (FS.empty()) BUI.FutureSuccessors.erase(CurrentUpdate.getFrom());
auto &FP = BUI.FuturePredecessors[CurrentUpdate.getTo()];
- FP.erase({CurrentUpdate.getFrom(), CurrentUpdate.getKind()});
+ assert(FP.back().getPointer() == CurrentUpdate.getFrom() &&
+ FP.back().getInt() == CurrentUpdate.getKind());
+ FP.pop_back();
if (FP.empty()) BUI.FuturePredecessors.erase(CurrentUpdate.getTo());
if (CurrentUpdate.getKind() == UpdateKind::Insert)
@@ -1261,6 +1293,7 @@ struct SemiNCAInfo {
// root which is the function's entry node. A PostDominatorTree can have
// multiple roots - one for each node with no successors and for infinite
// loops.
+ // Running time: O(N).
bool verifyRoots(const DomTreeT &DT) {
if (!DT.Parent && !DT.Roots.empty()) {
errs() << "Tree has no parent but has roots!\n";
@@ -1301,6 +1334,7 @@ struct SemiNCAInfo {
}
// Checks if the tree contains all reachable nodes in the input graph.
+ // Running time: O(N).
bool verifyReachability(const DomTreeT &DT) {
clear();
doFullDFSWalk(DT, AlwaysDescend);
@@ -1336,6 +1370,7 @@ struct SemiNCAInfo {
// Check if for every parent with a level L in the tree all of its children
// have level L + 1.
+ // Running time: O(N).
static bool VerifyLevels(const DomTreeT &DT) {
for (auto &NodeToTN : DT.DomTreeNodes) {
const TreeNodePtr TN = NodeToTN.second.get();
@@ -1367,6 +1402,7 @@ struct SemiNCAInfo {
// Check if the computed DFS numbers are correct. Note that DFS info may not
// be valid, and when that is the case, we don't verify the numbers.
+ // Running time: O(N log(N)).
static bool VerifyDFSNumbers(const DomTreeT &DT) {
if (!DT.DFSInfoValid || !DT.Parent)
return true;
@@ -1410,10 +1446,10 @@ struct SemiNCAInfo {
// Make a copy and sort it such that it is possible to check if there are
// no gaps between DFS numbers of adjacent children.
SmallVector<TreeNodePtr, 8> Children(Node->begin(), Node->end());
- std::sort(Children.begin(), Children.end(),
- [](const TreeNodePtr Ch1, const TreeNodePtr Ch2) {
- return Ch1->getDFSNumIn() < Ch2->getDFSNumIn();
- });
+ llvm::sort(Children.begin(), Children.end(),
+ [](const TreeNodePtr Ch1, const TreeNodePtr Ch2) {
+ return Ch1->getDFSNumIn() < Ch2->getDFSNumIn();
+ });
auto PrintChildrenError = [Node, &Children, PrintNodeAndDFSNums](
const TreeNodePtr FirstCh, const TreeNodePtr SecondCh) {
@@ -1497,10 +1533,10 @@ struct SemiNCAInfo {
// linear time, but the algorithms are complex. Instead, we do it in a
// straightforward N^2 and N^3 way below, using direct path reachability.
-
// Checks if the tree has the parent property: if for all edges from V to W in
// the input graph, such that V is reachable, the parent of W in the tree is
// an ancestor of V in the tree.
+ // Running time: O(N^2).
//
// This means that if a node gets disconnected from the graph, then all of
// the nodes it dominated previously will now become unreachable.
@@ -1510,8 +1546,8 @@ struct SemiNCAInfo {
const NodePtr BB = TN->getBlock();
if (!BB || TN->getChildren().empty()) continue;
- DEBUG(dbgs() << "Verifying parent property of node "
- << BlockNamePrinter(TN) << "\n");
+ LLVM_DEBUG(dbgs() << "Verifying parent property of node "
+ << BlockNamePrinter(TN) << "\n");
clear();
doFullDFSWalk(DT, [BB](NodePtr From, NodePtr To) {
return From != BB && To != BB;
@@ -1533,6 +1569,7 @@ struct SemiNCAInfo {
// Check if the tree has sibling property: if a node V does not dominate a
// node W for all siblings V and W in the tree.
+ // Running time: O(N^3).
//
// This means that if a node gets disconnected from the graph, then all of its
// siblings will now still be reachable.
@@ -1567,6 +1604,31 @@ struct SemiNCAInfo {
return true;
}
+
+ // Check if the given tree is the same as a freshly computed one for the same
+ // Parent.
+ // Running time: O(N^2), but faster in practise (same as tree construction).
+ //
+ // Note that this does not check if that the tree construction algorithm is
+ // correct and should be only used for fast (but possibly unsound)
+ // verification.
+ static bool IsSameAsFreshTree(const DomTreeT &DT) {
+ DomTreeT FreshTree;
+ FreshTree.recalculate(*DT.Parent);
+ const bool Different = DT.compare(FreshTree);
+
+ if (Different) {
+ errs() << (DT.isPostDominator() ? "Post" : "")
+ << "DominatorTree is different than a freshly computed one!\n"
+ << "\tCurrent:\n";
+ DT.print(errs());
+ errs() << "\n\tFreshly computed tree:\n";
+ FreshTree.print(errs());
+ errs().flush();
+ }
+
+ return !Different;
+ }
};
template <class DomTreeT>
@@ -1595,11 +1657,29 @@ void ApplyUpdates(DomTreeT &DT,
}
template <class DomTreeT>
-bool Verify(const DomTreeT &DT) {
+bool Verify(const DomTreeT &DT, typename DomTreeT::VerificationLevel VL) {
SemiNCAInfo<DomTreeT> SNCA(nullptr);
- return SNCA.verifyRoots(DT) && SNCA.verifyReachability(DT) &&
- SNCA.VerifyLevels(DT) && SNCA.verifyParentProperty(DT) &&
- SNCA.verifySiblingProperty(DT) && SNCA.VerifyDFSNumbers(DT);
+
+ // Simplist check is to compare against a new tree. This will also
+ // usefully print the old and new trees, if they are different.
+ if (!SNCA.IsSameAsFreshTree(DT))
+ return false;
+
+ // Common checks to verify the properties of the tree. O(N log N) at worst
+ if (!SNCA.verifyRoots(DT) || !SNCA.verifyReachability(DT) ||
+ !SNCA.VerifyLevels(DT) || !SNCA.VerifyDFSNumbers(DT))
+ return false;
+
+ // Extra checks depending on VerificationLevel. Up to O(N^3)
+ if (VL == DomTreeT::VerificationLevel::Basic ||
+ VL == DomTreeT::VerificationLevel::Full)
+ if (!SNCA.verifyParentProperty(DT))
+ return false;
+ if (VL == DomTreeT::VerificationLevel::Full)
+ if (!SNCA.verifySiblingProperty(DT))
+ return false;
+
+ return true;
}
} // namespace DomTreeBuilder
diff --git a/include/llvm/Support/GraphWriter.h b/include/llvm/Support/GraphWriter.h
index 3df5c867f7d3..c9a9f409c522 100644
--- a/include/llvm/Support/GraphWriter.h
+++ b/include/llvm/Support/GraphWriter.h
@@ -41,7 +41,7 @@ namespace DOT { // Private functions...
std::string EscapeString(const std::string &Label);
-/// \brief Get a color string for this node number. Simply round-robin selects
+/// Get a color string for this node number. Simply round-robin selects
/// from a reasonable number of colors.
StringRef getColorString(unsigned NodeNumber);
diff --git a/include/llvm/Support/Host.h b/include/llvm/Support/Host.h
index a4b0a340c568..57c79c0b9fdf 100644
--- a/include/llvm/Support/Host.h
+++ b/include/llvm/Support/Host.h
@@ -31,7 +31,7 @@
#define BYTE_ORDER LITTLE_ENDIAN
#endif
#else
-#if !defined(BYTE_ORDER) && !defined(LLVM_ON_WIN32)
+#if !defined(BYTE_ORDER) && !defined(_WIN32)
#include <machine/endian.h>
#endif
#endif
@@ -88,9 +88,9 @@ constexpr bool IsBigEndianHost = false;
namespace detail {
/// Helper functions to extract HostCPUName from /proc/cpuinfo on linux.
- StringRef getHostCPUNameForPowerPC(const StringRef &ProcCpuinfoContent);
- StringRef getHostCPUNameForARM(const StringRef &ProcCpuinfoContent);
- StringRef getHostCPUNameForS390x(const StringRef &ProcCpuinfoContent);
+ StringRef getHostCPUNameForPowerPC(StringRef ProcCpuinfoContent);
+ StringRef getHostCPUNameForARM(StringRef ProcCpuinfoContent);
+ StringRef getHostCPUNameForS390x(StringRef ProcCpuinfoContent);
StringRef getHostCPUNameForBPF();
}
}
diff --git a/include/llvm/Support/InitLLVM.h b/include/llvm/Support/InitLLVM.h
new file mode 100644
index 000000000000..0f629c9ac92d
--- /dev/null
+++ b/include/llvm/Support/InitLLVM.h
@@ -0,0 +1,46 @@
+//===- InitLLVM.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_LLVM_H
+#define LLVM_SUPPORT_LLVM_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/PrettyStackTrace.h"
+
+// The main() functions in typical LLVM tools start with InitLLVM which does
+// the following one-time initializations:
+//
+// 1. Setting up a signal handler so that pretty stack trace is printed out
+// if a process crashes.
+//
+// 2. If running on Windows, obtain command line arguments using a
+// multibyte character-aware API and convert arguments into UTF-8
+// encoding, so that you can assume that command line arguments are
+// always encoded in UTF-8 on any platform.
+//
+// InitLLVM calls llvm_shutdown() on destruction, which cleans up
+// ManagedStatic objects.
+namespace llvm {
+class InitLLVM {
+public:
+ InitLLVM(int &Argc, const char **&Argv);
+ InitLLVM(int &Argc, char **&Argv)
+ : InitLLVM(Argc, const_cast<const char **&>(Argv)) {}
+
+ ~InitLLVM();
+
+private:
+ BumpPtrAllocator Alloc;
+ SmallVector<const char *, 0> Args;
+ PrettyStackTraceProgram StackPrinter;
+};
+} // namespace llvm
+
+#endif
diff --git a/include/llvm/Support/JSON.h b/include/llvm/Support/JSON.h
new file mode 100644
index 000000000000..da3c5ea0b25d
--- /dev/null
+++ b/include/llvm/Support/JSON.h
@@ -0,0 +1,704 @@
+//===--- JSON.h - JSON values, parsing and serialization -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+///
+/// \file
+/// This file supports working with JSON data.
+///
+/// It comprises:
+///
+/// - classes which hold dynamically-typed parsed JSON structures
+/// These are value types that can be composed, inspected, and modified.
+/// See json::Value, and the related types json::Object and json::Array.
+///
+/// - functions to parse JSON text into Values, and to serialize Values to text.
+/// See parse(), operator<<, and format_provider.
+///
+/// - a convention and helpers for mapping between json::Value and user-defined
+/// types. See fromJSON(), ObjectMapper, and the class comment on Value.
+///
+/// Typically, JSON data would be read from an external source, parsed into
+/// a Value, and then converted into some native data structure before doing
+/// real work on it. (And vice versa when writing).
+///
+/// Other serialization mechanisms you may consider:
+///
+/// - YAML is also text-based, and more human-readable than JSON. It's a more
+/// complex format and data model, and YAML parsers aren't ubiquitous.
+/// YAMLParser.h is a streaming parser suitable for parsing large documents
+/// (including JSON, as YAML is a superset). It can be awkward to use
+/// directly. YAML I/O (YAMLTraits.h) provides data mapping that is more
+/// declarative than the toJSON/fromJSON conventions here.
+///
+/// - LLVM bitstream is a space- and CPU- efficient binary format. Typically it
+/// encodes LLVM IR ("bitcode"), but it can be a container for other data.
+/// Low-level reader/writer libraries are in Bitcode/Bitstream*.h
+///
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_JSON_H
+#define LLVM_SUPPORT_JSON_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/raw_ostream.h"
+#include <map>
+
+namespace llvm {
+namespace json {
+
+// === String encodings ===
+//
+// JSON strings are character sequences (not byte sequences like std::string).
+// We need to know the encoding, and for simplicity only support UTF-8.
+//
+// - When parsing, invalid UTF-8 is a syntax error like any other
+//
+// - When creating Values from strings, callers must ensure they are UTF-8.
+// with asserts on, invalid UTF-8 will crash the program
+// with asserts off, we'll substitute the replacement character (U+FFFD)
+// Callers can use json::isUTF8() and json::fixUTF8() for validation.
+//
+// - When retrieving strings from Values (e.g. asString()), the result will
+// always be valid UTF-8.
+
+/// Returns true if \p S is valid UTF-8, which is required for use as JSON.
+/// If it returns false, \p Offset is set to a byte offset near the first error.
+bool isUTF8(llvm::StringRef S, size_t *ErrOffset = nullptr);
+/// Replaces invalid UTF-8 sequences in \p S with the replacement character
+/// (U+FFFD). The returned string is valid UTF-8.
+/// This is much slower than isUTF8, so test that first.
+std::string fixUTF8(llvm::StringRef S);
+
+class Array;
+class ObjectKey;
+class Value;
+template <typename T> Value toJSON(const llvm::Optional<T> &Opt);
+
+/// An Object is a JSON object, which maps strings to heterogenous JSON values.
+/// It simulates DenseMap<ObjectKey, Value>. ObjectKey is a maybe-owned string.
+class Object {
+ using Storage = DenseMap<ObjectKey, Value, llvm::DenseMapInfo<StringRef>>;
+ Storage M;
+
+public:
+ using key_type = ObjectKey;
+ using mapped_type = Value;
+ using value_type = Storage::value_type;
+ using iterator = Storage::iterator;
+ using const_iterator = Storage::const_iterator;
+
+ explicit Object() = default;
+ // KV is a trivial key-value struct for list-initialization.
+ // (using std::pair forces extra copies).
+ struct KV;
+ explicit Object(std::initializer_list<KV> Properties);
+
+ iterator begin() { return M.begin(); }
+ const_iterator begin() const { return M.begin(); }
+ iterator end() { return M.end(); }
+ const_iterator end() const { return M.end(); }
+
+ bool empty() const { return M.empty(); }
+ size_t size() const { return M.size(); }
+
+ void clear() { M.clear(); }
+ std::pair<iterator, bool> insert(KV E);
+ template <typename... Ts>
+ std::pair<iterator, bool> try_emplace(const ObjectKey &K, Ts &&... Args) {
+ return M.try_emplace(K, std::forward<Ts>(Args)...);
+ }
+ template <typename... Ts>
+ std::pair<iterator, bool> try_emplace(ObjectKey &&K, Ts &&... Args) {
+ return M.try_emplace(std::move(K), std::forward<Ts>(Args)...);
+ }
+
+ iterator find(StringRef K) { return M.find_as(K); }
+ const_iterator find(StringRef K) const { return M.find_as(K); }
+ // operator[] acts as if Value was default-constructible as null.
+ Value &operator[](const ObjectKey &K);
+ Value &operator[](ObjectKey &&K);
+ // Look up a property, returning nullptr if it doesn't exist.
+ Value *get(StringRef K);
+ const Value *get(StringRef K) const;
+ // Typed accessors return None/nullptr if
+ // - the property doesn't exist
+ // - or it has the wrong type
+ llvm::Optional<std::nullptr_t> getNull(StringRef K) const;
+ llvm::Optional<bool> getBoolean(StringRef K) const;
+ llvm::Optional<double> getNumber(StringRef K) const;
+ llvm::Optional<int64_t> getInteger(StringRef K) const;
+ llvm::Optional<llvm::StringRef> getString(StringRef K) const;
+ const json::Object *getObject(StringRef K) const;
+ json::Object *getObject(StringRef K);
+ const json::Array *getArray(StringRef K) const;
+ json::Array *getArray(StringRef K);
+};
+bool operator==(const Object &LHS, const Object &RHS);
+inline bool operator!=(const Object &LHS, const Object &RHS) {
+ return !(LHS == RHS);
+}
+
+/// An Array is a JSON array, which contains heterogeneous JSON values.
+/// It simulates std::vector<Value>.
+class Array {
+ std::vector<Value> V;
+
+public:
+ using value_type = Value;
+ using iterator = std::vector<Value>::iterator;
+ using const_iterator = std::vector<Value>::const_iterator;
+
+ explicit Array() = default;
+ explicit Array(std::initializer_list<Value> Elements);
+ template <typename Collection> explicit Array(const Collection &C) {
+ for (const auto &V : C)
+ emplace_back(V);
+ }
+
+ Value &operator[](size_t I) { return V[I]; }
+ const Value &operator[](size_t I) const { return V[I]; }
+ Value &front() { return V.front(); }
+ const Value &front() const { return V.front(); }
+ Value &back() { return V.back(); }
+ const Value &back() const { return V.back(); }
+ Value *data() { return V.data(); }
+ const Value *data() const { return V.data(); }
+
+ iterator begin() { return V.begin(); }
+ const_iterator begin() const { return V.begin(); }
+ iterator end() { return V.end(); }
+ const_iterator end() const { return V.end(); }
+
+ bool empty() const { return V.empty(); }
+ size_t size() const { return V.size(); }
+
+ void clear() { V.clear(); }
+ void push_back(const Value &E) { V.push_back(E); }
+ void push_back(Value &&E) { V.push_back(std::move(E)); }
+ template <typename... Args> void emplace_back(Args &&... A) {
+ V.emplace_back(std::forward<Args>(A)...);
+ }
+ void pop_back() { V.pop_back(); }
+ // FIXME: insert() takes const_iterator since C++11, old libstdc++ disagrees.
+ iterator insert(iterator P, const Value &E) { return V.insert(P, E); }
+ iterator insert(iterator P, Value &&E) {
+ return V.insert(P, std::move(E));
+ }
+ template <typename It> iterator insert(iterator P, It A, It Z) {
+ return V.insert(P, A, Z);
+ }
+ template <typename... Args> iterator emplace(const_iterator P, Args &&... A) {
+ return V.emplace(P, std::forward<Args>(A)...);
+ }
+
+ friend bool operator==(const Array &L, const Array &R) { return L.V == R.V; }
+};
+inline bool operator!=(const Array &L, const Array &R) { return !(L == R); }
+
+/// A Value is an JSON value of unknown type.
+/// They can be copied, but should generally be moved.
+///
+/// === Composing values ===
+///
+/// You can implicitly construct Values from:
+/// - strings: std::string, SmallString, formatv, StringRef, char*
+/// (char*, and StringRef are references, not copies!)
+/// - numbers
+/// - booleans
+/// - null: nullptr
+/// - arrays: {"foo", 42.0, false}
+/// - serializable things: types with toJSON(const T&)->Value, found by ADL
+///
+/// They can also be constructed from object/array helpers:
+/// - json::Object is a type like map<ObjectKey, Value>
+/// - json::Array is a type like vector<Value>
+/// These can be list-initialized, or used to build up collections in a loop.
+/// json::ary(Collection) converts all items in a collection to Values.
+///
+/// === Inspecting values ===
+///
+/// Each Value is one of the JSON kinds:
+/// null (nullptr_t)
+/// boolean (bool)
+/// number (double or int64)
+/// string (StringRef)
+/// array (json::Array)
+/// object (json::Object)
+///
+/// The kind can be queried directly, or implicitly via the typed accessors:
+/// if (Optional<StringRef> S = E.getAsString()
+/// assert(E.kind() == Value::String);
+///
+/// Array and Object also have typed indexing accessors for easy traversal:
+/// Expected<Value> E = parse(R"( {"options": {"font": "sans-serif"}} )");
+/// if (Object* O = E->getAsObject())
+/// if (Object* Opts = O->getObject("options"))
+/// if (Optional<StringRef> Font = Opts->getString("font"))
+/// assert(Opts->at("font").kind() == Value::String);
+///
+/// === Converting JSON values to C++ types ===
+///
+/// The convention is to have a deserializer function findable via ADL:
+/// fromJSON(const json::Value&, T&)->bool
+/// Deserializers are provided for:
+/// - bool
+/// - int and int64_t
+/// - double
+/// - std::string
+/// - vector<T>, where T is deserializable
+/// - map<string, T>, where T is deserializable
+/// - Optional<T>, where T is deserializable
+/// ObjectMapper can help writing fromJSON() functions for object types.
+///
+/// For conversion in the other direction, the serializer function is:
+/// toJSON(const T&) -> json::Value
+/// If this exists, then it also allows constructing Value from T, and can
+/// be used to serialize vector<T>, map<string, T>, and Optional<T>.
+///
+/// === Serialization ===
+///
+/// Values can be serialized to JSON:
+/// 1) raw_ostream << Value // Basic formatting.
+/// 2) raw_ostream << formatv("{0}", Value) // Basic formatting.
+/// 3) raw_ostream << formatv("{0:2}", Value) // Pretty-print with indent 2.
+///
+/// And parsed:
+/// Expected<Value> E = json::parse("[1, 2, null]");
+/// assert(E && E->kind() == Value::Array);
+class Value {
+public:
+ enum Kind {
+ Null,
+ Boolean,
+ /// Number values can store both int64s and doubles at full precision,
+ /// depending on what they were constructed/parsed from.
+ Number,
+ String,
+ Array,
+ Object,
+ };
+
+ // It would be nice to have Value() be null. But that would make {} null too.
+ Value(const Value &M) { copyFrom(M); }
+ Value(Value &&M) { moveFrom(std::move(M)); }
+ Value(std::initializer_list<Value> Elements);
+ Value(json::Array &&Elements) : Type(T_Array) {
+ create<json::Array>(std::move(Elements));
+ }
+ Value(json::Object &&Properties) : Type(T_Object) {
+ create<json::Object>(std::move(Properties));
+ }
+ // Strings: types with value semantics. Must be valid UTF-8.
+ Value(std::string V) : Type(T_String) {
+ if (LLVM_UNLIKELY(!isUTF8(V))) {
+ assert(false && "Invalid UTF-8 in value used as JSON");
+ V = fixUTF8(std::move(V));
+ }
+ create<std::string>(std::move(V));
+ }
+ Value(const llvm::SmallVectorImpl<char> &V)
+ : Value(std::string(V.begin(), V.end())){};
+ Value(const llvm::formatv_object_base &V) : Value(V.str()){};
+ // Strings: types with reference semantics. Must be valid UTF-8.
+ Value(StringRef V) : Type(T_StringRef) {
+ create<llvm::StringRef>(V);
+ if (LLVM_UNLIKELY(!isUTF8(V))) {
+ assert(false && "Invalid UTF-8 in value used as JSON");
+ *this = Value(fixUTF8(V));
+ }
+ }
+ Value(const char *V) : Value(StringRef(V)) {}
+ Value(std::nullptr_t) : Type(T_Null) {}
+ // Boolean (disallow implicit conversions).
+ // (The last template parameter is a dummy to keep templates distinct.)
+ template <
+ typename T,
+ typename = typename std::enable_if<std::is_same<T, bool>::value>::type,
+ bool = false>
+ Value(T B) : Type(T_Boolean) {
+ create<bool>(B);
+ }
+ // Integers (except boolean). Must be non-narrowing convertible to int64_t.
+ template <
+ typename T,
+ typename = typename std::enable_if<std::is_integral<T>::value>::type,
+ typename = typename std::enable_if<!std::is_same<T, bool>::value>::type>
+ Value(T I) : Type(T_Integer) {
+ create<int64_t>(int64_t{I});
+ }
+ // Floating point. Must be non-narrowing convertible to double.
+ template <typename T,
+ typename =
+ typename std::enable_if<std::is_floating_point<T>::value>::type,
+ double * = nullptr>
+ Value(T D) : Type(T_Double) {
+ create<double>(double{D});
+ }
+ // Serializable types: with a toJSON(const T&)->Value function, found by ADL.
+ template <typename T,
+ typename = typename std::enable_if<std::is_same<
+ Value, decltype(toJSON(*(const T *)nullptr))>::value>,
+ Value * = nullptr>
+ Value(const T &V) : Value(toJSON(V)) {}
+
+ Value &operator=(const Value &M) {
+ destroy();
+ copyFrom(M);
+ return *this;
+ }
+ Value &operator=(Value &&M) {
+ destroy();
+ moveFrom(std::move(M));
+ return *this;
+ }
+ ~Value() { destroy(); }
+
+ Kind kind() const {
+ switch (Type) {
+ case T_Null:
+ return Null;
+ case T_Boolean:
+ return Boolean;
+ case T_Double:
+ case T_Integer:
+ return Number;
+ case T_String:
+ case T_StringRef:
+ return String;
+ case T_Object:
+ return Object;
+ case T_Array:
+ return Array;
+ }
+ llvm_unreachable("Unknown kind");
+ }
+
+ // Typed accessors return None/nullptr if the Value is not of this type.
+ llvm::Optional<std::nullptr_t> getAsNull() const {
+ if (LLVM_LIKELY(Type == T_Null))
+ return nullptr;
+ return llvm::None;
+ }
+ llvm::Optional<bool> getAsBoolean() const {
+ if (LLVM_LIKELY(Type == T_Boolean))
+ return as<bool>();
+ return llvm::None;
+ }
+ llvm::Optional<double> getAsNumber() const {
+ if (LLVM_LIKELY(Type == T_Double))
+ return as<double>();
+ if (LLVM_LIKELY(Type == T_Integer))
+ return as<int64_t>();
+ return llvm::None;
+ }
+ // Succeeds if the Value is a Number, and exactly representable as int64_t.
+ llvm::Optional<int64_t> getAsInteger() const {
+ if (LLVM_LIKELY(Type == T_Integer))
+ return as<int64_t>();
+ if (LLVM_LIKELY(Type == T_Double)) {
+ double D = as<double>();
+ if (LLVM_LIKELY(std::modf(D, &D) == 0.0 &&
+ D >= double(std::numeric_limits<int64_t>::min()) &&
+ D <= double(std::numeric_limits<int64_t>::max())))
+ return D;
+ }
+ return llvm::None;
+ }
+ llvm::Optional<llvm::StringRef> getAsString() const {
+ if (Type == T_String)
+ return llvm::StringRef(as<std::string>());
+ if (LLVM_LIKELY(Type == T_StringRef))
+ return as<llvm::StringRef>();
+ return llvm::None;
+ }
+ const json::Object *getAsObject() const {
+ return LLVM_LIKELY(Type == T_Object) ? &as<json::Object>() : nullptr;
+ }
+ json::Object *getAsObject() {
+ return LLVM_LIKELY(Type == T_Object) ? &as<json::Object>() : nullptr;
+ }
+ const json::Array *getAsArray() const {
+ return LLVM_LIKELY(Type == T_Array) ? &as<json::Array>() : nullptr;
+ }
+ json::Array *getAsArray() {
+ return LLVM_LIKELY(Type == T_Array) ? &as<json::Array>() : nullptr;
+ }
+
+ /// Serializes this Value to JSON, writing it to the provided stream.
+ /// The formatting is compact (no extra whitespace) and deterministic.
+ /// For pretty-printing, use the formatv() format_provider below.
+ friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Value &);
+
+private:
+ void destroy();
+ void copyFrom(const Value &M);
+ // We allow moving from *const* Values, by marking all members as mutable!
+ // This hack is needed to support initializer-list syntax efficiently.
+ // (std::initializer_list<T> is a container of const T).
+ void moveFrom(const Value &&M);
+ friend class Array;
+ friend class Object;
+
+ template <typename T, typename... U> void create(U &&... V) {
+ new (reinterpret_cast<T *>(Union.buffer)) T(std::forward<U>(V)...);
+ }
+ template <typename T> T &as() const {
+ return *reinterpret_cast<T *>(Union.buffer);
+ }
+
+ template <typename Indenter>
+ void print(llvm::raw_ostream &, const Indenter &) const;
+ friend struct llvm::format_provider<llvm::json::Value>;
+
+ enum ValueType : char {
+ T_Null,
+ T_Boolean,
+ T_Double,
+ T_Integer,
+ T_StringRef,
+ T_String,
+ T_Object,
+ T_Array,
+ };
+ // All members mutable, see moveFrom().
+ mutable ValueType Type;
+ mutable llvm::AlignedCharArrayUnion<bool, double, int64_t, llvm::StringRef,
+ std::string, json::Array, json::Object>
+ Union;
+};
+
+bool operator==(const Value &, const Value &);
+inline bool operator!=(const Value &L, const Value &R) { return !(L == R); }
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Value &);
+
+/// ObjectKey is a used to capture keys in Object. Like Value but:
+/// - only strings are allowed
+/// - it's optimized for the string literal case (Owned == nullptr)
+/// Like Value, strings must be UTF-8. See isUTF8 documentation for details.
+class ObjectKey {
+public:
+ ObjectKey(const char *S) : ObjectKey(StringRef(S)) {}
+ ObjectKey(std::string S) : Owned(new std::string(std::move(S))) {
+ if (LLVM_UNLIKELY(!isUTF8(*Owned))) {
+ assert(false && "Invalid UTF-8 in value used as JSON");
+ *Owned = fixUTF8(std::move(*Owned));
+ }
+ Data = *Owned;
+ }
+ ObjectKey(llvm::StringRef S) : Data(S) {
+ if (LLVM_UNLIKELY(!isUTF8(Data))) {
+ assert(false && "Invalid UTF-8 in value used as JSON");
+ *this = ObjectKey(fixUTF8(S));
+ }
+ }
+ ObjectKey(const llvm::SmallVectorImpl<char> &V)
+ : ObjectKey(std::string(V.begin(), V.end())) {}
+ ObjectKey(const llvm::formatv_object_base &V) : ObjectKey(V.str()) {}
+
+ ObjectKey(const ObjectKey &C) { *this = C; }
+ ObjectKey(ObjectKey &&C) : ObjectKey(static_cast<const ObjectKey &&>(C)) {}
+ ObjectKey &operator=(const ObjectKey &C) {
+ if (C.Owned) {
+ Owned.reset(new std::string(*C.Owned));
+ Data = *Owned;
+ } else {
+ Data = C.Data;
+ }
+ return *this;
+ }
+ ObjectKey &operator=(ObjectKey &&) = default;
+
+ operator llvm::StringRef() const { return Data; }
+ std::string str() const { return Data.str(); }
+
+private:
+ // FIXME: this is unneccesarily large (3 pointers). Pointer + length + owned
+ // could be 2 pointers at most.
+ std::unique_ptr<std::string> Owned;
+ llvm::StringRef Data;
+};
+
+inline bool operator==(const ObjectKey &L, const ObjectKey &R) {
+ return llvm::StringRef(L) == llvm::StringRef(R);
+}
+inline bool operator!=(const ObjectKey &L, const ObjectKey &R) {
+ return !(L == R);
+}
+inline bool operator<(const ObjectKey &L, const ObjectKey &R) {
+ return StringRef(L) < StringRef(R);
+}
+
+struct Object::KV {
+ ObjectKey K;
+ Value V;
+};
+
+inline Object::Object(std::initializer_list<KV> Properties) {
+ for (const auto &P : Properties) {
+ auto R = try_emplace(P.K, nullptr);
+ if (R.second)
+ R.first->getSecond().moveFrom(std::move(P.V));
+ }
+}
+inline std::pair<Object::iterator, bool> Object::insert(KV E) {
+ return try_emplace(std::move(E.K), std::move(E.V));
+}
+
+// Standard deserializers are provided for primitive types.
+// See comments on Value.
+inline bool fromJSON(const Value &E, std::string &Out) {
+ if (auto S = E.getAsString()) {
+ Out = *S;
+ return true;
+ }
+ return false;
+}
+inline bool fromJSON(const Value &E, int &Out) {
+ if (auto S = E.getAsInteger()) {
+ Out = *S;
+ return true;
+ }
+ return false;
+}
+inline bool fromJSON(const Value &E, int64_t &Out) {
+ if (auto S = E.getAsInteger()) {
+ Out = *S;
+ return true;
+ }
+ return false;
+}
+inline bool fromJSON(const Value &E, double &Out) {
+ if (auto S = E.getAsNumber()) {
+ Out = *S;
+ return true;
+ }
+ return false;
+}
+inline bool fromJSON(const Value &E, bool &Out) {
+ if (auto S = E.getAsBoolean()) {
+ Out = *S;
+ return true;
+ }
+ return false;
+}
+template <typename T> bool fromJSON(const Value &E, llvm::Optional<T> &Out) {
+ if (E.getAsNull()) {
+ Out = llvm::None;
+ return true;
+ }
+ T Result;
+ if (!fromJSON(E, Result))
+ return false;
+ Out = std::move(Result);
+ return true;
+}
+template <typename T> bool fromJSON(const Value &E, std::vector<T> &Out) {
+ if (auto *A = E.getAsArray()) {
+ Out.clear();
+ Out.resize(A->size());
+ for (size_t I = 0; I < A->size(); ++I)
+ if (!fromJSON((*A)[I], Out[I]))
+ return false;
+ return true;
+ }
+ return false;
+}
+template <typename T>
+bool fromJSON(const Value &E, std::map<std::string, T> &Out) {
+ if (auto *O = E.getAsObject()) {
+ Out.clear();
+ for (const auto &KV : *O)
+ if (!fromJSON(KV.second, Out[llvm::StringRef(KV.first)]))
+ return false;
+ return true;
+ }
+ return false;
+}
+
+// Allow serialization of Optional<T> for supported T.
+template <typename T> Value toJSON(const llvm::Optional<T> &Opt) {
+ return Opt ? Value(*Opt) : Value(nullptr);
+}
+
+/// Helper for mapping JSON objects onto protocol structs.
+///
+/// Example:
+/// \code
+/// bool fromJSON(const Value &E, MyStruct &R) {
+/// ObjectMapper O(E);
+/// if (!O || !O.map("mandatory_field", R.MandatoryField))
+/// return false;
+/// O.map("optional_field", R.OptionalField);
+/// return true;
+/// }
+/// \endcode
+class ObjectMapper {
+public:
+ ObjectMapper(const Value &E) : O(E.getAsObject()) {}
+
+ /// True if the expression is an object.
+ /// Must be checked before calling map().
+ operator bool() { return O; }
+
+ /// Maps a property to a field, if it exists.
+ template <typename T> bool map(StringRef Prop, T &Out) {
+ assert(*this && "Must check this is an object before calling map()");
+ if (const Value *E = O->get(Prop))
+ return fromJSON(*E, Out);
+ return false;
+ }
+
+ /// Maps a property to a field, if it exists.
+ /// (Optional requires special handling, because missing keys are OK).
+ template <typename T> bool map(StringRef Prop, llvm::Optional<T> &Out) {
+ assert(*this && "Must check this is an object before calling map()");
+ if (const Value *E = O->get(Prop))
+ return fromJSON(*E, Out);
+ Out = llvm::None;
+ return true;
+ }
+
+private:
+ const Object *O;
+};
+
+/// Parses the provided JSON source, or returns a ParseError.
+/// The returned Value is self-contained and owns its strings (they do not refer
+/// to the original source).
+llvm::Expected<Value> parse(llvm::StringRef JSON);
+
+class ParseError : public llvm::ErrorInfo<ParseError> {
+ const char *Msg;
+ unsigned Line, Column, Offset;
+
+public:
+ static char ID;
+ ParseError(const char *Msg, unsigned Line, unsigned Column, unsigned Offset)
+ : Msg(Msg), Line(Line), Column(Column), Offset(Offset) {}
+ void log(llvm::raw_ostream &OS) const override {
+ OS << llvm::formatv("[{0}:{1}, byte={2}]: {3}", Line, Column, Offset, Msg);
+ }
+ std::error_code convertToErrorCode() const override {
+ return llvm::inconvertibleErrorCode();
+ }
+};
+} // namespace json
+
+/// Allow printing json::Value with formatv().
+/// The default style is basic/compact formatting, like operator<<.
+/// A format string like formatv("{0:2}", Value) pretty-prints with indent 2.
+template <> struct format_provider<llvm::json::Value> {
+ static void format(const llvm::json::Value &, raw_ostream &, StringRef);
+};
+} // namespace llvm
+
+#endif
diff --git a/include/llvm/Support/JamCRC.h b/include/llvm/Support/JamCRC.h
index 5268bbd9ba1e..846d6cea9828 100644
--- a/include/llvm/Support/JamCRC.h
+++ b/include/llvm/Support/JamCRC.h
@@ -36,7 +36,7 @@ class JamCRC {
public:
JamCRC(uint32_t Init = 0xFFFFFFFFU) : CRC(Init) {}
- // \brief Update the CRC calculation with Data.
+ // Update the CRC calculation with Data.
void update(ArrayRef<char> Data);
uint32_t getCRC() const { return CRC; }
diff --git a/include/llvm/Support/KnownBits.h b/include/llvm/Support/KnownBits.h
index 97e73b13fca3..259df9546c57 100644
--- a/include/llvm/Support/KnownBits.h
+++ b/include/llvm/Support/KnownBits.h
@@ -103,7 +103,7 @@ public:
One.setSignBit();
}
- /// Make this value negative.
+ /// Make this value non-negative.
void makeNonNegative() {
Zero.setSignBit();
}
diff --git a/include/llvm/Support/LEB128.h b/include/llvm/Support/LEB128.h
index 6af6e9f34474..9feb07229225 100644
--- a/include/llvm/Support/LEB128.h
+++ b/include/llvm/Support/LEB128.h
@@ -19,9 +19,10 @@
namespace llvm {
-/// Utility function to encode a SLEB128 value to an output stream.
-inline void encodeSLEB128(int64_t Value, raw_ostream &OS,
- unsigned PadTo = 0) {
+/// Utility function to encode a SLEB128 value to an output stream. Returns
+/// the length in bytes of the encoded value.
+inline unsigned encodeSLEB128(int64_t Value, raw_ostream &OS,
+ unsigned PadTo = 0) {
bool More;
unsigned Count = 0;
do {
@@ -42,7 +43,9 @@ inline void encodeSLEB128(int64_t Value, raw_ostream &OS,
for (; Count < PadTo - 1; ++Count)
OS << char(PadValue | 0x80);
OS << char(PadValue);
+ Count++;
}
+ return Count;
}
/// Utility function to encode a SLEB128 value to a buffer. Returns
@@ -73,9 +76,10 @@ inline unsigned encodeSLEB128(int64_t Value, uint8_t *p, unsigned PadTo = 0) {
return (unsigned)(p - orig_p);
}
-/// Utility function to encode a ULEB128 value to an output stream.
-inline void encodeULEB128(uint64_t Value, raw_ostream &OS,
- unsigned PadTo = 0) {
+/// Utility function to encode a ULEB128 value to an output stream. Returns
+/// the length in bytes of the encoded value.
+inline unsigned encodeULEB128(uint64_t Value, raw_ostream &OS,
+ unsigned PadTo = 0) {
unsigned Count = 0;
do {
uint8_t Byte = Value & 0x7f;
@@ -93,6 +97,7 @@ inline void encodeULEB128(uint64_t Value, raw_ostream &OS,
OS << '\x00';
Count++;
}
+ return Count;
}
/// Utility function to encode a ULEB128 value to a buffer. Returns
diff --git a/include/llvm/Support/LineIterator.h b/include/llvm/Support/LineIterator.h
index 9d4cd3bd4c6d..892d289976cb 100644
--- a/include/llvm/Support/LineIterator.h
+++ b/include/llvm/Support/LineIterator.h
@@ -18,7 +18,7 @@ namespace llvm {
class MemoryBuffer;
-/// \brief A forward iterator which reads text lines from a buffer.
+/// A forward iterator which reads text lines from a buffer.
///
/// This class provides a forward iterator interface for reading one line at
/// a time from a buffer. When default constructed the iterator will be the
@@ -39,23 +39,23 @@ class line_iterator
StringRef CurrentLine;
public:
- /// \brief Default construct an "end" iterator.
+ /// Default construct an "end" iterator.
line_iterator() : Buffer(nullptr) {}
- /// \brief Construct a new iterator around some memory buffer.
+ /// Construct a new iterator around some memory buffer.
explicit line_iterator(const MemoryBuffer &Buffer, bool SkipBlanks = true,
char CommentMarker = '\0');
- /// \brief Return true if we've reached EOF or are an "end" iterator.
+ /// Return true if we've reached EOF or are an "end" iterator.
bool is_at_eof() const { return !Buffer; }
- /// \brief Return true if we're an "end" iterator or have reached EOF.
+ /// Return true if we're an "end" iterator or have reached EOF.
bool is_at_end() const { return is_at_eof(); }
- /// \brief Return the current line number. May return any number at EOF.
+ /// Return the current line number. May return any number at EOF.
int64_t line_number() const { return LineNumber; }
- /// \brief Advance to the next (non-empty, non-comment) line.
+ /// Advance to the next (non-empty, non-comment) line.
line_iterator &operator++() {
advance();
return *this;
@@ -66,7 +66,7 @@ public:
return tmp;
}
- /// \brief Get the current line as a \c StringRef.
+ /// Get the current line as a \c StringRef.
StringRef operator*() const { return CurrentLine; }
const StringRef *operator->() const { return &CurrentLine; }
@@ -80,7 +80,7 @@ public:
}
private:
- /// \brief Advance the iterator to the next line.
+ /// Advance the iterator to the next line.
void advance();
};
}
diff --git a/include/llvm/Support/LockFileManager.h b/include/llvm/Support/LockFileManager.h
index 1e417bdd5b25..86db0b2b1020 100644
--- a/include/llvm/Support/LockFileManager.h
+++ b/include/llvm/Support/LockFileManager.h
@@ -11,14 +11,13 @@
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/FileSystem.h"
#include <system_error>
#include <utility> // for std::pair
namespace llvm {
class StringRef;
-/// \brief Class that manages the creation of a lock file to aid
+/// Class that manages the creation of a lock file to aid
/// implicit coordination between different processes.
///
/// The implicit coordination works by creating a ".lock" file alongside
@@ -28,33 +27,33 @@ class StringRef;
/// operation.
class LockFileManager {
public:
- /// \brief Describes the state of a lock file.
+ /// Describes the state of a lock file.
enum LockFileState {
- /// \brief The lock file has been created and is owned by this instance
+ /// The lock file has been created and is owned by this instance
/// of the object.
LFS_Owned,
- /// \brief The lock file already exists and is owned by some other
+ /// The lock file already exists and is owned by some other
/// instance.
LFS_Shared,
- /// \brief An error occurred while trying to create or find the lock
+ /// An error occurred while trying to create or find the lock
/// file.
LFS_Error
};
- /// \brief Describes the result of waiting for the owner to release the lock.
+ /// Describes the result of waiting for the owner to release the lock.
enum WaitForUnlockResult {
- /// \brief The lock was released successfully.
+ /// The lock was released successfully.
Res_Success,
- /// \brief Owner died while holding the lock.
+ /// Owner died while holding the lock.
Res_OwnerDied,
- /// \brief Reached timeout while waiting for the owner to release the lock.
+ /// Reached timeout while waiting for the owner to release the lock.
Res_Timeout
};
private:
SmallString<128> FileName;
SmallString<128> LockFileName;
- Optional<sys::fs::TempFile> UniqueLockFile;
+ SmallString<128> UniqueLockFileName;
Optional<std::pair<std::string, int> > Owner;
std::error_code ErrorCode;
@@ -73,22 +72,22 @@ public:
LockFileManager(StringRef FileName);
~LockFileManager();
- /// \brief Determine the state of the lock file.
+ /// Determine the state of the lock file.
LockFileState getState() const;
operator LockFileState() const { return getState(); }
- /// \brief For a shared lock, wait until the owner releases the lock.
+ /// For a shared lock, wait until the owner releases the lock.
WaitForUnlockResult waitForUnlock();
- /// \brief Remove the lock file. This may delete a different lock file than
+ /// Remove the lock file. This may delete a different lock file than
/// the one previously read if there is a race.
std::error_code unsafeRemoveLockFile();
- /// \brief Get error message, or "" if there is no error.
+ /// Get error message, or "" if there is no error.
std::string getErrorMessage() const;
- /// \brief Set error and error message
+ /// Set error and error message
void setError(const std::error_code &EC, StringRef ErrorMsg = "") {
ErrorCode = EC;
ErrorDiagMsg = ErrorMsg.str();
diff --git a/include/llvm/Support/LowLevelTypeImpl.h b/include/llvm/Support/LowLevelTypeImpl.h
index 099fa4618997..a0a5a52d206e 100644
--- a/include/llvm/Support/LowLevelTypeImpl.h
+++ b/include/llvm/Support/LowLevelTypeImpl.h
@@ -28,7 +28,7 @@
#define LLVM_SUPPORT_LOWLEVELTYPEIMPL_H
#include "llvm/ADT/DenseMapInfo.h"
-#include "llvm/CodeGen/MachineValueType.h"
+#include "llvm/Support/MachineValueType.h"
#include <cassert>
namespace llvm {
diff --git a/include/llvm/Support/MD5.h b/include/llvm/Support/MD5.h
index 2c0dc76485f8..bb2bdbf1bed2 100644
--- a/include/llvm/Support/MD5.h
+++ b/include/llvm/Support/MD5.h
@@ -81,20 +81,20 @@ public:
MD5();
- /// \brief Updates the hash for the byte stream provided.
+ /// Updates the hash for the byte stream provided.
void update(ArrayRef<uint8_t> Data);
- /// \brief Updates the hash for the StringRef provided.
+ /// Updates the hash for the StringRef provided.
void update(StringRef Str);
- /// \brief Finishes off the hash and puts the result in result.
+ /// Finishes off the hash and puts the result in result.
void final(MD5Result &Result);
- /// \brief Translates the bytes in \p Res to a hex string that is
+ /// Translates the bytes in \p Res to a hex string that is
/// deposited into \p Str. The result will be of length 32.
static void stringifyResult(MD5Result &Result, SmallString<32> &Str);
- /// \brief Computes the hash for a given bytes.
+ /// Computes the hash for a given bytes.
static std::array<uint8_t, 16> hash(ArrayRef<uint8_t> Data);
private:
diff --git a/include/llvm/Support/MachineValueType.h b/include/llvm/Support/MachineValueType.h
new file mode 100644
index 000000000000..552dea05029c
--- /dev/null
+++ b/include/llvm/Support/MachineValueType.h
@@ -0,0 +1,1058 @@
+//===- Support/MachineValueType.h - Machine-Level types ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the set of machine-level target independent types which
+// legal values in the code generator use.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_MACHINEVALUETYPE_H
+#define LLVM_SUPPORT_MACHINEVALUETYPE_H
+
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include <cassert>
+
+namespace llvm {
+
+ class Type;
+
+ /// Machine Value Type. Every type that is supported natively by some
+ /// processor targeted by LLVM occurs here. This means that any legal value
+ /// type can be represented by an MVT.
+ class MVT {
+ public:
+ enum SimpleValueType : uint8_t {
+ // Simple value types that aren't explicitly part of this enumeration
+ // are considered extended value types.
+ INVALID_SIMPLE_VALUE_TYPE = 0,
+
+ // If you change this numbering, you must change the values in
+ // ValueTypes.td as well!
+ Other = 1, // This is a non-standard value
+ i1 = 2, // This is a 1 bit integer value
+ i8 = 3, // This is an 8 bit integer value
+ i16 = 4, // This is a 16 bit integer value
+ i32 = 5, // This is a 32 bit integer value
+ i64 = 6, // This is a 64 bit integer value
+ i128 = 7, // This is a 128 bit integer value
+
+ FIRST_INTEGER_VALUETYPE = i1,
+ LAST_INTEGER_VALUETYPE = i128,
+
+ f16 = 8, // This is a 16 bit floating point value
+ f32 = 9, // This is a 32 bit floating point value
+ f64 = 10, // This is a 64 bit floating point value
+ f80 = 11, // This is a 80 bit floating point value
+ f128 = 12, // This is a 128 bit floating point value
+ ppcf128 = 13, // This is a PPC 128-bit floating point value
+
+ FIRST_FP_VALUETYPE = f16,
+ LAST_FP_VALUETYPE = ppcf128,
+
+ v1i1 = 14, // 1 x i1
+ v2i1 = 15, // 2 x i1
+ v4i1 = 16, // 4 x i1
+ v8i1 = 17, // 8 x i1
+ v16i1 = 18, // 16 x i1
+ v32i1 = 19, // 32 x i1
+ v64i1 = 20, // 64 x i1
+ v128i1 = 21, // 128 x i1
+ v512i1 = 22, // 512 x i1
+ v1024i1 = 23, // 1024 x i1
+
+ v1i8 = 24, // 1 x i8
+ v2i8 = 25, // 2 x i8
+ v4i8 = 26, // 4 x i8
+ v8i8 = 27, // 8 x i8
+ v16i8 = 28, // 16 x i8
+ v32i8 = 29, // 32 x i8
+ v64i8 = 30, // 64 x i8
+ v128i8 = 31, //128 x i8
+ v256i8 = 32, //256 x i8
+
+ v1i16 = 33, // 1 x i16
+ v2i16 = 34, // 2 x i16
+ v4i16 = 35, // 4 x i16
+ v8i16 = 36, // 8 x i16
+ v16i16 = 37, // 16 x i16
+ v32i16 = 38, // 32 x i16
+ v64i16 = 39, // 64 x i16
+ v128i16 = 40, //128 x i16
+
+ v1i32 = 41, // 1 x i32
+ v2i32 = 42, // 2 x i32
+ v4i32 = 43, // 4 x i32
+ v8i32 = 44, // 8 x i32
+ v16i32 = 45, // 16 x i32
+ v32i32 = 46, // 32 x i32
+ v64i32 = 47, // 64 x i32
+
+ v1i64 = 48, // 1 x i64
+ v2i64 = 49, // 2 x i64
+ v4i64 = 50, // 4 x i64
+ v8i64 = 51, // 8 x i64
+ v16i64 = 52, // 16 x i64
+ v32i64 = 53, // 32 x i64
+
+ v1i128 = 54, // 1 x i128
+
+ // Scalable integer types
+ nxv1i1 = 55, // n x 1 x i1
+ nxv2i1 = 56, // n x 2 x i1
+ nxv4i1 = 57, // n x 4 x i1
+ nxv8i1 = 58, // n x 8 x i1
+ nxv16i1 = 59, // n x 16 x i1
+ nxv32i1 = 60, // n x 32 x i1
+
+ nxv1i8 = 61, // n x 1 x i8
+ nxv2i8 = 62, // n x 2 x i8
+ nxv4i8 = 63, // n x 4 x i8
+ nxv8i8 = 64, // n x 8 x i8
+ nxv16i8 = 65, // n x 16 x i8
+ nxv32i8 = 66, // n x 32 x i8
+
+ nxv1i16 = 67, // n x 1 x i16
+ nxv2i16 = 68, // n x 2 x i16
+ nxv4i16 = 69, // n x 4 x i16
+ nxv8i16 = 70, // n x 8 x i16
+ nxv16i16 = 71, // n x 16 x i16
+ nxv32i16 = 72, // n x 32 x i16
+
+ nxv1i32 = 73, // n x 1 x i32
+ nxv2i32 = 74, // n x 2 x i32
+ nxv4i32 = 75, // n x 4 x i32
+ nxv8i32 = 76, // n x 8 x i32
+ nxv16i32 = 77, // n x 16 x i32
+ nxv32i32 = 78, // n x 32 x i32
+
+ nxv1i64 = 79, // n x 1 x i64
+ nxv2i64 = 80, // n x 2 x i64
+ nxv4i64 = 81, // n x 4 x i64
+ nxv8i64 = 82, // n x 8 x i64
+ nxv16i64 = 83, // n x 16 x i64
+ nxv32i64 = 84, // n x 32 x i64
+
+ FIRST_INTEGER_VECTOR_VALUETYPE = v1i1,
+ LAST_INTEGER_VECTOR_VALUETYPE = nxv32i64,
+
+ FIRST_INTEGER_SCALABLE_VALUETYPE = nxv1i1,
+ LAST_INTEGER_SCALABLE_VALUETYPE = nxv32i64,
+
+ v2f16 = 85, // 2 x f16
+ v4f16 = 86, // 4 x f16
+ v8f16 = 87, // 8 x f16
+ v1f32 = 88, // 1 x f32
+ v2f32 = 89, // 2 x f32
+ v4f32 = 90, // 4 x f32
+ v8f32 = 91, // 8 x f32
+ v16f32 = 92, // 16 x f32
+ v1f64 = 93, // 1 x f64
+ v2f64 = 94, // 2 x f64
+ v4f64 = 95, // 4 x f64
+ v8f64 = 96, // 8 x f64
+
+ nxv2f16 = 97, // n x 2 x f16
+ nxv4f16 = 98, // n x 4 x f16
+ nxv8f16 = 99, // n x 8 x f16
+ nxv1f32 = 100, // n x 1 x f32
+ nxv2f32 = 101, // n x 2 x f32
+ nxv4f32 = 102, // n x 4 x f32
+ nxv8f32 = 103, // n x 8 x f32
+ nxv16f32 = 104, // n x 16 x f32
+ nxv1f64 = 105, // n x 1 x f64
+ nxv2f64 = 106, // n x 2 x f64
+ nxv4f64 = 107, // n x 4 x f64
+ nxv8f64 = 108, // n x 8 x f64
+
+ FIRST_FP_VECTOR_VALUETYPE = v2f16,
+ LAST_FP_VECTOR_VALUETYPE = nxv8f64,
+
+ FIRST_FP_SCALABLE_VALUETYPE = nxv2f16,
+ LAST_FP_SCALABLE_VALUETYPE = nxv8f64,
+
+ FIRST_VECTOR_VALUETYPE = v1i1,
+ LAST_VECTOR_VALUETYPE = nxv8f64,
+
+ x86mmx = 109, // This is an X86 MMX value
+
+ Glue = 110, // This glues nodes together during pre-RA sched
+
+ isVoid = 111, // This has no value
+
+ Untyped = 112, // This value takes a register, but has
+ // unspecified type. The register class
+ // will be determined by the opcode.
+
+ ExceptRef = 113, // WebAssembly's except_ref type
+
+ FIRST_VALUETYPE = 1, // This is always the beginning of the list.
+ LAST_VALUETYPE = 114, // This always remains at the end of the list.
+
+ // This is the current maximum for LAST_VALUETYPE.
+ // MVT::MAX_ALLOWED_VALUETYPE is used for asserts and to size bit vectors
+ // This value must be a multiple of 32.
+ MAX_ALLOWED_VALUETYPE = 128,
+
+ // A value of type llvm::TokenTy
+ token = 248,
+
+ // This is MDNode or MDString.
+ Metadata = 249,
+
+ // An int value the size of the pointer of the current
+ // target to any address space. This must only be used internal to
+ // tblgen. Other than for overloading, we treat iPTRAny the same as iPTR.
+ iPTRAny = 250,
+
+ // A vector with any length and element size. This is used
+ // for intrinsics that have overloadings based on vector types.
+ // This is only for tblgen's consumption!
+ vAny = 251,
+
+ // Any floating-point or vector floating-point value. This is used
+ // for intrinsics that have overloadings based on floating-point types.
+ // This is only for tblgen's consumption!
+ fAny = 252,
+
+ // An integer or vector integer value of any bit width. This is
+ // used for intrinsics that have overloadings based on integer bit widths.
+ // This is only for tblgen's consumption!
+ iAny = 253,
+
+ // An int value the size of the pointer of the current
+ // target. This should only be used internal to tblgen!
+ iPTR = 254,
+
+ // Any type. This is used for intrinsics that have overloadings.
+ // This is only for tblgen's consumption!
+ Any = 255
+ };
+
+ SimpleValueType SimpleTy = INVALID_SIMPLE_VALUE_TYPE;
+
+ // A class to represent the number of elements in a vector
+ //
+ // For fixed-length vectors, the total number of elements is equal to 'Min'
+ // For scalable vectors, the total number of elements is a multiple of 'Min'
+ class ElementCount {
+ public:
+ unsigned Min;
+ bool Scalable;
+
+ ElementCount(unsigned Min, bool Scalable)
+ : Min(Min), Scalable(Scalable) {}
+
+ ElementCount operator*(unsigned RHS) {
+ return { Min * RHS, Scalable };
+ }
+
+ ElementCount& operator*=(unsigned RHS) {
+ Min *= RHS;
+ return *this;
+ }
+
+ ElementCount operator/(unsigned RHS) {
+ return { Min / RHS, Scalable };
+ }
+
+ ElementCount& operator/=(unsigned RHS) {
+ Min /= RHS;
+ return *this;
+ }
+
+ bool operator==(const ElementCount& RHS) {
+ return Min == RHS.Min && Scalable == RHS.Scalable;
+ }
+ };
+
+ constexpr MVT() = default;
+ constexpr MVT(SimpleValueType SVT) : SimpleTy(SVT) {}
+
+ bool operator>(const MVT& S) const { return SimpleTy > S.SimpleTy; }
+ bool operator<(const MVT& S) const { return SimpleTy < S.SimpleTy; }
+ bool operator==(const MVT& S) const { return SimpleTy == S.SimpleTy; }
+ bool operator!=(const MVT& S) const { return SimpleTy != S.SimpleTy; }
+ bool operator>=(const MVT& S) const { return SimpleTy >= S.SimpleTy; }
+ bool operator<=(const MVT& S) const { return SimpleTy <= S.SimpleTy; }
+
+ /// Return true if this is a valid simple valuetype.
+ bool isValid() const {
+ return (SimpleTy >= MVT::FIRST_VALUETYPE &&
+ SimpleTy < MVT::LAST_VALUETYPE);
+ }
+
+ /// Return true if this is a FP or a vector FP type.
+ bool isFloatingPoint() const {
+ return ((SimpleTy >= MVT::FIRST_FP_VALUETYPE &&
+ SimpleTy <= MVT::LAST_FP_VALUETYPE) ||
+ (SimpleTy >= MVT::FIRST_FP_VECTOR_VALUETYPE &&
+ SimpleTy <= MVT::LAST_FP_VECTOR_VALUETYPE));
+ }
+
+ /// Return true if this is an integer or a vector integer type.
+ bool isInteger() const {
+ return ((SimpleTy >= MVT::FIRST_INTEGER_VALUETYPE &&
+ SimpleTy <= MVT::LAST_INTEGER_VALUETYPE) ||
+ (SimpleTy >= MVT::FIRST_INTEGER_VECTOR_VALUETYPE &&
+ SimpleTy <= MVT::LAST_INTEGER_VECTOR_VALUETYPE));
+ }
+
+ /// Return true if this is an integer, not including vectors.
+ bool isScalarInteger() const {
+ return (SimpleTy >= MVT::FIRST_INTEGER_VALUETYPE &&
+ SimpleTy <= MVT::LAST_INTEGER_VALUETYPE);
+ }
+
+ /// Return true if this is a vector value type.
+ bool isVector() const {
+ return (SimpleTy >= MVT::FIRST_VECTOR_VALUETYPE &&
+ SimpleTy <= MVT::LAST_VECTOR_VALUETYPE);
+ }
+
+ /// Return true if this is a vector value type where the
+ /// runtime length is machine dependent
+ bool isScalableVector() const {
+ return ((SimpleTy >= MVT::FIRST_INTEGER_SCALABLE_VALUETYPE &&
+ SimpleTy <= MVT::LAST_INTEGER_SCALABLE_VALUETYPE) ||
+ (SimpleTy >= MVT::FIRST_FP_SCALABLE_VALUETYPE &&
+ SimpleTy <= MVT::LAST_FP_SCALABLE_VALUETYPE));
+ }
+
+ /// Return true if this is a 16-bit vector type.
+ bool is16BitVector() const {
+ return (SimpleTy == MVT::v2i8 || SimpleTy == MVT::v1i16 ||
+ SimpleTy == MVT::v16i1);
+ }
+
+ /// Return true if this is a 32-bit vector type.
+ bool is32BitVector() const {
+ return (SimpleTy == MVT::v32i1 || SimpleTy == MVT::v4i8 ||
+ SimpleTy == MVT::v2i16 || SimpleTy == MVT::v1i32 ||
+ SimpleTy == MVT::v2f16 || SimpleTy == MVT::v1f32);
+ }
+
+ /// Return true if this is a 64-bit vector type.
+ bool is64BitVector() const {
+ return (SimpleTy == MVT::v64i1 || SimpleTy == MVT::v8i8 ||
+ SimpleTy == MVT::v4i16 || SimpleTy == MVT::v2i32 ||
+ SimpleTy == MVT::v1i64 || SimpleTy == MVT::v4f16 ||
+ SimpleTy == MVT::v2f32 || SimpleTy == MVT::v1f64);
+ }
+
+ /// Return true if this is a 128-bit vector type.
+ bool is128BitVector() const {
+ return (SimpleTy == MVT::v128i1 || SimpleTy == MVT::v16i8 ||
+ SimpleTy == MVT::v8i16 || SimpleTy == MVT::v4i32 ||
+ SimpleTy == MVT::v2i64 || SimpleTy == MVT::v1i128 ||
+ SimpleTy == MVT::v8f16 || SimpleTy == MVT::v4f32 ||
+ SimpleTy == MVT::v2f64);
+ }
+
+ /// Return true if this is a 256-bit vector type.
+ bool is256BitVector() const {
+ return (SimpleTy == MVT::v8f32 || SimpleTy == MVT::v4f64 ||
+ SimpleTy == MVT::v32i8 || SimpleTy == MVT::v16i16 ||
+ SimpleTy == MVT::v8i32 || SimpleTy == MVT::v4i64);
+ }
+
+ /// Return true if this is a 512-bit vector type.
+ bool is512BitVector() const {
+ return (SimpleTy == MVT::v16f32 || SimpleTy == MVT::v8f64 ||
+ SimpleTy == MVT::v512i1 || SimpleTy == MVT::v64i8 ||
+ SimpleTy == MVT::v32i16 || SimpleTy == MVT::v16i32 ||
+ SimpleTy == MVT::v8i64);
+ }
+
+ /// Return true if this is a 1024-bit vector type.
+ bool is1024BitVector() const {
+ return (SimpleTy == MVT::v1024i1 || SimpleTy == MVT::v128i8 ||
+ SimpleTy == MVT::v64i16 || SimpleTy == MVT::v32i32 ||
+ SimpleTy == MVT::v16i64);
+ }
+
+ /// Return true if this is a 2048-bit vector type.
+ bool is2048BitVector() const {
+ return (SimpleTy == MVT::v256i8 || SimpleTy == MVT::v128i16 ||
+ SimpleTy == MVT::v64i32 || SimpleTy == MVT::v32i64);
+ }
+
+ /// Return true if this is an overloaded type for TableGen.
+ bool isOverloaded() const {
+ return (SimpleTy==MVT::Any ||
+ SimpleTy==MVT::iAny || SimpleTy==MVT::fAny ||
+ SimpleTy==MVT::vAny || SimpleTy==MVT::iPTRAny);
+ }
+
+ /// Returns true if the given vector is a power of 2.
+ bool isPow2VectorType() const {
+ unsigned NElts = getVectorNumElements();
+ return !(NElts & (NElts - 1));
+ }
+
+ /// Widens the length of the given vector MVT up to the nearest power of 2
+ /// and returns that type.
+ MVT getPow2VectorType() const {
+ if (isPow2VectorType())
+ return *this;
+
+ unsigned NElts = getVectorNumElements();
+ unsigned Pow2NElts = 1 << Log2_32_Ceil(NElts);
+ return MVT::getVectorVT(getVectorElementType(), Pow2NElts);
+ }
+
+ /// If this is a vector, return the element type, otherwise return this.
+ MVT getScalarType() const {
+ return isVector() ? getVectorElementType() : *this;
+ }
+
+ MVT getVectorElementType() const {
+ switch (SimpleTy) {
+ default:
+ llvm_unreachable("Not a vector MVT!");
+ case v1i1:
+ case v2i1:
+ case v4i1:
+ case v8i1:
+ case v16i1:
+ case v32i1:
+ case v64i1:
+ case v128i1:
+ case v512i1:
+ case v1024i1:
+ case nxv1i1:
+ case nxv2i1:
+ case nxv4i1:
+ case nxv8i1:
+ case nxv16i1:
+ case nxv32i1: return i1;
+ case v1i8:
+ case v2i8:
+ case v4i8:
+ case v8i8:
+ case v16i8:
+ case v32i8:
+ case v64i8:
+ case v128i8:
+ case v256i8:
+ case nxv1i8:
+ case nxv2i8:
+ case nxv4i8:
+ case nxv8i8:
+ case nxv16i8:
+ case nxv32i8: return i8;
+ case v1i16:
+ case v2i16:
+ case v4i16:
+ case v8i16:
+ case v16i16:
+ case v32i16:
+ case v64i16:
+ case v128i16:
+ case nxv1i16:
+ case nxv2i16:
+ case nxv4i16:
+ case nxv8i16:
+ case nxv16i16:
+ case nxv32i16: return i16;
+ case v1i32:
+ case v2i32:
+ case v4i32:
+ case v8i32:
+ case v16i32:
+ case v32i32:
+ case v64i32:
+ case nxv1i32:
+ case nxv2i32:
+ case nxv4i32:
+ case nxv8i32:
+ case nxv16i32:
+ case nxv32i32: return i32;
+ case v1i64:
+ case v2i64:
+ case v4i64:
+ case v8i64:
+ case v16i64:
+ case v32i64:
+ case nxv1i64:
+ case nxv2i64:
+ case nxv4i64:
+ case nxv8i64:
+ case nxv16i64:
+ case nxv32i64: return i64;
+ case v1i128: return i128;
+ case v2f16:
+ case v4f16:
+ case v8f16:
+ case nxv2f16:
+ case nxv4f16:
+ case nxv8f16: return f16;
+ case v1f32:
+ case v2f32:
+ case v4f32:
+ case v8f32:
+ case v16f32:
+ case nxv1f32:
+ case nxv2f32:
+ case nxv4f32:
+ case nxv8f32:
+ case nxv16f32: return f32;
+ case v1f64:
+ case v2f64:
+ case v4f64:
+ case v8f64:
+ case nxv1f64:
+ case nxv2f64:
+ case nxv4f64:
+ case nxv8f64: return f64;
+ }
+ }
+
+ unsigned getVectorNumElements() const {
+ switch (SimpleTy) {
+ default:
+ llvm_unreachable("Not a vector MVT!");
+ case v1024i1: return 1024;
+ case v512i1: return 512;
+ case v256i8: return 256;
+ case v128i1:
+ case v128i8:
+ case v128i16: return 128;
+ case v64i1:
+ case v64i8:
+ case v64i16:
+ case v64i32: return 64;
+ case v32i1:
+ case v32i8:
+ case v32i16:
+ case v32i32:
+ case v32i64:
+ case nxv32i1:
+ case nxv32i8:
+ case nxv32i16:
+ case nxv32i32:
+ case nxv32i64: return 32;
+ case v16i1:
+ case v16i8:
+ case v16i16:
+ case v16i32:
+ case v16i64:
+ case v16f32:
+ case nxv16i1:
+ case nxv16i8:
+ case nxv16i16:
+ case nxv16i32:
+ case nxv16i64:
+ case nxv16f32: return 16;
+ case v8i1:
+ case v8i8:
+ case v8i16:
+ case v8i32:
+ case v8i64:
+ case v8f16:
+ case v8f32:
+ case v8f64:
+ case nxv8i1:
+ case nxv8i8:
+ case nxv8i16:
+ case nxv8i32:
+ case nxv8i64:
+ case nxv8f16:
+ case nxv8f32:
+ case nxv8f64: return 8;
+ case v4i1:
+ case v4i8:
+ case v4i16:
+ case v4i32:
+ case v4i64:
+ case v4f16:
+ case v4f32:
+ case v4f64:
+ case nxv4i1:
+ case nxv4i8:
+ case nxv4i16:
+ case nxv4i32:
+ case nxv4i64:
+ case nxv4f16:
+ case nxv4f32:
+ case nxv4f64: return 4;
+ case v2i1:
+ case v2i8:
+ case v2i16:
+ case v2i32:
+ case v2i64:
+ case v2f16:
+ case v2f32:
+ case v2f64:
+ case nxv2i1:
+ case nxv2i8:
+ case nxv2i16:
+ case nxv2i32:
+ case nxv2i64:
+ case nxv2f16:
+ case nxv2f32:
+ case nxv2f64: return 2;
+ case v1i1:
+ case v1i8:
+ case v1i16:
+ case v1i32:
+ case v1i64:
+ case v1i128:
+ case v1f32:
+ case v1f64:
+ case nxv1i1:
+ case nxv1i8:
+ case nxv1i16:
+ case nxv1i32:
+ case nxv1i64:
+ case nxv1f32:
+ case nxv1f64: return 1;
+ }
+ }
+
+ MVT::ElementCount getVectorElementCount() const {
+ return { getVectorNumElements(), isScalableVector() };
+ }
+
+ unsigned getSizeInBits() const {
+ switch (SimpleTy) {
+ default:
+ llvm_unreachable("getSizeInBits called on extended MVT.");
+ case Other:
+ llvm_unreachable("Value type is non-standard value, Other.");
+ case iPTR:
+ llvm_unreachable("Value type size is target-dependent. Ask TLI.");
+ case iPTRAny:
+ case iAny:
+ case fAny:
+ case vAny:
+ case Any:
+ llvm_unreachable("Value type is overloaded.");
+ case token:
+ llvm_unreachable("Token type is a sentinel that cannot be used "
+ "in codegen and has no size");
+ case Metadata:
+ llvm_unreachable("Value type is metadata.");
+ case i1:
+ case v1i1:
+ case nxv1i1: return 1;
+ case v2i1:
+ case nxv2i1: return 2;
+ case v4i1:
+ case nxv4i1: return 4;
+ case i8 :
+ case v1i8:
+ case v8i1:
+ case nxv1i8:
+ case nxv8i1: return 8;
+ case i16 :
+ case f16:
+ case v16i1:
+ case v2i8:
+ case v1i16:
+ case nxv16i1:
+ case nxv2i8:
+ case nxv1i16: return 16;
+ case f32 :
+ case i32 :
+ case v32i1:
+ case v4i8:
+ case v2i16:
+ case v2f16:
+ case v1f32:
+ case v1i32:
+ case nxv32i1:
+ case nxv4i8:
+ case nxv2i16:
+ case nxv1i32:
+ case nxv2f16:
+ case nxv1f32: return 32;
+ case x86mmx:
+ case f64 :
+ case i64 :
+ case v64i1:
+ case v8i8:
+ case v4i16:
+ case v2i32:
+ case v1i64:
+ case v4f16:
+ case v2f32:
+ case v1f64:
+ case nxv8i8:
+ case nxv4i16:
+ case nxv2i32:
+ case nxv1i64:
+ case nxv4f16:
+ case nxv2f32:
+ case nxv1f64: return 64;
+ case f80 : return 80;
+ case f128:
+ case ppcf128:
+ case i128:
+ case v128i1:
+ case v16i8:
+ case v8i16:
+ case v4i32:
+ case v2i64:
+ case v1i128:
+ case v8f16:
+ case v4f32:
+ case v2f64:
+ case nxv16i8:
+ case nxv8i16:
+ case nxv4i32:
+ case nxv2i64:
+ case nxv8f16:
+ case nxv4f32:
+ case nxv2f64: return 128;
+ case v32i8:
+ case v16i16:
+ case v8i32:
+ case v4i64:
+ case v8f32:
+ case v4f64:
+ case nxv32i8:
+ case nxv16i16:
+ case nxv8i32:
+ case nxv4i64:
+ case nxv8f32:
+ case nxv4f64: return 256;
+ case v512i1:
+ case v64i8:
+ case v32i16:
+ case v16i32:
+ case v8i64:
+ case v16f32:
+ case v8f64:
+ case nxv32i16:
+ case nxv16i32:
+ case nxv8i64:
+ case nxv16f32:
+ case nxv8f64: return 512;
+ case v1024i1:
+ case v128i8:
+ case v64i16:
+ case v32i32:
+ case v16i64:
+ case nxv32i32:
+ case nxv16i64: return 1024;
+ case v256i8:
+ case v128i16:
+ case v64i32:
+ case v32i64:
+ case nxv32i64: return 2048;
+ case ExceptRef: return 0; // opaque type
+ }
+ }
+
+ unsigned getScalarSizeInBits() const {
+ return getScalarType().getSizeInBits();
+ }
+
+ /// Return the number of bytes overwritten by a store of the specified value
+ /// type.
+ unsigned getStoreSize() const {
+ return (getSizeInBits() + 7) / 8;
+ }
+
+ /// Return the number of bits overwritten by a store of the specified value
+ /// type.
+ unsigned getStoreSizeInBits() const {
+ return getStoreSize() * 8;
+ }
+
+ /// Return true if this has more bits than VT.
+ bool bitsGT(MVT VT) const {
+ return getSizeInBits() > VT.getSizeInBits();
+ }
+
+ /// Return true if this has no less bits than VT.
+ bool bitsGE(MVT VT) const {
+ return getSizeInBits() >= VT.getSizeInBits();
+ }
+
+ /// Return true if this has less bits than VT.
+ bool bitsLT(MVT VT) const {
+ return getSizeInBits() < VT.getSizeInBits();
+ }
+
+ /// Return true if this has no more bits than VT.
+ bool bitsLE(MVT VT) const {
+ return getSizeInBits() <= VT.getSizeInBits();
+ }
+
+ static MVT getFloatingPointVT(unsigned BitWidth) {
+ switch (BitWidth) {
+ default:
+ llvm_unreachable("Bad bit width!");
+ case 16:
+ return MVT::f16;
+ case 32:
+ return MVT::f32;
+ case 64:
+ return MVT::f64;
+ case 80:
+ return MVT::f80;
+ case 128:
+ return MVT::f128;
+ }
+ }
+
+ static MVT getIntegerVT(unsigned BitWidth) {
+ switch (BitWidth) {
+ default:
+ return (MVT::SimpleValueType)(MVT::INVALID_SIMPLE_VALUE_TYPE);
+ case 1:
+ return MVT::i1;
+ case 8:
+ return MVT::i8;
+ case 16:
+ return MVT::i16;
+ case 32:
+ return MVT::i32;
+ case 64:
+ return MVT::i64;
+ case 128:
+ return MVT::i128;
+ }
+ }
+
+ static MVT getVectorVT(MVT VT, unsigned NumElements) {
+ switch (VT.SimpleTy) {
+ default:
+ break;
+ case MVT::i1:
+ if (NumElements == 1) return MVT::v1i1;
+ if (NumElements == 2) return MVT::v2i1;
+ if (NumElements == 4) return MVT::v4i1;
+ if (NumElements == 8) return MVT::v8i1;
+ if (NumElements == 16) return MVT::v16i1;
+ if (NumElements == 32) return MVT::v32i1;
+ if (NumElements == 64) return MVT::v64i1;
+ if (NumElements == 128) return MVT::v128i1;
+ if (NumElements == 512) return MVT::v512i1;
+ if (NumElements == 1024) return MVT::v1024i1;
+ break;
+ case MVT::i8:
+ if (NumElements == 1) return MVT::v1i8;
+ if (NumElements == 2) return MVT::v2i8;
+ if (NumElements == 4) return MVT::v4i8;
+ if (NumElements == 8) return MVT::v8i8;
+ if (NumElements == 16) return MVT::v16i8;
+ if (NumElements == 32) return MVT::v32i8;
+ if (NumElements == 64) return MVT::v64i8;
+ if (NumElements == 128) return MVT::v128i8;
+ if (NumElements == 256) return MVT::v256i8;
+ break;
+ case MVT::i16:
+ if (NumElements == 1) return MVT::v1i16;
+ if (NumElements == 2) return MVT::v2i16;
+ if (NumElements == 4) return MVT::v4i16;
+ if (NumElements == 8) return MVT::v8i16;
+ if (NumElements == 16) return MVT::v16i16;
+ if (NumElements == 32) return MVT::v32i16;
+ if (NumElements == 64) return MVT::v64i16;
+ if (NumElements == 128) return MVT::v128i16;
+ break;
+ case MVT::i32:
+ if (NumElements == 1) return MVT::v1i32;
+ if (NumElements == 2) return MVT::v2i32;
+ if (NumElements == 4) return MVT::v4i32;
+ if (NumElements == 8) return MVT::v8i32;
+ if (NumElements == 16) return MVT::v16i32;
+ if (NumElements == 32) return MVT::v32i32;
+ if (NumElements == 64) return MVT::v64i32;
+ break;
+ case MVT::i64:
+ if (NumElements == 1) return MVT::v1i64;
+ if (NumElements == 2) return MVT::v2i64;
+ if (NumElements == 4) return MVT::v4i64;
+ if (NumElements == 8) return MVT::v8i64;
+ if (NumElements == 16) return MVT::v16i64;
+ if (NumElements == 32) return MVT::v32i64;
+ break;
+ case MVT::i128:
+ if (NumElements == 1) return MVT::v1i128;
+ break;
+ case MVT::f16:
+ if (NumElements == 2) return MVT::v2f16;
+ if (NumElements == 4) return MVT::v4f16;
+ if (NumElements == 8) return MVT::v8f16;
+ break;
+ case MVT::f32:
+ if (NumElements == 1) return MVT::v1f32;
+ if (NumElements == 2) return MVT::v2f32;
+ if (NumElements == 4) return MVT::v4f32;
+ if (NumElements == 8) return MVT::v8f32;
+ if (NumElements == 16) return MVT::v16f32;
+ break;
+ case MVT::f64:
+ if (NumElements == 1) return MVT::v1f64;
+ if (NumElements == 2) return MVT::v2f64;
+ if (NumElements == 4) return MVT::v4f64;
+ if (NumElements == 8) return MVT::v8f64;
+ break;
+ }
+ return (MVT::SimpleValueType)(MVT::INVALID_SIMPLE_VALUE_TYPE);
+ }
+
+ static MVT getScalableVectorVT(MVT VT, unsigned NumElements) {
+ switch(VT.SimpleTy) {
+ default:
+ break;
+ case MVT::i1:
+ if (NumElements == 1) return MVT::nxv1i1;
+ if (NumElements == 2) return MVT::nxv2i1;
+ if (NumElements == 4) return MVT::nxv4i1;
+ if (NumElements == 8) return MVT::nxv8i1;
+ if (NumElements == 16) return MVT::nxv16i1;
+ if (NumElements == 32) return MVT::nxv32i1;
+ break;
+ case MVT::i8:
+ if (NumElements == 1) return MVT::nxv1i8;
+ if (NumElements == 2) return MVT::nxv2i8;
+ if (NumElements == 4) return MVT::nxv4i8;
+ if (NumElements == 8) return MVT::nxv8i8;
+ if (NumElements == 16) return MVT::nxv16i8;
+ if (NumElements == 32) return MVT::nxv32i8;
+ break;
+ case MVT::i16:
+ if (NumElements == 1) return MVT::nxv1i16;
+ if (NumElements == 2) return MVT::nxv2i16;
+ if (NumElements == 4) return MVT::nxv4i16;
+ if (NumElements == 8) return MVT::nxv8i16;
+ if (NumElements == 16) return MVT::nxv16i16;
+ if (NumElements == 32) return MVT::nxv32i16;
+ break;
+ case MVT::i32:
+ if (NumElements == 1) return MVT::nxv1i32;
+ if (NumElements == 2) return MVT::nxv2i32;
+ if (NumElements == 4) return MVT::nxv4i32;
+ if (NumElements == 8) return MVT::nxv8i32;
+ if (NumElements == 16) return MVT::nxv16i32;
+ if (NumElements == 32) return MVT::nxv32i32;
+ break;
+ case MVT::i64:
+ if (NumElements == 1) return MVT::nxv1i64;
+ if (NumElements == 2) return MVT::nxv2i64;
+ if (NumElements == 4) return MVT::nxv4i64;
+ if (NumElements == 8) return MVT::nxv8i64;
+ if (NumElements == 16) return MVT::nxv16i64;
+ if (NumElements == 32) return MVT::nxv32i64;
+ break;
+ case MVT::f16:
+ if (NumElements == 2) return MVT::nxv2f16;
+ if (NumElements == 4) return MVT::nxv4f16;
+ if (NumElements == 8) return MVT::nxv8f16;
+ break;
+ case MVT::f32:
+ if (NumElements == 1) return MVT::nxv1f32;
+ if (NumElements == 2) return MVT::nxv2f32;
+ if (NumElements == 4) return MVT::nxv4f32;
+ if (NumElements == 8) return MVT::nxv8f32;
+ if (NumElements == 16) return MVT::nxv16f32;
+ break;
+ case MVT::f64:
+ if (NumElements == 1) return MVT::nxv1f64;
+ if (NumElements == 2) return MVT::nxv2f64;
+ if (NumElements == 4) return MVT::nxv4f64;
+ if (NumElements == 8) return MVT::nxv8f64;
+ break;
+ }
+ return (MVT::SimpleValueType)(MVT::INVALID_SIMPLE_VALUE_TYPE);
+ }
+
+ static MVT getVectorVT(MVT VT, unsigned NumElements, bool IsScalable) {
+ if (IsScalable)
+ return getScalableVectorVT(VT, NumElements);
+ return getVectorVT(VT, NumElements);
+ }
+
+ static MVT getVectorVT(MVT VT, MVT::ElementCount EC) {
+ if (EC.Scalable)
+ return getScalableVectorVT(VT, EC.Min);
+ return getVectorVT(VT, EC.Min);
+ }
+
+ /// Return the value type corresponding to the specified type. This returns
+ /// all pointers as iPTR. If HandleUnknown is true, unknown types are
+ /// returned as Other, otherwise they are invalid.
+ static MVT getVT(Type *Ty, bool HandleUnknown = false);
+
+ private:
+ /// A simple iterator over the MVT::SimpleValueType enum.
+ struct mvt_iterator {
+ SimpleValueType VT;
+
+ mvt_iterator(SimpleValueType VT) : VT(VT) {}
+
+ MVT operator*() const { return VT; }
+ bool operator!=(const mvt_iterator &LHS) const { return VT != LHS.VT; }
+
+ mvt_iterator& operator++() {
+ VT = (MVT::SimpleValueType)((int)VT + 1);
+ assert((int)VT <= MVT::MAX_ALLOWED_VALUETYPE &&
+ "MVT iterator overflowed.");
+ return *this;
+ }
+ };
+
+ /// A range of the MVT::SimpleValueType enum.
+ using mvt_range = iterator_range<mvt_iterator>;
+
+ public:
+ /// SimpleValueType Iteration
+ /// @{
+ static mvt_range all_valuetypes() {
+ return mvt_range(MVT::FIRST_VALUETYPE, MVT::LAST_VALUETYPE);
+ }
+
+ static mvt_range integer_valuetypes() {
+ return mvt_range(MVT::FIRST_INTEGER_VALUETYPE,
+ (MVT::SimpleValueType)(MVT::LAST_INTEGER_VALUETYPE + 1));
+ }
+
+ static mvt_range fp_valuetypes() {
+ return mvt_range(MVT::FIRST_FP_VALUETYPE,
+ (MVT::SimpleValueType)(MVT::LAST_FP_VALUETYPE + 1));
+ }
+
+ static mvt_range vector_valuetypes() {
+ return mvt_range(MVT::FIRST_VECTOR_VALUETYPE,
+ (MVT::SimpleValueType)(MVT::LAST_VECTOR_VALUETYPE + 1));
+ }
+
+ static mvt_range integer_vector_valuetypes() {
+ return mvt_range(
+ MVT::FIRST_INTEGER_VECTOR_VALUETYPE,
+ (MVT::SimpleValueType)(MVT::LAST_INTEGER_VECTOR_VALUETYPE + 1));
+ }
+
+ static mvt_range fp_vector_valuetypes() {
+ return mvt_range(
+ MVT::FIRST_FP_VECTOR_VALUETYPE,
+ (MVT::SimpleValueType)(MVT::LAST_FP_VECTOR_VALUETYPE + 1));
+ }
+
+ static mvt_range integer_scalable_vector_valuetypes() {
+ return mvt_range(MVT::FIRST_INTEGER_SCALABLE_VALUETYPE,
+ (MVT::SimpleValueType)(MVT::LAST_INTEGER_SCALABLE_VALUETYPE + 1));
+ }
+
+ static mvt_range fp_scalable_vector_valuetypes() {
+ return mvt_range(MVT::FIRST_FP_SCALABLE_VALUETYPE,
+ (MVT::SimpleValueType)(MVT::LAST_FP_SCALABLE_VALUETYPE + 1));
+ }
+ /// @}
+ };
+
+} // end namespace llvm
+
+#endif // LLVM_CODEGEN_MACHINEVALUETYPE_H
diff --git a/include/llvm/Support/MathExtras.h b/include/llvm/Support/MathExtras.h
index a37a16784e2a..b59f21b4998e 100644
--- a/include/llvm/Support/MathExtras.h
+++ b/include/llvm/Support/MathExtras.h
@@ -23,22 +23,30 @@
#include <limits>
#include <type_traits>
-#ifdef _MSC_VER
-#include <intrin.h>
-#endif
-
#ifdef __ANDROID_NDK__
#include <android/api-level.h>
#endif
+#ifdef _MSC_VER
+// Declare these intrinsics manually rather including intrin.h. It's very
+// expensive, and MathExtras.h is popular.
+// #include <intrin.h>
+extern "C" {
+unsigned char _BitScanForward(unsigned long *_Index, unsigned long _Mask);
+unsigned char _BitScanForward64(unsigned long *_Index, unsigned __int64 _Mask);
+unsigned char _BitScanReverse(unsigned long *_Index, unsigned long _Mask);
+unsigned char _BitScanReverse64(unsigned long *_Index, unsigned __int64 _Mask);
+}
+#endif
+
namespace llvm {
-/// \brief The behavior an operation has on an input of 0.
+/// The behavior an operation has on an input of 0.
enum ZeroBehavior {
- /// \brief The returned value is undefined.
+ /// The returned value is undefined.
ZB_Undefined,
- /// \brief The returned value is numeric_limits<T>::max()
+ /// The returned value is numeric_limits<T>::max()
ZB_Max,
- /// \brief The returned value is numeric_limits<T>::digits
+ /// The returned value is numeric_limits<T>::digits
ZB_Width
};
@@ -101,7 +109,7 @@ template <typename T> struct TrailingZerosCounter<T, 8> {
#endif
} // namespace detail
-/// \brief Count number of 0's from the least significant bit to the most
+/// Count number of 0's from the least significant bit to the most
/// stopping at the first 1.
///
/// Only unsigned integral types are allowed.
@@ -170,7 +178,7 @@ template <typename T> struct LeadingZerosCounter<T, 8> {
#endif
} // namespace detail
-/// \brief Count number of 0's from the most significant bit to the least
+/// Count number of 0's from the most significant bit to the least
/// stopping at the first 1.
///
/// Only unsigned integral types are allowed.
@@ -185,7 +193,7 @@ std::size_t countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
return llvm::detail::LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB);
}
-/// \brief Get the index of the first set bit starting from the least
+/// Get the index of the first set bit starting from the least
/// significant bit.
///
/// Only unsigned integral types are allowed.
@@ -199,7 +207,7 @@ template <typename T> T findFirstSet(T Val, ZeroBehavior ZB = ZB_Max) {
return countTrailingZeros(Val, ZB_Undefined);
}
-/// \brief Create a bitmask with the N right-most bits set to 1, and all other
+/// Create a bitmask with the N right-most bits set to 1, and all other
/// bits set to 0. Only unsigned types are allowed.
template <typename T> T maskTrailingOnes(unsigned N) {
static_assert(std::is_unsigned<T>::value, "Invalid type!");
@@ -208,25 +216,25 @@ template <typename T> T maskTrailingOnes(unsigned N) {
return N == 0 ? 0 : (T(-1) >> (Bits - N));
}
-/// \brief Create a bitmask with the N left-most bits set to 1, and all other
+/// Create a bitmask with the N left-most bits set to 1, and all other
/// bits set to 0. Only unsigned types are allowed.
template <typename T> T maskLeadingOnes(unsigned N) {
return ~maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
}
-/// \brief Create a bitmask with the N right-most bits set to 0, and all other
+/// Create a bitmask with the N right-most bits set to 0, and all other
/// bits set to 1. Only unsigned types are allowed.
template <typename T> T maskTrailingZeros(unsigned N) {
return maskLeadingOnes<T>(CHAR_BIT * sizeof(T) - N);
}
-/// \brief Create a bitmask with the N left-most bits set to 0, and all other
+/// Create a bitmask with the N left-most bits set to 0, and all other
/// bits set to 1. Only unsigned types are allowed.
template <typename T> T maskLeadingZeros(unsigned N) {
return maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
}
-/// \brief Get the index of the last set bit starting from the least
+/// Get the index of the last set bit starting from the least
/// significant bit.
///
/// Only unsigned integral types are allowed.
@@ -243,7 +251,7 @@ template <typename T> T findLastSet(T Val, ZeroBehavior ZB = ZB_Max) {
(std::numeric_limits<T>::digits - 1);
}
-/// \brief Macro compressed bit reversal table for 256 bits.
+/// Macro compressed bit reversal table for 256 bits.
///
/// http://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
static const unsigned char BitReverseTable256[256] = {
@@ -256,7 +264,7 @@ static const unsigned char BitReverseTable256[256] = {
#undef R6
};
-/// \brief Reverse the bits in \p Val.
+/// Reverse the bits in \p Val.
template <typename T>
T reverseBits(T Val) {
unsigned char in[sizeof(Val)];
@@ -442,7 +450,7 @@ inline uint64_t ByteSwap_64(uint64_t Value) {
return sys::SwapByteOrder_64(Value);
}
-/// \brief Count the number of ones from the most significant bit to the first
+/// Count the number of ones from the most significant bit to the first
/// zero bit.
///
/// Ex. countLeadingOnes(0xFF0FFF00) == 8.
@@ -455,10 +463,10 @@ std::size_t countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
static_assert(std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed,
"Only unsigned integral types are allowed.");
- return countLeadingZeros(~Value, ZB);
+ return countLeadingZeros<T>(~Value, ZB);
}
-/// \brief Count the number of ones from the least significant bit to the first
+/// Count the number of ones from the least significant bit to the first
/// zero bit.
///
/// Ex. countTrailingOnes(0x00FF00FF) == 8.
@@ -471,7 +479,7 @@ std::size_t countTrailingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
static_assert(std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed,
"Only unsigned integral types are allowed.");
- return countTrailingZeros(~Value, ZB);
+ return countTrailingZeros<T>(~Value, ZB);
}
namespace detail {
@@ -505,7 +513,7 @@ template <typename T> struct PopulationCounter<T, 8> {
};
} // namespace detail
-/// \brief Count the number of set bits in a value.
+/// Count the number of set bits in a value.
/// Ex. countPopulation(0xF000F000) = 8
/// Returns 0 if the word is zero.
template <typename T>
@@ -608,7 +616,7 @@ constexpr inline uint64_t MinAlign(uint64_t A, uint64_t B) {
return (A | B) & (1 + ~(A | B));
}
-/// \brief Aligns \c Addr to \c Alignment bytes, rounding up.
+/// Aligns \c Addr to \c Alignment bytes, rounding up.
///
/// Alignment should be a power of two. This method rounds up, so
/// alignAddr(7, 4) == 8 and alignAddr(8, 4) == 8.
@@ -621,7 +629,7 @@ inline uintptr_t alignAddr(const void *Addr, size_t Alignment) {
return (((uintptr_t)Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1));
}
-/// \brief Returns the necessary adjustment for aligning \c Ptr to \c Alignment
+/// Returns the necessary adjustment for aligning \c Ptr to \c Alignment
/// bytes, rounding up.
inline size_t alignmentAdjustment(const void *Ptr, size_t Alignment) {
return alignAddr(Ptr, Alignment) - (uintptr_t)Ptr;
diff --git a/include/llvm/Support/MemAlloc.h b/include/llvm/Support/MemAlloc.h
new file mode 100644
index 000000000000..d06c659cfba6
--- /dev/null
+++ b/include/llvm/Support/MemAlloc.h
@@ -0,0 +1,49 @@
+//===- MemAlloc.h - Memory allocation functions -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// This file defines counterparts of C library allocation functions defined in
+/// the namespace 'std'. The new allocation functions crash on allocation
+/// failure instead of returning null pointer.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_MEMALLOC_H
+#define LLVM_SUPPORT_MEMALLOC_H
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <cstdlib>
+
+namespace llvm {
+
+LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_malloc(size_t Sz) {
+ void *Result = std::malloc(Sz);
+ if (Result == nullptr)
+ report_bad_alloc_error("Allocation failed");
+ return Result;
+}
+
+LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_calloc(size_t Count,
+ size_t Sz) {
+ void *Result = std::calloc(Count, Sz);
+ if (Result == nullptr)
+ report_bad_alloc_error("Allocation failed");
+ return Result;
+}
+
+LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_realloc(void *Ptr, size_t Sz) {
+ void *Result = std::realloc(Ptr, Sz);
+ if (Result == nullptr)
+ report_bad_alloc_error("Allocation failed");
+ return Result;
+}
+
+}
+#endif
diff --git a/include/llvm/Support/Memory.h b/include/llvm/Support/Memory.h
index 3140dc6eef42..fa026d49a61b 100644
--- a/include/llvm/Support/Memory.h
+++ b/include/llvm/Support/Memory.h
@@ -25,7 +25,7 @@ namespace sys {
/// and a size. It is used by the Memory class (a friend) as the result of
/// various memory allocation operations.
/// @see Memory
- /// @brief Memory block abstraction.
+ /// Memory block abstraction.
class MemoryBlock {
public:
MemoryBlock() : Address(nullptr), Size(0) { }
@@ -42,7 +42,7 @@ namespace sys {
/// This class provides various memory handling functions that manipulate
/// MemoryBlock instances.
/// @since 1.4
- /// @brief An abstraction for memory operations.
+ /// An abstraction for memory operations.
class Memory {
public:
enum ProtectionFlags {
@@ -74,7 +74,7 @@ namespace sys {
/// \r a non-null MemoryBlock if the function was successful,
/// otherwise a null MemoryBlock is with \p EC describing the error.
///
- /// @brief Allocate mapped memory.
+ /// Allocate mapped memory.
static MemoryBlock allocateMappedMemory(size_t NumBytes,
const MemoryBlock *const NearBlock,
unsigned Flags,
@@ -88,7 +88,7 @@ namespace sys {
/// \r error_success if the function was successful, or an error_code
/// describing the failure if an error occurred.
///
- /// @brief Release mapped memory.
+ /// Release mapped memory.
static std::error_code releaseMappedMemory(MemoryBlock &Block);
/// This method sets the protection flags for a block of memory to the
@@ -105,7 +105,7 @@ namespace sys {
/// \r error_success if the function was successful, or an error_code
/// describing the failure if an error occurred.
///
- /// @brief Set memory protection state.
+ /// Set memory protection state.
static std::error_code protectMappedMemory(const MemoryBlock &Block,
unsigned Flags);
diff --git a/include/llvm/Support/MemoryBuffer.h b/include/llvm/Support/MemoryBuffer.h
index 7b849fdb8670..535579ecff53 100644
--- a/include/llvm/Support/MemoryBuffer.h
+++ b/include/llvm/Support/MemoryBuffer.h
@@ -20,6 +20,7 @@
#include "llvm/ADT/Twine.h"
#include "llvm/Support/CBindingWrapping.h"
#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
#include <cstddef>
#include <cstdint>
#include <memory>
@@ -49,7 +50,8 @@ protected:
void init(const char *BufStart, const char *BufEnd,
bool RequiresNullTerminator);
- static constexpr bool Writable = false;
+ static constexpr sys::fs::mapped_file_region::mapmode Mapmode =
+ sys::fs::mapped_file_region::readonly;
public:
MemoryBuffer(const MemoryBuffer &) = delete;
@@ -117,12 +119,6 @@ public:
static std::unique_ptr<MemoryBuffer>
getMemBufferCopy(StringRef InputData, const Twine &BufferName = "");
- /// Allocate a new zero-initialized MemoryBuffer of the specified size. Note
- /// that the caller need not initialize the memory allocated by this method.
- /// The memory is owned by the MemoryBuffer object.
- static std::unique_ptr<MemoryBuffer>
- getNewMemBuffer(size_t Size, StringRef BufferName = "");
-
/// Read all of stdin into a file buffer, and return it.
static ErrorOr<std::unique_ptr<MemoryBuffer>> getSTDIN();
@@ -152,17 +148,21 @@ public:
virtual BufferKind getBufferKind() const = 0;
MemoryBufferRef getMemBufferRef() const;
+
+private:
+ virtual void anchor();
};
-/// This class is an extension of MemoryBuffer, which allows writing to the
-/// underlying contents. It only supports creation methods that are guaranteed
-/// to produce a writable buffer. For example, mapping a file read-only is not
-/// supported.
+/// This class is an extension of MemoryBuffer, which allows copy-on-write
+/// access to the underlying contents. It only supports creation methods that
+/// are guaranteed to produce a writable buffer. For example, mapping a file
+/// read-only is not supported.
class WritableMemoryBuffer : public MemoryBuffer {
protected:
WritableMemoryBuffer() = default;
- static constexpr bool Writable = true;
+ static constexpr sys::fs::mapped_file_region::mapmode Mapmode =
+ sys::fs::mapped_file_region::priv;
public:
using MemoryBuffer::getBuffer;
@@ -196,6 +196,60 @@ public:
static std::unique_ptr<WritableMemoryBuffer>
getNewUninitMemBuffer(size_t Size, const Twine &BufferName = "");
+ /// Allocate a new zero-initialized MemoryBuffer of the specified size. Note
+ /// that the caller need not initialize the memory allocated by this method.
+ /// The memory is owned by the MemoryBuffer object.
+ static std::unique_ptr<WritableMemoryBuffer>
+ getNewMemBuffer(size_t Size, const Twine &BufferName = "");
+
+private:
+ // Hide these base class factory function so one can't write
+ // WritableMemoryBuffer::getXXX()
+ // and be surprised that he got a read-only Buffer.
+ using MemoryBuffer::getFileAsStream;
+ using MemoryBuffer::getFileOrSTDIN;
+ using MemoryBuffer::getMemBuffer;
+ using MemoryBuffer::getMemBufferCopy;
+ using MemoryBuffer::getOpenFile;
+ using MemoryBuffer::getOpenFileSlice;
+ using MemoryBuffer::getSTDIN;
+};
+
+/// This class is an extension of MemoryBuffer, which allows write access to
+/// the underlying contents and committing those changes to the original source.
+/// It only supports creation methods that are guaranteed to produce a writable
+/// buffer. For example, mapping a file read-only is not supported.
+class WriteThroughMemoryBuffer : public MemoryBuffer {
+protected:
+ WriteThroughMemoryBuffer() = default;
+
+ static constexpr sys::fs::mapped_file_region::mapmode Mapmode =
+ sys::fs::mapped_file_region::readwrite;
+
+public:
+ using MemoryBuffer::getBuffer;
+ using MemoryBuffer::getBufferEnd;
+ using MemoryBuffer::getBufferStart;
+
+ // const_cast is well-defined here, because the underlying buffer is
+ // guaranteed to have been initialized with a mutable buffer.
+ char *getBufferStart() {
+ return const_cast<char *>(MemoryBuffer::getBufferStart());
+ }
+ char *getBufferEnd() {
+ return const_cast<char *>(MemoryBuffer::getBufferEnd());
+ }
+ MutableArrayRef<char> getBuffer() {
+ return {getBufferStart(), getBufferEnd()};
+ }
+
+ static ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>>
+ getFile(const Twine &Filename, int64_t FileSize = -1);
+
+ /// Map a subrange of the specified file as a ReadWriteMemoryBuffer.
+ static ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>>
+ getFileSlice(const Twine &Filename, uint64_t MapSize, uint64_t Offset);
+
private:
// Hide these base class factory function so one can't write
// WritableMemoryBuffer::getXXX()
@@ -204,7 +258,6 @@ private:
using MemoryBuffer::getFileOrSTDIN;
using MemoryBuffer::getMemBuffer;
using MemoryBuffer::getMemBufferCopy;
- using MemoryBuffer::getNewMemBuffer;
using MemoryBuffer::getOpenFile;
using MemoryBuffer::getOpenFileSlice;
using MemoryBuffer::getSTDIN;
diff --git a/include/llvm/Support/MipsABIFlags.h b/include/llvm/Support/MipsABIFlags.h
index 93f6b416ba88..12c350015b21 100644
--- a/include/llvm/Support/MipsABIFlags.h
+++ b/include/llvm/Support/MipsABIFlags.h
@@ -42,7 +42,9 @@ enum AFL_ASE {
AFL_ASE_MSA = 0x00000200, // MSA ASE
AFL_ASE_MIPS16 = 0x00000400, // MIPS16 ASE
AFL_ASE_MICROMIPS = 0x00000800, // MICROMIPS ASE
- AFL_ASE_XPA = 0x00001000 // XPA ASE
+ AFL_ASE_XPA = 0x00001000, // XPA ASE
+ AFL_ASE_CRC = 0x00008000, // CRC ASE
+ AFL_ASE_GINV = 0x00020000 // GINV ASE
};
// Values for the isa_ext word of an ABI flags structure.
diff --git a/include/llvm/Support/Mutex.h b/include/llvm/Support/Mutex.h
index 0f4e61af4439..680d94b24ef5 100644
--- a/include/llvm/Support/Mutex.h
+++ b/include/llvm/Support/Mutex.h
@@ -14,6 +14,7 @@
#ifndef LLVM_SUPPORT_MUTEX_H
#define LLVM_SUPPORT_MUTEX_H
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Threading.h"
#include <cassert>
@@ -22,7 +23,7 @@ namespace llvm
{
namespace sys
{
- /// @brief Platform agnostic Mutex class.
+ /// Platform agnostic Mutex class.
class MutexImpl
{
/// @name Constructors
@@ -33,11 +34,11 @@ namespace llvm
/// to false, the lock will not be recursive which makes it cheaper but
/// also more likely to deadlock (same thread can't acquire more than
/// once).
- /// @brief Default Constructor.
+ /// Default Constructor.
explicit MutexImpl(bool recursive = true);
/// Releases and removes the lock
- /// @brief Destructor
+ /// Destructor
~MutexImpl();
/// @}
@@ -48,14 +49,14 @@ namespace llvm
/// Attempts to unconditionally acquire the lock. If the lock is held by
/// another thread, this method will wait until it can acquire the lock.
/// @returns false if any kind of error occurs, true otherwise.
- /// @brief Unconditionally acquire the lock.
+ /// Unconditionally acquire the lock.
bool acquire();
/// Attempts to release the lock. If the lock is held by the current
/// thread, the lock is released allowing other threads to acquire the
/// lock.
/// @returns false if any kind of error occurs, true otherwise.
- /// @brief Unconditionally release the lock.
+ /// Unconditionally release the lock.
bool release();
/// Attempts to acquire the lock without blocking. If the lock is not
@@ -63,7 +64,7 @@ namespace llvm
/// the lock is available, it is acquired.
/// @returns false if any kind of error occurs or the lock is not
/// available, true otherwise.
- /// @brief Try to acquire the lock.
+ /// Try to acquire the lock.
bool tryacquire();
//@}
diff --git a/include/llvm/Support/MutexGuard.h b/include/llvm/Support/MutexGuard.h
index 07b64b611960..641d64d94988 100644
--- a/include/llvm/Support/MutexGuard.h
+++ b/include/llvm/Support/MutexGuard.h
@@ -23,7 +23,7 @@ namespace llvm {
/// these on the stack at the top of some scope to be assured that C++
/// destruction of the object will always release the Mutex and thus avoid
/// a host of nasty multi-threading problems in the face of exceptions, etc.
- /// @brief Guard a section of code with a Mutex.
+ /// Guard a section of code with a Mutex.
class MutexGuard {
sys::Mutex &M;
MutexGuard(const MutexGuard &) = delete;
diff --git a/include/llvm/Support/OnDiskHashTable.h b/include/llvm/Support/OnDiskHashTable.h
index e9c28daf03b9..912e2700d1a0 100644
--- a/include/llvm/Support/OnDiskHashTable.h
+++ b/include/llvm/Support/OnDiskHashTable.h
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief Defines facilities for reading and writing on-disk hash tables.
+/// Defines facilities for reading and writing on-disk hash tables.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_ONDISKHASHTABLE_H
@@ -25,7 +25,7 @@
namespace llvm {
-/// \brief Generates an on disk hash table.
+/// Generates an on disk hash table.
///
/// This needs an \c Info that handles storing values into the hash table's
/// payload and computes the hash for a given key. This should provide the
@@ -57,7 +57,7 @@ namespace llvm {
/// };
/// \endcode
template <typename Info> class OnDiskChainedHashTableGenerator {
- /// \brief A single item in the hash table.
+ /// A single item in the hash table.
class Item {
public:
typename Info::key_type Key;
@@ -75,7 +75,7 @@ template <typename Info> class OnDiskChainedHashTableGenerator {
offset_type NumEntries;
llvm::SpecificBumpPtrAllocator<Item> BA;
- /// \brief A linked list of values in a particular hash bucket.
+ /// A linked list of values in a particular hash bucket.
struct Bucket {
offset_type Off;
unsigned Length;
@@ -85,7 +85,7 @@ template <typename Info> class OnDiskChainedHashTableGenerator {
Bucket *Buckets;
private:
- /// \brief Insert an item into the appropriate hash bucket.
+ /// Insert an item into the appropriate hash bucket.
void insert(Bucket *Buckets, size_t Size, Item *E) {
Bucket &B = Buckets[E->Hash & (Size - 1)];
E->Next = B.Head;
@@ -93,9 +93,10 @@ private:
B.Head = E;
}
- /// \brief Resize the hash table, moving the old entries into the new buckets.
+ /// Resize the hash table, moving the old entries into the new buckets.
void resize(size_t NewSize) {
- Bucket *NewBuckets = (Bucket *)std::calloc(NewSize, sizeof(Bucket));
+ Bucket *NewBuckets = static_cast<Bucket *>(
+ safe_calloc(NewSize, sizeof(Bucket)));
// Populate NewBuckets with the old entries.
for (size_t I = 0; I < NumBuckets; ++I)
for (Item *E = Buckets[I].Head; E;) {
@@ -111,14 +112,14 @@ private:
}
public:
- /// \brief Insert an entry into the table.
+ /// Insert an entry into the table.
void insert(typename Info::key_type_ref Key,
typename Info::data_type_ref Data) {
Info InfoObj;
insert(Key, Data, InfoObj);
}
- /// \brief Insert an entry into the table.
+ /// Insert an entry into the table.
///
/// Uses the provided Info instead of a stack allocated one.
void insert(typename Info::key_type_ref Key,
@@ -129,7 +130,7 @@ public:
insert(Buckets, NumBuckets, new (BA.Allocate()) Item(Key, Data, InfoObj));
}
- /// \brief Determine whether an entry has been inserted.
+ /// Determine whether an entry has been inserted.
bool contains(typename Info::key_type_ref Key, Info &InfoObj) {
unsigned Hash = InfoObj.ComputeHash(Key);
for (Item *I = Buckets[Hash & (NumBuckets - 1)].Head; I; I = I->Next)
@@ -138,18 +139,18 @@ public:
return false;
}
- /// \brief Emit the table to Out, which must not be at offset 0.
+ /// Emit the table to Out, which must not be at offset 0.
offset_type Emit(raw_ostream &Out) {
Info InfoObj;
return Emit(Out, InfoObj);
}
- /// \brief Emit the table to Out, which must not be at offset 0.
+ /// Emit the table to Out, which must not be at offset 0.
///
/// Uses the provided Info instead of a stack allocated one.
offset_type Emit(raw_ostream &Out, Info &InfoObj) {
using namespace llvm::support;
- endian::Writer<little> LE(Out);
+ endian::Writer LE(Out, little);
// Now we're done adding entries, resize the bucket list if it's
// significantly too large. (This only happens if the number of
@@ -226,13 +227,13 @@ public:
NumBuckets = 64;
// Note that we do not need to run the constructors of the individual
// Bucket objects since 'calloc' returns bytes that are all 0.
- Buckets = (Bucket *)std::calloc(NumBuckets, sizeof(Bucket));
+ Buckets = static_cast<Bucket *>(safe_calloc(NumBuckets, sizeof(Bucket)));
}
~OnDiskChainedHashTableGenerator() { std::free(Buckets); }
};
-/// \brief Provides lookup on an on disk hash table.
+/// Provides lookup on an on disk hash table.
///
/// This needs an \c Info that handles reading values from the hash table's
/// payload and computes the hash for a given key. This should provide the
@@ -338,14 +339,14 @@ public:
bool operator!=(const iterator &X) const { return X.Data != Data; }
};
- /// \brief Look up the stored data for a particular key.
+ /// Look up the stored data for a particular key.
iterator find(const external_key_type &EKey, Info *InfoPtr = nullptr) {
const internal_key_type &IKey = InfoObj.GetInternalKey(EKey);
hash_value_type KeyHash = InfoObj.ComputeHash(IKey);
return find_hashed(IKey, KeyHash, InfoPtr);
}
- /// \brief Look up the stored data for a particular key with a known hash.
+ /// Look up the stored data for a particular key with a known hash.
iterator find_hashed(const internal_key_type &IKey, hash_value_type KeyHash,
Info *InfoPtr = nullptr) {
using namespace llvm::support;
@@ -403,7 +404,7 @@ public:
Info &getInfoObj() { return InfoObj; }
- /// \brief Create the hash table.
+ /// Create the hash table.
///
/// \param Buckets is the beginning of the hash table itself, which follows
/// the payload of entire structure. This is the value returned by
@@ -423,7 +424,7 @@ public:
}
};
-/// \brief Provides lookup and iteration over an on disk hash table.
+/// Provides lookup and iteration over an on disk hash table.
///
/// \copydetails llvm::OnDiskChainedHashTable
template <typename Info>
@@ -439,7 +440,7 @@ public:
typedef typename base_type::offset_type offset_type;
private:
- /// \brief Iterates over all of the keys in the table.
+ /// Iterates over all of the keys in the table.
class iterator_base {
const unsigned char *Ptr;
offset_type NumItemsInBucketLeft;
@@ -496,7 +497,7 @@ public:
: base_type(NumBuckets, NumEntries, Buckets, Base, InfoObj),
Payload(Payload) {}
- /// \brief Iterates over all of the keys in the table.
+ /// Iterates over all of the keys in the table.
class key_iterator : public iterator_base {
Info *InfoObj;
@@ -542,7 +543,7 @@ public:
return make_range(key_begin(), key_end());
}
- /// \brief Iterates over all the entries in the table, returning the data.
+ /// Iterates over all the entries in the table, returning the data.
class data_iterator : public iterator_base {
Info *InfoObj;
@@ -585,7 +586,7 @@ public:
return make_range(data_begin(), data_end());
}
- /// \brief Create the hash table.
+ /// Create the hash table.
///
/// \param Buckets is the beginning of the hash table itself, which follows
/// the payload of entire structure. This is the value returned by
diff --git a/include/llvm/Support/Options.h b/include/llvm/Support/Options.h
index 9019804d24e0..dd321c6a1984 100644
--- a/include/llvm/Support/Options.h
+++ b/include/llvm/Support/Options.h
@@ -56,7 +56,7 @@ char OptionKey<ValT, Base, Mem>::ID = 0;
} // namespace detail
-/// \brief Singleton class used to register debug options.
+/// Singleton class used to register debug options.
///
/// The OptionRegistry is responsible for managing lifetimes of the options and
/// provides interfaces for option registration and reading values from options.
@@ -66,7 +66,7 @@ class OptionRegistry {
private:
DenseMap<void *, cl::Option *> Options;
- /// \brief Adds a cl::Option to the registry.
+ /// Adds a cl::Option to the registry.
///
/// \param Key unique key for option
/// \param O option to map to \p Key
@@ -79,10 +79,10 @@ public:
~OptionRegistry();
OptionRegistry() {}
- /// \brief Returns a reference to the singleton instance.
+ /// Returns a reference to the singleton instance.
static OptionRegistry &instance();
- /// \brief Registers an option with the OptionRegistry singleton.
+ /// Registers an option with the OptionRegistry singleton.
///
/// \tparam ValT type of the option's data
/// \tparam Base class used to key the option
@@ -100,7 +100,7 @@ public:
instance().addOption(&detail::OptionKey<ValT, Base, Mem>::ID, Option);
}
- /// \brief Returns the value of the option.
+ /// Returns the value of the option.
///
/// \tparam ValT type of the option's data
/// \tparam Base class used to key the option
diff --git a/include/llvm/Support/Parallel.h b/include/llvm/Support/Parallel.h
index 6bc0a6bbaf2b..1462265343be 100644
--- a/include/llvm/Support/Parallel.h
+++ b/include/llvm/Support/Parallel.h
@@ -56,12 +56,12 @@ public:
~Latch() { sync(); }
void inc() {
- std::unique_lock<std::mutex> lock(Mutex);
+ std::lock_guard<std::mutex> lock(Mutex);
++Count;
}
void dec() {
- std::unique_lock<std::mutex> lock(Mutex);
+ std::lock_guard<std::mutex> lock(Mutex);
if (--Count == 0)
Cond.notify_all();
}
@@ -100,7 +100,7 @@ void parallel_for_each_n(IndexTy Begin, IndexTy End, FuncTy Fn) {
#else
const ptrdiff_t MinParallelSize = 1024;
-/// \brief Inclusive median.
+/// Inclusive median.
template <class RandomAccessIterator, class Comparator>
RandomAccessIterator medianOf3(RandomAccessIterator Start,
RandomAccessIterator End,
@@ -118,7 +118,7 @@ void parallel_quick_sort(RandomAccessIterator Start, RandomAccessIterator End,
const Comparator &Comp, TaskGroup &TG, size_t Depth) {
// Do a sequential sort for small inputs.
if (std::distance(Start, End) < detail::MinParallelSize || Depth == 0) {
- std::sort(Start, End, Comp);
+ llvm::sort(Start, End, Comp);
return;
}
@@ -200,7 +200,7 @@ void sort(Policy policy, RandomAccessIterator Start, RandomAccessIterator End,
const Comparator &Comp = Comparator()) {
static_assert(is_execution_policy<Policy>::value,
"Invalid execution policy!");
- std::sort(Start, End, Comp);
+ llvm::sort(Start, End, Comp);
}
template <class Policy, class IterTy, class FuncTy>
diff --git a/include/llvm/Support/Path.h b/include/llvm/Support/Path.h
index e5979674cf1c..c4cc93721d7e 100644
--- a/include/llvm/Support/Path.h
+++ b/include/llvm/Support/Path.h
@@ -20,6 +20,7 @@
#include "llvm/ADT/iterator.h"
#include "llvm/Support/DataTypes.h"
#include <iterator>
+#include <system_error>
namespace llvm {
namespace sys {
@@ -30,7 +31,7 @@ enum class Style { windows, posix, native };
/// @name Lexical Component Iterator
/// @{
-/// @brief Path iterator.
+/// Path iterator.
///
/// This is an input iterator that iterates over the individual components in
/// \a path. The traversal order is as follows:
@@ -66,11 +67,11 @@ public:
const_iterator &operator++(); // preincrement
bool operator==(const const_iterator &RHS) const;
- /// @brief Difference in bytes between this and RHS.
+ /// Difference in bytes between this and RHS.
ptrdiff_t operator-(const const_iterator &RHS) const;
};
-/// @brief Reverse path iterator.
+/// Reverse path iterator.
///
/// This is an input iterator that iterates over the individual components in
/// \a path in reverse order. The traversal order is exactly reversed from that
@@ -91,26 +92,26 @@ public:
reverse_iterator &operator++(); // preincrement
bool operator==(const reverse_iterator &RHS) const;
- /// @brief Difference in bytes between this and RHS.
+ /// Difference in bytes between this and RHS.
ptrdiff_t operator-(const reverse_iterator &RHS) const;
};
-/// @brief Get begin iterator over \a path.
+/// Get begin iterator over \a path.
/// @param path Input path.
/// @returns Iterator initialized with the first component of \a path.
const_iterator begin(StringRef path, Style style = Style::native);
-/// @brief Get end iterator over \a path.
+/// Get end iterator over \a path.
/// @param path Input path.
/// @returns Iterator initialized to the end of \a path.
const_iterator end(StringRef path);
-/// @brief Get reverse begin iterator over \a path.
+/// Get reverse begin iterator over \a path.
/// @param path Input path.
/// @returns Iterator initialized with the first reverse component of \a path.
reverse_iterator rbegin(StringRef path, Style style = Style::native);
-/// @brief Get reverse end iterator over \a path.
+/// Get reverse end iterator over \a path.
/// @param path Input path.
/// @returns Iterator initialized to the reverse end of \a path.
reverse_iterator rend(StringRef path);
@@ -119,7 +120,7 @@ reverse_iterator rend(StringRef path);
/// @name Lexical Modifiers
/// @{
-/// @brief Remove the last component from \a path unless it is the root dir.
+/// Remove the last component from \a path unless it is the root dir.
///
/// @code
/// directory/filename.cpp => directory/
@@ -131,7 +132,7 @@ reverse_iterator rend(StringRef path);
/// @param path A path that is modified to not have a file component.
void remove_filename(SmallVectorImpl<char> &path, Style style = Style::native);
-/// @brief Replace the file extension of \a path with \a extension.
+/// Replace the file extension of \a path with \a extension.
///
/// @code
/// ./filename.cpp => ./filename.extension
@@ -146,7 +147,7 @@ void remove_filename(SmallVectorImpl<char> &path, Style style = Style::native);
void replace_extension(SmallVectorImpl<char> &path, const Twine &extension,
Style style = Style::native);
-/// @brief Replace matching path prefix with another path.
+/// Replace matching path prefix with another path.
///
/// @code
/// /foo, /old, /new => /foo
@@ -163,7 +164,7 @@ void replace_path_prefix(SmallVectorImpl<char> &Path,
const StringRef &OldPrefix, const StringRef &NewPrefix,
Style style = Style::native);
-/// @brief Append to path.
+/// Append to path.
///
/// @code
/// /foo + bar/f => /foo/bar/f
@@ -181,7 +182,7 @@ void append(SmallVectorImpl<char> &path, const Twine &a,
void append(SmallVectorImpl<char> &path, Style style, const Twine &a,
const Twine &b = "", const Twine &c = "", const Twine &d = "");
-/// @brief Append to path.
+/// Append to path.
///
/// @code
/// /foo + [bar,f] => /foo/bar/f
@@ -215,7 +216,7 @@ void native(const Twine &path, SmallVectorImpl<char> &result,
/// @param path A path that is transformed to native format.
void native(SmallVectorImpl<char> &path, Style style = Style::native);
-/// @brief Replaces backslashes with slashes if Windows.
+/// Replaces backslashes with slashes if Windows.
///
/// @param path processed path
/// @result The result of replacing backslashes with forward slashes if Windows.
@@ -227,7 +228,7 @@ std::string convert_to_slash(StringRef path, Style style = Style::native);
/// @name Lexical Observers
/// @{
-/// @brief Get root name.
+/// Get root name.
///
/// @code
/// //net/hello => //net
@@ -239,7 +240,7 @@ std::string convert_to_slash(StringRef path, Style style = Style::native);
/// @result The root name of \a path if it has one, otherwise "".
StringRef root_name(StringRef path, Style style = Style::native);
-/// @brief Get root directory.
+/// Get root directory.
///
/// @code
/// /goo/hello => /
@@ -252,7 +253,7 @@ StringRef root_name(StringRef path, Style style = Style::native);
/// "".
StringRef root_directory(StringRef path, Style style = Style::native);
-/// @brief Get root path.
+/// Get root path.
///
/// Equivalent to root_name + root_directory.
///
@@ -260,7 +261,7 @@ StringRef root_directory(StringRef path, Style style = Style::native);
/// @result The root path of \a path if it has one, otherwise "".
StringRef root_path(StringRef path, Style style = Style::native);
-/// @brief Get relative path.
+/// Get relative path.
///
/// @code
/// C:\hello\world => hello\world
@@ -272,7 +273,7 @@ StringRef root_path(StringRef path, Style style = Style::native);
/// @result The path starting after root_path if one exists, otherwise "".
StringRef relative_path(StringRef path, Style style = Style::native);
-/// @brief Get parent path.
+/// Get parent path.
///
/// @code
/// / => <empty>
@@ -284,7 +285,7 @@ StringRef relative_path(StringRef path, Style style = Style::native);
/// @result The parent path of \a path if one exists, otherwise "".
StringRef parent_path(StringRef path, Style style = Style::native);
-/// @brief Get filename.
+/// Get filename.
///
/// @code
/// /foo.txt => foo.txt
@@ -298,7 +299,7 @@ StringRef parent_path(StringRef path, Style style = Style::native);
/// of \a path.
StringRef filename(StringRef path, Style style = Style::native);
-/// @brief Get stem.
+/// Get stem.
///
/// If filename contains a dot but not solely one or two dots, result is the
/// substring of filename ending at (but not including) the last dot. Otherwise
@@ -316,7 +317,7 @@ StringRef filename(StringRef path, Style style = Style::native);
/// @result The stem of \a path.
StringRef stem(StringRef path, Style style = Style::native);
-/// @brief Get extension.
+/// Get extension.
///
/// If filename contains a dot but not solely one or two dots, result is the
/// substring of filename starting at (and including) the last dot, and ending
@@ -332,18 +333,18 @@ StringRef stem(StringRef path, Style style = Style::native);
/// @result The extension of \a path.
StringRef extension(StringRef path, Style style = Style::native);
-/// @brief Check whether the given char is a path separator on the host OS.
+/// Check whether the given char is a path separator on the host OS.
///
/// @param value a character
/// @result true if \a value is a path separator character on the host OS
bool is_separator(char value, Style style = Style::native);
-/// @brief Return the preferred separator for this platform.
+/// Return the preferred separator for this platform.
///
/// @result StringRef of the preferred separator, null-terminated.
StringRef get_separator(Style style = Style::native);
-/// @brief Get the typical temporary directory for the system, e.g.,
+/// Get the typical temporary directory for the system, e.g.,
/// "/var/tmp" or "C:/TEMP"
///
/// @param erasedOnReboot Whether to favor a path that is erased on reboot
@@ -354,13 +355,13 @@ StringRef get_separator(Style style = Style::native);
/// @param result Holds the resulting path name.
void system_temp_directory(bool erasedOnReboot, SmallVectorImpl<char> &result);
-/// @brief Get the user's home directory.
+/// Get the user's home directory.
///
/// @param result Holds the resulting path name.
/// @result True if a home directory is set, false otherwise.
bool home_directory(SmallVectorImpl<char> &result);
-/// @brief Get the user's cache directory.
+/// Get the user's cache directory.
///
/// Expect the resulting path to be a directory shared with other
/// applications/services used by the user. Params \p Path1 to \p Path3 can be
@@ -376,7 +377,7 @@ bool home_directory(SmallVectorImpl<char> &result);
bool user_cache_directory(SmallVectorImpl<char> &Result, const Twine &Path1,
const Twine &Path2 = "", const Twine &Path3 = "");
-/// @brief Has root name?
+/// Has root name?
///
/// root_name != ""
///
@@ -384,7 +385,7 @@ bool user_cache_directory(SmallVectorImpl<char> &Result, const Twine &Path1,
/// @result True if the path has a root name, false otherwise.
bool has_root_name(const Twine &path, Style style = Style::native);
-/// @brief Has root directory?
+/// Has root directory?
///
/// root_directory != ""
///
@@ -392,7 +393,7 @@ bool has_root_name(const Twine &path, Style style = Style::native);
/// @result True if the path has a root directory, false otherwise.
bool has_root_directory(const Twine &path, Style style = Style::native);
-/// @brief Has root path?
+/// Has root path?
///
/// root_path != ""
///
@@ -400,7 +401,7 @@ bool has_root_directory(const Twine &path, Style style = Style::native);
/// @result True if the path has a root path, false otherwise.
bool has_root_path(const Twine &path, Style style = Style::native);
-/// @brief Has relative path?
+/// Has relative path?
///
/// relative_path != ""
///
@@ -408,7 +409,7 @@ bool has_root_path(const Twine &path, Style style = Style::native);
/// @result True if the path has a relative path, false otherwise.
bool has_relative_path(const Twine &path, Style style = Style::native);
-/// @brief Has parent path?
+/// Has parent path?
///
/// parent_path != ""
///
@@ -416,7 +417,7 @@ bool has_relative_path(const Twine &path, Style style = Style::native);
/// @result True if the path has a parent path, false otherwise.
bool has_parent_path(const Twine &path, Style style = Style::native);
-/// @brief Has filename?
+/// Has filename?
///
/// filename != ""
///
@@ -424,7 +425,7 @@ bool has_parent_path(const Twine &path, Style style = Style::native);
/// @result True if the path has a filename, false otherwise.
bool has_filename(const Twine &path, Style style = Style::native);
-/// @brief Has stem?
+/// Has stem?
///
/// stem != ""
///
@@ -432,7 +433,7 @@ bool has_filename(const Twine &path, Style style = Style::native);
/// @result True if the path has a stem, false otherwise.
bool has_stem(const Twine &path, Style style = Style::native);
-/// @brief Has extension?
+/// Has extension?
///
/// extension != ""
///
@@ -440,25 +441,25 @@ bool has_stem(const Twine &path, Style style = Style::native);
/// @result True if the path has a extension, false otherwise.
bool has_extension(const Twine &path, Style style = Style::native);
-/// @brief Is path absolute?
+/// Is path absolute?
///
/// @param path Input path.
/// @result True if the path is absolute, false if it is not.
bool is_absolute(const Twine &path, Style style = Style::native);
-/// @brief Is path relative?
+/// Is path relative?
///
/// @param path Input path.
/// @result True if the path is relative, false if it is not.
bool is_relative(const Twine &path, Style style = Style::native);
-/// @brief Remove redundant leading "./" pieces and consecutive separators.
+/// Remove redundant leading "./" pieces and consecutive separators.
///
/// @param path Input path.
/// @result The cleaned-up \a path.
StringRef remove_leading_dotslash(StringRef path, Style style = Style::native);
-/// @brief In-place remove any './' and optionally '../' components from a path.
+/// In-place remove any './' and optionally '../' components from a path.
///
/// @param path processed path
/// @param remove_dot_dot specify if '../' (except for leading "../") should be
@@ -467,6 +468,10 @@ StringRef remove_leading_dotslash(StringRef path, Style style = Style::native);
bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot = false,
Style style = Style::native);
+#if defined(_WIN32)
+std::error_code widenPath(const Twine &Path8, SmallVectorImpl<wchar_t> &Path16);
+#endif
+
} // end namespace path
} // end namespace sys
} // end namespace llvm
diff --git a/include/llvm/Support/PointerLikeTypeTraits.h b/include/llvm/Support/PointerLikeTypeTraits.h
index 794230d606a4..1710b57131d1 100644
--- a/include/llvm/Support/PointerLikeTypeTraits.h
+++ b/include/llvm/Support/PointerLikeTypeTraits.h
@@ -16,6 +16,7 @@
#define LLVM_SUPPORT_POINTERLIKETYPETRAITS_H
#include "llvm/Support/DataTypes.h"
+#include <assert.h>
#include <type_traits>
namespace llvm {
@@ -111,6 +112,39 @@ template <> struct PointerLikeTypeTraits<uintptr_t> {
enum { NumLowBitsAvailable = 0 };
};
+/// Provide suitable custom traits struct for function pointers.
+///
+/// Function pointers can't be directly given these traits as functions can't
+/// have their alignment computed with `alignof` and we need different casting.
+///
+/// To rely on higher alignment for a specialized use, you can provide a
+/// customized form of this template explicitly with higher alignment, and
+/// potentially use alignment attributes on functions to satisfy that.
+template <int Alignment, typename FunctionPointerT>
+struct FunctionPointerLikeTypeTraits {
+ enum { NumLowBitsAvailable = detail::ConstantLog2<Alignment>::value };
+ static inline void *getAsVoidPointer(FunctionPointerT P) {
+ assert((reinterpret_cast<uintptr_t>(P) &
+ ~((uintptr_t)-1 << NumLowBitsAvailable)) == 0 &&
+ "Alignment not satisfied for an actual function pointer!");
+ return reinterpret_cast<void *>(P);
+ }
+ static inline FunctionPointerT getFromVoidPointer(void *P) {
+ return reinterpret_cast<FunctionPointerT>(P);
+ }
+};
+
+/// Provide a default specialization for function pointers that assumes 4-byte
+/// alignment.
+///
+/// We assume here that functions used with this are always at least 4-byte
+/// aligned. This means that, for example, thumb functions won't work or systems
+/// with weird unaligned function pointers won't work. But all practical systems
+/// we support satisfy this requirement.
+template <typename ReturnT, typename... ParamTs>
+struct PointerLikeTypeTraits<ReturnT (*)(ParamTs...)>
+ : FunctionPointerLikeTypeTraits<4, ReturnT (*)(ParamTs...)> {};
+
} // end namespace llvm
#endif
diff --git a/include/llvm/Support/Process.h b/include/llvm/Support/Process.h
index 82b0d9f6ba28..f9f1cac86278 100644
--- a/include/llvm/Support/Process.h
+++ b/include/llvm/Support/Process.h
@@ -26,7 +26,6 @@
#define LLVM_SUPPORT_PROCESS_H
#include "llvm/ADT/Optional.h"
-#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Chrono.h"
#include "llvm/Support/DataTypes.h"
@@ -39,13 +38,13 @@ class StringRef;
namespace sys {
-/// \brief A collection of legacy interfaces for querying information about the
+/// A collection of legacy interfaces for querying information about the
/// current executing process.
class Process {
public:
static unsigned getPageSize();
- /// \brief Return process memory usage.
+ /// Return process memory usage.
/// This static function will return the total amount of memory allocated
/// by the process. This only counts the memory allocated via the malloc,
/// calloc and realloc functions and includes any "free" holes in the
@@ -67,10 +66,10 @@ public:
/// This function makes the necessary calls to the operating system to
/// prevent core files or any other kind of large memory dumps that can
/// occur when a program fails.
- /// @brief Prevent core file generation.
+ /// Prevent core file generation.
static void PreventCoreFiles();
- /// \brief true if PreventCoreFiles has been called, false otherwise.
+ /// true if PreventCoreFiles has been called, false otherwise.
static bool AreCoreFilesPrevented();
// This function returns the environment variable \arg name's value as a UTF-8
@@ -90,14 +89,6 @@ public:
static Optional<std::string> FindInEnvPath(StringRef EnvName,
StringRef FileName);
- /// This function returns a SmallVector containing the arguments passed from
- /// the operating system to the program. This function expects to be handed
- /// the vector passed in from main.
- static std::error_code
- GetArgumentVector(SmallVectorImpl<const char *> &Args,
- ArrayRef<const char *> ArgsFromMain,
- SpecificBumpPtrAllocator<char> &ArgAllocator);
-
// This functions ensures that the standard file descriptors (input, output,
// and error) are properly mapped to a file descriptor before we use any of
// them. This should only be called by standalone programs, library
diff --git a/include/llvm/Support/Program.h b/include/llvm/Support/Program.h
index 06fd35078145..1f4dbdce3323 100644
--- a/include/llvm/Support/Program.h
+++ b/include/llvm/Support/Program.h
@@ -17,6 +17,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/ErrorOr.h"
#include <system_error>
@@ -27,35 +28,32 @@ namespace sys {
// a colon on Unix or a semicolon on Windows.
#if defined(LLVM_ON_UNIX)
const char EnvPathSeparator = ':';
-#elif defined (LLVM_ON_WIN32)
+#elif defined (_WIN32)
const char EnvPathSeparator = ';';
#endif
-/// @brief This struct encapsulates information about a process.
-struct ProcessInfo {
-#if defined(LLVM_ON_UNIX)
- typedef pid_t ProcessId;
-#elif defined(LLVM_ON_WIN32)
- typedef unsigned long ProcessId; // Must match the type of DWORD on Windows.
- typedef void * HANDLE; // Must match the type of HANDLE on Windows.
- /// The handle to the process (available on Windows only).
- HANDLE ProcessHandle;
+#if defined(_WIN32)
+ typedef unsigned long procid_t; // Must match the type of DWORD on Windows.
+ typedef void *process_t; // Must match the type of HANDLE on Windows.
#else
-#error "ProcessInfo is not defined for this platform!"
+ typedef pid_t procid_t;
+ typedef procid_t process_t;
#endif
- enum : ProcessId { InvalidPid = 0 };
+ /// This struct encapsulates information about a process.
+ struct ProcessInfo {
+ enum : procid_t { InvalidPid = 0 };
- /// The process identifier.
- ProcessId Pid;
+ procid_t Pid; /// The process identifier.
+ process_t Process; /// Platform-dependent process object.
- /// The return code, set after execution.
- int ReturnCode;
+ /// The return code, set after execution.
+ int ReturnCode;
- ProcessInfo();
-};
+ ProcessInfo();
+ };
- /// \brief Find the first executable file \p Name in \p Paths.
+ /// Find the first executable file \p Name in \p Paths.
///
/// This does not perform hashing as a shell would but instead stats each PATH
/// entry individually so should generally be avoided. Core LLVM library
@@ -91,12 +89,13 @@ struct ProcessInfo {
int ExecuteAndWait(
StringRef Program, ///< Path of the program to be executed. It is
///< presumed this is the result of the findProgramByName method.
- const char **Args, ///< A vector of strings that are passed to the
+ ArrayRef<StringRef> Args, ///< An array of strings that are passed to the
///< program. The first element should be the name of the program.
- ///< The list *must* be terminated by a null char* entry.
- const char **Env = nullptr, ///< An optional vector of strings to use for
- ///< the program's environment. If not provided, the current program's
- ///< environment will be used.
+ ///< The array should **not** be terminated by an empty StringRef.
+ Optional<ArrayRef<StringRef>> Env = None, ///< An optional vector of
+ ///< strings to use for the program's environment. If not provided, the
+ ///< current program's environment will be used. If specified, the
+ ///< vector should **not** be terminated by an empty StringRef.
ArrayRef<Optional<StringRef>> Redirects = {}, ///<
///< An array of optional paths. Should have a size of zero or three.
///< If the array is empty, no redirections are performed.
@@ -125,8 +124,8 @@ struct ProcessInfo {
/// \note On Microsoft Windows systems, users will need to either call
/// \see Wait until the process finished execution or win32 CloseHandle() API
/// on ProcessInfo.ProcessHandle to avoid memory leaks.
- ProcessInfo ExecuteNoWait(StringRef Program, const char **Args,
- const char **Env = nullptr,
+ ProcessInfo ExecuteNoWait(StringRef Program, ArrayRef<StringRef> Args,
+ Optional<ArrayRef<StringRef>> Env,
ArrayRef<Optional<StringRef>> Redirects = {},
unsigned MemoryLimit = 0,
std::string *ErrMsg = nullptr,
@@ -135,6 +134,11 @@ struct ProcessInfo {
/// Return true if the given arguments fit within system-specific
/// argument length limits.
bool commandLineFitsWithinSystemLimits(StringRef Program,
+ ArrayRef<StringRef> Args);
+
+ /// Return true if the given arguments fit within system-specific
+ /// argument length limits.
+ bool commandLineFitsWithinSystemLimits(StringRef Program,
ArrayRef<const char *> Args);
/// File encoding options when writing contents that a non-UTF8 tool will
@@ -191,6 +195,14 @@ struct ProcessInfo {
///< string is non-empty upon return an error occurred while invoking the
///< program.
);
+
+#if defined(_WIN32)
+ /// Given a list of command line arguments, quote and escape them as necessary
+ /// to build a single flat command line appropriate for calling CreateProcess
+ /// on
+ /// Windows.
+ std::string flattenWindowsCommandLine(ArrayRef<StringRef> Args);
+#endif
}
}
diff --git a/include/llvm/Support/RWMutex.h b/include/llvm/Support/RWMutex.h
index 85f4fc09fb87..5ac3e558999b 100644
--- a/include/llvm/Support/RWMutex.h
+++ b/include/llvm/Support/RWMutex.h
@@ -21,7 +21,7 @@
namespace llvm {
namespace sys {
- /// @brief Platform agnostic RWMutex class.
+ /// Platform agnostic RWMutex class.
class RWMutexImpl
{
/// @name Constructors
@@ -29,7 +29,7 @@ namespace sys {
public:
/// Initializes the lock but doesn't acquire it.
- /// @brief Default Constructor.
+ /// Default Constructor.
explicit RWMutexImpl();
/// @}
@@ -40,7 +40,7 @@ namespace sys {
/// @}
/// Releases and removes the lock
- /// @brief Destructor
+ /// Destructor
~RWMutexImpl();
/// @}
@@ -52,24 +52,24 @@ namespace sys {
/// lock is held by a writer, this method will wait until it can acquire
/// the lock.
/// @returns false if any kind of error occurs, true otherwise.
- /// @brief Unconditionally acquire the lock in reader mode.
+ /// Unconditionally acquire the lock in reader mode.
bool reader_acquire();
/// Attempts to release the lock in reader mode.
/// @returns false if any kind of error occurs, true otherwise.
- /// @brief Unconditionally release the lock in reader mode.
+ /// Unconditionally release the lock in reader mode.
bool reader_release();
/// Attempts to unconditionally acquire the lock in reader mode. If the
/// lock is held by any readers, this method will wait until it can
/// acquire the lock.
/// @returns false if any kind of error occurs, true otherwise.
- /// @brief Unconditionally acquire the lock in writer mode.
+ /// Unconditionally acquire the lock in writer mode.
bool writer_acquire();
/// Attempts to release the lock in writer mode.
/// @returns false if any kind of error occurs, true otherwise.
- /// @brief Unconditionally release the lock in write mode.
+ /// Unconditionally release the lock in write mode.
bool writer_release();
//@}
diff --git a/include/llvm/Support/Regex.h b/include/llvm/Support/Regex.h
index f498835bcb58..d901eb1e3ffb 100644
--- a/include/llvm/Support/Regex.h
+++ b/include/llvm/Support/Regex.h
@@ -86,11 +86,11 @@ namespace llvm {
std::string sub(StringRef Repl, StringRef String,
std::string *Error = nullptr);
- /// \brief If this function returns true, ^Str$ is an extended regular
+ /// If this function returns true, ^Str$ is an extended regular
/// expression that matches Str and only Str.
static bool isLiteralERE(StringRef Str);
- /// \brief Turn String into a regex by escaping its special characters.
+ /// Turn String into a regex by escaping its special characters.
static std::string escape(StringRef String);
private:
diff --git a/include/llvm/Support/SMLoc.h b/include/llvm/Support/SMLoc.h
index 5b8be5505540..c74feff378d6 100644
--- a/include/llvm/Support/SMLoc.h
+++ b/include/llvm/Support/SMLoc.h
@@ -44,8 +44,8 @@ public:
/// Represents a range in source code.
///
/// SMRange is implemented using a half-open range, as is the convention in C++.
-/// In the string "abc", the range (1,3] represents the substring "bc", and the
-/// range (2,2] represents an empty range between the characters "b" and "c".
+/// In the string "abc", the range [1,3) represents the substring "bc", and the
+/// range [2,2) represents an empty range between the characters "b" and "c".
class SMRange {
public:
SMLoc Start, End;
@@ -54,7 +54,7 @@ public:
SMRange(NoneType) {}
SMRange(SMLoc St, SMLoc En) : Start(St), End(En) {
assert(Start.isValid() == End.isValid() &&
- "Start and end should either both be valid or both be invalid!");
+ "Start and End should either both be valid or both be invalid!");
}
bool isValid() const { return Start.isValid(); }
diff --git a/include/llvm/Support/SaveAndRestore.h b/include/llvm/Support/SaveAndRestore.h
index ef154ac9c913..8e11789907ad 100644
--- a/include/llvm/Support/SaveAndRestore.h
+++ b/include/llvm/Support/SaveAndRestore.h
@@ -32,18 +32,6 @@ private:
T OldValue;
};
-/// Similar to \c SaveAndRestore. Operates only on bools; the old value of a
-/// variable is saved, and during the dstor the old value is or'ed with the new
-/// value.
-struct SaveOr {
- SaveOr(bool &X) : X(X), OldValue(X) { X = false; }
- ~SaveOr() { X |= OldValue; }
-
-private:
- bool &X;
- const bool OldValue;
-};
-
} // namespace llvm
#endif
diff --git a/include/llvm/Support/ScaledNumber.h b/include/llvm/Support/ScaledNumber.h
index cfbdbc751617..3bd3ccedc42c 100644
--- a/include/llvm/Support/ScaledNumber.h
+++ b/include/llvm/Support/ScaledNumber.h
@@ -33,16 +33,16 @@
namespace llvm {
namespace ScaledNumbers {
-/// \brief Maximum scale; same as APFloat for easy debug printing.
+/// Maximum scale; same as APFloat for easy debug printing.
const int32_t MaxScale = 16383;
-/// \brief Maximum scale; same as APFloat for easy debug printing.
+/// Maximum scale; same as APFloat for easy debug printing.
const int32_t MinScale = -16382;
-/// \brief Get the width of a number.
+/// Get the width of a number.
template <class DigitsT> inline int getWidth() { return sizeof(DigitsT) * 8; }
-/// \brief Conditionally round up a scaled number.
+/// Conditionally round up a scaled number.
///
/// Given \c Digits and \c Scale, round up iff \c ShouldRound is \c true.
/// Always returns \c Scale unless there's an overflow, in which case it
@@ -61,19 +61,19 @@ inline std::pair<DigitsT, int16_t> getRounded(DigitsT Digits, int16_t Scale,
return std::make_pair(Digits, Scale);
}
-/// \brief Convenience helper for 32-bit rounding.
+/// Convenience helper for 32-bit rounding.
inline std::pair<uint32_t, int16_t> getRounded32(uint32_t Digits, int16_t Scale,
bool ShouldRound) {
return getRounded(Digits, Scale, ShouldRound);
}
-/// \brief Convenience helper for 64-bit rounding.
+/// Convenience helper for 64-bit rounding.
inline std::pair<uint64_t, int16_t> getRounded64(uint64_t Digits, int16_t Scale,
bool ShouldRound) {
return getRounded(Digits, Scale, ShouldRound);
}
-/// \brief Adjust a 64-bit scaled number down to the appropriate width.
+/// Adjust a 64-bit scaled number down to the appropriate width.
///
/// \pre Adding 64 to \c Scale will not overflow INT16_MAX.
template <class DigitsT>
@@ -91,24 +91,24 @@ inline std::pair<DigitsT, int16_t> getAdjusted(uint64_t Digits,
Digits & (UINT64_C(1) << (Shift - 1)));
}
-/// \brief Convenience helper for adjusting to 32 bits.
+/// Convenience helper for adjusting to 32 bits.
inline std::pair<uint32_t, int16_t> getAdjusted32(uint64_t Digits,
int16_t Scale = 0) {
return getAdjusted<uint32_t>(Digits, Scale);
}
-/// \brief Convenience helper for adjusting to 64 bits.
+/// Convenience helper for adjusting to 64 bits.
inline std::pair<uint64_t, int16_t> getAdjusted64(uint64_t Digits,
int16_t Scale = 0) {
return getAdjusted<uint64_t>(Digits, Scale);
}
-/// \brief Multiply two 64-bit integers to create a 64-bit scaled number.
+/// Multiply two 64-bit integers to create a 64-bit scaled number.
///
/// Implemented with four 64-bit integer multiplies.
std::pair<uint64_t, int16_t> multiply64(uint64_t LHS, uint64_t RHS);
-/// \brief Multiply two 32-bit integers to create a 32-bit scaled number.
+/// Multiply two 32-bit integers to create a 32-bit scaled number.
///
/// Implemented with one 64-bit integer multiply.
template <class DigitsT>
@@ -121,31 +121,31 @@ inline std::pair<DigitsT, int16_t> getProduct(DigitsT LHS, DigitsT RHS) {
return multiply64(LHS, RHS);
}
-/// \brief Convenience helper for 32-bit product.
+/// Convenience helper for 32-bit product.
inline std::pair<uint32_t, int16_t> getProduct32(uint32_t LHS, uint32_t RHS) {
return getProduct(LHS, RHS);
}
-/// \brief Convenience helper for 64-bit product.
+/// Convenience helper for 64-bit product.
inline std::pair<uint64_t, int16_t> getProduct64(uint64_t LHS, uint64_t RHS) {
return getProduct(LHS, RHS);
}
-/// \brief Divide two 64-bit integers to create a 64-bit scaled number.
+/// Divide two 64-bit integers to create a 64-bit scaled number.
///
/// Implemented with long division.
///
/// \pre \c Dividend and \c Divisor are non-zero.
std::pair<uint64_t, int16_t> divide64(uint64_t Dividend, uint64_t Divisor);
-/// \brief Divide two 32-bit integers to create a 32-bit scaled number.
+/// Divide two 32-bit integers to create a 32-bit scaled number.
///
/// Implemented with one 64-bit integer divide/remainder pair.
///
/// \pre \c Dividend and \c Divisor are non-zero.
std::pair<uint32_t, int16_t> divide32(uint32_t Dividend, uint32_t Divisor);
-/// \brief Divide two 32-bit numbers to create a 32-bit scaled number.
+/// Divide two 32-bit numbers to create a 32-bit scaled number.
///
/// Implemented with one 64-bit integer divide/remainder pair.
///
@@ -167,19 +167,19 @@ std::pair<DigitsT, int16_t> getQuotient(DigitsT Dividend, DigitsT Divisor) {
return divide32(Dividend, Divisor);
}
-/// \brief Convenience helper for 32-bit quotient.
+/// Convenience helper for 32-bit quotient.
inline std::pair<uint32_t, int16_t> getQuotient32(uint32_t Dividend,
uint32_t Divisor) {
return getQuotient(Dividend, Divisor);
}
-/// \brief Convenience helper for 64-bit quotient.
+/// Convenience helper for 64-bit quotient.
inline std::pair<uint64_t, int16_t> getQuotient64(uint64_t Dividend,
uint64_t Divisor) {
return getQuotient(Dividend, Divisor);
}
-/// \brief Implementation of getLg() and friends.
+/// Implementation of getLg() and friends.
///
/// Returns the rounded lg of \c Digits*2^Scale and an int specifying whether
/// this was rounded up (1), down (-1), or exact (0).
@@ -206,7 +206,7 @@ inline std::pair<int32_t, int> getLgImpl(DigitsT Digits, int16_t Scale) {
return std::make_pair(Floor + Round, Round ? 1 : -1);
}
-/// \brief Get the lg (rounded) of a scaled number.
+/// Get the lg (rounded) of a scaled number.
///
/// Get the lg of \c Digits*2^Scale.
///
@@ -215,7 +215,7 @@ template <class DigitsT> int32_t getLg(DigitsT Digits, int16_t Scale) {
return getLgImpl(Digits, Scale).first;
}
-/// \brief Get the lg floor of a scaled number.
+/// Get the lg floor of a scaled number.
///
/// Get the floor of the lg of \c Digits*2^Scale.
///
@@ -225,7 +225,7 @@ template <class DigitsT> int32_t getLgFloor(DigitsT Digits, int16_t Scale) {
return Lg.first - (Lg.second > 0);
}
-/// \brief Get the lg ceiling of a scaled number.
+/// Get the lg ceiling of a scaled number.
///
/// Get the ceiling of the lg of \c Digits*2^Scale.
///
@@ -235,7 +235,7 @@ template <class DigitsT> int32_t getLgCeiling(DigitsT Digits, int16_t Scale) {
return Lg.first + (Lg.second < 0);
}
-/// \brief Implementation for comparing scaled numbers.
+/// Implementation for comparing scaled numbers.
///
/// Compare two 64-bit numbers with different scales. Given that the scale of
/// \c L is higher than that of \c R by \c ScaleDiff, compare them. Return -1,
@@ -244,7 +244,7 @@ template <class DigitsT> int32_t getLgCeiling(DigitsT Digits, int16_t Scale) {
/// \pre 0 <= ScaleDiff < 64.
int compareImpl(uint64_t L, uint64_t R, int ScaleDiff);
-/// \brief Compare two scaled numbers.
+/// Compare two scaled numbers.
///
/// Compare two scaled numbers. Returns 0 for equal, -1 for less than, and 1
/// for greater than.
@@ -271,7 +271,7 @@ int compare(DigitsT LDigits, int16_t LScale, DigitsT RDigits, int16_t RScale) {
return -compareImpl(RDigits, LDigits, LScale - RScale);
}
-/// \brief Match scales of two numbers.
+/// Match scales of two numbers.
///
/// Given two scaled numbers, match up their scales. Change the digits and
/// scales in place. Shift the digits as necessary to form equivalent numbers,
@@ -324,7 +324,7 @@ int16_t matchScales(DigitsT &LDigits, int16_t &LScale, DigitsT &RDigits,
return LScale;
}
-/// \brief Get the sum of two scaled numbers.
+/// Get the sum of two scaled numbers.
///
/// Get the sum of two scaled numbers with as much precision as possible.
///
@@ -352,19 +352,19 @@ std::pair<DigitsT, int16_t> getSum(DigitsT LDigits, int16_t LScale,
return std::make_pair(HighBit | Sum >> 1, Scale + 1);
}
-/// \brief Convenience helper for 32-bit sum.
+/// Convenience helper for 32-bit sum.
inline std::pair<uint32_t, int16_t> getSum32(uint32_t LDigits, int16_t LScale,
uint32_t RDigits, int16_t RScale) {
return getSum(LDigits, LScale, RDigits, RScale);
}
-/// \brief Convenience helper for 64-bit sum.
+/// Convenience helper for 64-bit sum.
inline std::pair<uint64_t, int16_t> getSum64(uint64_t LDigits, int16_t LScale,
uint64_t RDigits, int16_t RScale) {
return getSum(LDigits, LScale, RDigits, RScale);
}
-/// \brief Get the difference of two scaled numbers.
+/// Get the difference of two scaled numbers.
///
/// Get LHS minus RHS with as much precision as possible.
///
@@ -395,7 +395,7 @@ std::pair<DigitsT, int16_t> getDifference(DigitsT LDigits, int16_t LScale,
return std::make_pair(LDigits, LScale);
}
-/// \brief Convenience helper for 32-bit difference.
+/// Convenience helper for 32-bit difference.
inline std::pair<uint32_t, int16_t> getDifference32(uint32_t LDigits,
int16_t LScale,
uint32_t RDigits,
@@ -403,7 +403,7 @@ inline std::pair<uint32_t, int16_t> getDifference32(uint32_t LDigits,
return getDifference(LDigits, LScale, RDigits, RScale);
}
-/// \brief Convenience helper for 64-bit difference.
+/// Convenience helper for 64-bit difference.
inline std::pair<uint64_t, int16_t> getDifference64(uint64_t LDigits,
int16_t LScale,
uint64_t RDigits,
@@ -443,7 +443,7 @@ public:
}
};
-/// \brief Simple representation of a scaled number.
+/// Simple representation of a scaled number.
///
/// ScaledNumber is a number represented by digits and a scale. It uses simple
/// saturation arithmetic and every operation is well-defined for every value.
@@ -534,7 +534,7 @@ public:
int16_t getScale() const { return Scale; }
DigitsType getDigits() const { return Digits; }
- /// \brief Convert to the given integer type.
+ /// Convert to the given integer type.
///
/// Convert to \c IntT using simple saturating arithmetic, truncating if
/// necessary.
@@ -548,17 +548,17 @@ public:
return Digits == DigitsType(1) << -Scale;
}
- /// \brief The log base 2, rounded.
+ /// The log base 2, rounded.
///
/// Get the lg of the scalar. lg 0 is defined to be INT32_MIN.
int32_t lg() const { return ScaledNumbers::getLg(Digits, Scale); }
- /// \brief The log base 2, rounded towards INT32_MIN.
+ /// The log base 2, rounded towards INT32_MIN.
///
/// Get the lg floor. lg 0 is defined to be INT32_MIN.
int32_t lgFloor() const { return ScaledNumbers::getLgFloor(Digits, Scale); }
- /// \brief The log base 2, rounded towards INT32_MAX.
+ /// The log base 2, rounded towards INT32_MAX.
///
/// Get the lg ceiling. lg 0 is defined to be INT32_MIN.
int32_t lgCeiling() const {
@@ -574,7 +574,7 @@ public:
bool operator!() const { return isZero(); }
- /// \brief Convert to a decimal representation in a string.
+ /// Convert to a decimal representation in a string.
///
/// Convert to a string. Uses scientific notation for very large/small
/// numbers. Scientific notation is used roughly for numbers outside of the
@@ -597,7 +597,7 @@ public:
return ScaledNumberBase::toString(Digits, Scale, Width, Precision);
}
- /// \brief Print a decimal representation.
+ /// Print a decimal representation.
///
/// Print a string. See toString for documentation.
raw_ostream &print(raw_ostream &OS,
@@ -634,7 +634,7 @@ private:
void shiftLeft(int32_t Shift);
void shiftRight(int32_t Shift);
- /// \brief Adjust two floats to have matching exponents.
+ /// Adjust two floats to have matching exponents.
///
/// Adjust \c this and \c X to have matching exponents. Returns the new \c X
/// by value. Does nothing if \a isZero() for either.
@@ -647,7 +647,7 @@ private:
}
public:
- /// \brief Scale a large number accurately.
+ /// Scale a large number accurately.
///
/// Scale N (multiply it by this). Uses full precision multiplication, even
/// if Width is smaller than 64, so information is not lost.
@@ -693,7 +693,7 @@ private:
return countLeadingZeros32(Digits) + Width - 32;
}
- /// \brief Adjust a number to width, rounding up if necessary.
+ /// Adjust a number to width, rounding up if necessary.
///
/// Should only be called for \c Shift close to zero.
///
diff --git a/include/llvm/Support/ScopedPrinter.h b/include/llvm/Support/ScopedPrinter.h
index 1b6651932212..062439b4f7db 100644
--- a/include/llvm/Support/ScopedPrinter.h
+++ b/include/llvm/Support/ScopedPrinter.h
@@ -80,6 +80,8 @@ public:
void resetIndent() { IndentLevel = 0; }
+ int getIndentLevel() { return IndentLevel; }
+
void setPrefix(StringRef P) { Prefix = P; }
void printIndent() {
@@ -136,7 +138,7 @@ public:
}
}
- std::sort(SetFlags.begin(), SetFlags.end(), &flagName<TFlag>);
+ llvm::sort(SetFlags.begin(), SetFlags.end(), &flagName<TFlag>);
startLine() << Label << " [ (" << hex(Value) << ")\n";
for (const auto &Flag : SetFlags) {
@@ -261,7 +263,11 @@ public:
}
void printString(StringRef Label, const std::string &Value) {
- startLine() << Label << ": " << Value << "\n";
+ printString(Label, StringRef(Value));
+ }
+
+ void printString(StringRef Label, const char* Value) {
+ printString(Label, StringRef(Value));
}
template <typename T>
diff --git a/include/llvm/Support/Signals.h b/include/llvm/Support/Signals.h
index cbd6f686a778..f25a04969904 100644
--- a/include/llvm/Support/Signals.h
+++ b/include/llvm/Support/Signals.h
@@ -29,16 +29,16 @@ namespace sys {
/// This function registers signal handlers to ensure that if a signal gets
/// delivered that the named file is removed.
- /// @brief Remove a file if a fatal signal occurs.
+ /// Remove a file if a fatal signal occurs.
bool RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg = nullptr);
/// This function removes a file from the list of files to be removed on
/// signal delivery.
void DontRemoveFileOnSignal(StringRef Filename);
- /// When an error signal (such as SIBABRT or SIGSEGV) is delivered to the
+ /// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
/// process, print a stack trace and then exit.
- /// \brief Print a stack trace if a fatal signal occurs.
+ /// Print a stack trace if a fatal signal occurs.
/// \param Argv0 the current binary name, used to find the symbolizer
/// relative to the current binary before searching $PATH; can be
/// StringRef(), in which case we will only search $PATH.
@@ -50,16 +50,18 @@ namespace sys {
/// Disable all system dialog boxes that appear when the process crashes.
void DisableSystemDialogsOnCrash();
- /// \brief Print the stack trace using the given \c raw_ostream object.
+ /// Print the stack trace using the given \c raw_ostream object.
void PrintStackTrace(raw_ostream &OS);
// Run all registered signal handlers.
void RunSignalHandlers();
- /// AddSignalHandler - Add a function to be called when an abort/kill signal
- /// is delivered to the process. The handler can have a cookie passed to it
- /// to identify what instance of the handler it is.
- void AddSignalHandler(void (*FnPtr)(void *), void *Cookie);
+ using SignalHandlerCallback = void (*)(void *);
+
+ /// Add a function to be called when an abort/kill signal is delivered to the
+ /// process. The handler can have a cookie passed to it to identify what
+ /// instance of the handler it is.
+ void AddSignalHandler(SignalHandlerCallback FnPtr, void *Cookie);
/// This function registers a function to be called when the user "interrupts"
/// the program (typically by pressing ctrl-c). When the user interrupts the
@@ -69,7 +71,7 @@ namespace sys {
/// functions. An null interrupt function pointer disables the current
/// installed function. Note also that the handler may be executed on a
/// different thread on some platforms.
- /// @brief Register a function to be called when ctrl-c is pressed.
+ /// Register a function to be called when ctrl-c is pressed.
void SetInterruptFunction(void (*IF)());
} // End sys namespace
} // End llvm namespace
diff --git a/include/llvm/Support/SmallVectorMemoryBuffer.h b/include/llvm/Support/SmallVectorMemoryBuffer.h
new file mode 100644
index 000000000000..f43c2fb8f826
--- /dev/null
+++ b/include/llvm/Support/SmallVectorMemoryBuffer.h
@@ -0,0 +1,64 @@
+//===- SmallVectorMemoryBuffer.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares a wrapper class to hold the memory into which an
+// object will be generated.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_OBJECTMEMORYBUFFER_H
+#define LLVM_EXECUTIONENGINE_OBJECTMEMORYBUFFER_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+/// SmallVector-backed MemoryBuffer instance.
+///
+/// This class enables efficient construction of MemoryBuffers from SmallVector
+/// instances. This is useful for MCJIT and Orc, where object files are streamed
+/// into SmallVectors, then inspected using ObjectFile (which takes a
+/// MemoryBuffer).
+class SmallVectorMemoryBuffer : public MemoryBuffer {
+public:
+ /// Construct an SmallVectorMemoryBuffer from the given SmallVector
+ /// r-value.
+ ///
+ /// FIXME: It'd be nice for this to be a non-templated constructor taking a
+ /// SmallVectorImpl here instead of a templated one taking a SmallVector<N>,
+ /// but SmallVector's move-construction/assignment currently only take
+ /// SmallVectors. If/when that is fixed we can simplify this constructor and
+ /// the following one.
+ SmallVectorMemoryBuffer(SmallVectorImpl<char> &&SV)
+ : SV(std::move(SV)), BufferName("<in-memory object>") {
+ init(this->SV.begin(), this->SV.end(), false);
+ }
+
+ /// Construct a named SmallVectorMemoryBuffer from the given
+ /// SmallVector r-value and StringRef.
+ SmallVectorMemoryBuffer(SmallVectorImpl<char> &&SV, StringRef Name)
+ : SV(std::move(SV)), BufferName(Name) {
+ init(this->SV.begin(), this->SV.end(), false);
+ }
+
+ StringRef getBufferIdentifier() const override { return BufferName; }
+
+ BufferKind getBufferKind() const override { return MemoryBuffer_Malloc; }
+
+private:
+ SmallVector<char, 0> SV;
+ std::string BufferName;
+ void anchor() override;
+};
+
+} // namespace llvm
+
+#endif
diff --git a/include/llvm/Support/SourceMgr.h b/include/llvm/Support/SourceMgr.h
index c08bf858760a..63ac893239d1 100644
--- a/include/llvm/Support/SourceMgr.h
+++ b/include/llvm/Support/SourceMgr.h
@@ -18,6 +18,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/None.h"
+#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
@@ -57,8 +58,38 @@ private:
/// The memory buffer for the file.
std::unique_ptr<MemoryBuffer> Buffer;
+ /// Helper type for OffsetCache below: since we're storing many offsets
+ /// into relatively small files (often smaller than 2^8 or 2^16 bytes),
+ /// we select the offset vector element type dynamically based on the
+ /// size of Buffer.
+ using VariableSizeOffsets = PointerUnion4<std::vector<uint8_t> *,
+ std::vector<uint16_t> *,
+ std::vector<uint32_t> *,
+ std::vector<uint64_t> *>;
+
+ /// Vector of offsets into Buffer at which there are line-endings
+ /// (lazily populated). Once populated, the '\n' that marks the end of
+ /// line number N from [1..] is at Buffer[OffsetCache[N-1]]. Since
+ /// these offsets are in sorted (ascending) order, they can be
+ /// binary-searched for the first one after any given offset (eg. an
+ /// offset corresponding to a particular SMLoc).
+ mutable VariableSizeOffsets OffsetCache;
+
+ /// Populate \c OffsetCache and look up a given \p Ptr in it, assuming
+ /// it points somewhere into \c Buffer. The static type parameter \p T
+ /// must be an unsigned integer type from uint{8,16,32,64}_t large
+ /// enough to store offsets inside \c Buffer.
+ template<typename T>
+ unsigned getLineNumber(const char *Ptr) const;
+
/// This is the location of the parent include, or null if at the top level.
SMLoc IncludeLoc;
+
+ SrcBuffer() = default;
+ SrcBuffer(SrcBuffer &&);
+ SrcBuffer(const SrcBuffer &) = delete;
+ SrcBuffer &operator=(const SrcBuffer &) = delete;
+ ~SrcBuffer();
};
/// This is all of the buffers that we are reading from.
@@ -67,10 +98,6 @@ private:
// This is the list of directories we should search for include files in.
std::vector<std::string> IncludeDirectories;
- /// This is a cache for line number queries, its implementation is really
- /// private to SourceMgr.cpp.
- mutable void *LineNoCache = nullptr;
-
DiagHandlerTy DiagHandler = nullptr;
void *DiagContext = nullptr;
@@ -80,7 +107,7 @@ public:
SourceMgr() = default;
SourceMgr(const SourceMgr &) = delete;
SourceMgr &operator=(const SourceMgr &) = delete;
- ~SourceMgr();
+ ~SourceMgr() = default;
void setIncludeDirs(const std::vector<std::string> &Dirs) {
IncludeDirectories = Dirs;
diff --git a/include/llvm/Support/StringSaver.h b/include/llvm/Support/StringSaver.h
index e85b2895ce51..6b77d487333b 100644
--- a/include/llvm/Support/StringSaver.h
+++ b/include/llvm/Support/StringSaver.h
@@ -10,23 +10,49 @@
#ifndef LLVM_SUPPORT_STRINGSAVER_H
#define LLVM_SUPPORT_STRINGSAVER_H
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Allocator.h"
namespace llvm {
-/// \brief Saves strings in the inheritor's stable storage and returns a
+/// Saves strings in the provided stable storage and returns a
/// StringRef with a stable character pointer.
class StringSaver final {
BumpPtrAllocator &Alloc;
public:
StringSaver(BumpPtrAllocator &Alloc) : Alloc(Alloc) {}
+
+ // All returned strings are null-terminated: *save(S).end() == 0.
StringRef save(const char *S) { return save(StringRef(S)); }
StringRef save(StringRef S);
StringRef save(const Twine &S) { return save(StringRef(S.str())); }
StringRef save(const std::string &S) { return save(StringRef(S)); }
};
+
+/// Saves strings in the provided stable storage and returns a StringRef with a
+/// stable character pointer. Saving the same string yields the same StringRef.
+///
+/// Compared to StringSaver, it does more work but avoids saving the same string
+/// multiple times.
+///
+/// Compared to StringPool, it performs fewer allocations but doesn't support
+/// refcounting/deletion.
+class UniqueStringSaver final {
+ StringSaver Strings;
+ llvm::DenseSet<llvm::StringRef> Unique;
+
+public:
+ UniqueStringSaver(BumpPtrAllocator &Alloc) : Strings(Alloc) {}
+
+ // All returned strings are null-terminated: *save(S).end() == 0.
+ StringRef save(const char *S) { return save(StringRef(S)); }
+ StringRef save(StringRef S);
+ StringRef save(const Twine &S) { return save(StringRef(S.str())); }
+ StringRef save(const std::string &S) { return save(StringRef(S)); }
+};
+
}
#endif
diff --git a/include/llvm/Support/SystemUtils.h b/include/llvm/Support/SystemUtils.h
index 2997b1b0c9cf..bd60793d1554 100644
--- a/include/llvm/Support/SystemUtils.h
+++ b/include/llvm/Support/SystemUtils.h
@@ -21,7 +21,7 @@ namespace llvm {
/// Determine if the raw_ostream provided is connected to a terminal. If so,
/// generate a warning message to errs() advising against display of bitcode
/// and return true. Otherwise just return false.
-/// @brief Check for output written to a console
+/// Check for output written to a console
bool CheckBitcodeOutputToConsole(
raw_ostream &stream_to_check, ///< The stream to be checked
bool print_warning = true ///< Control whether warnings are printed
diff --git a/include/llvm/Support/TargetOpcodes.def b/include/llvm/Support/TargetOpcodes.def
new file mode 100644
index 000000000000..21f5c7e709b8
--- /dev/null
+++ b/include/llvm/Support/TargetOpcodes.def
@@ -0,0 +1,482 @@
+//===-- llvm/Support/TargetOpcodes.def - Target Indep Opcodes ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the target independent instruction opcodes.
+//
+//===----------------------------------------------------------------------===//
+
+// NOTE: NO INCLUDE GUARD DESIRED!
+
+/// HANDLE_TARGET_OPCODE defines an opcode and its associated enum value.
+///
+#ifndef HANDLE_TARGET_OPCODE
+#define HANDLE_TARGET_OPCODE(OPC, NUM)
+#endif
+
+/// HANDLE_TARGET_OPCODE_MARKER defines an alternative identifier for an opcode.
+///
+#ifndef HANDLE_TARGET_OPCODE_MARKER
+#define HANDLE_TARGET_OPCODE_MARKER(IDENT, OPC)
+#endif
+
+/// Every instruction defined here must also appear in Target.td.
+///
+HANDLE_TARGET_OPCODE(PHI)
+HANDLE_TARGET_OPCODE(INLINEASM)
+HANDLE_TARGET_OPCODE(CFI_INSTRUCTION)
+HANDLE_TARGET_OPCODE(EH_LABEL)
+HANDLE_TARGET_OPCODE(GC_LABEL)
+HANDLE_TARGET_OPCODE(ANNOTATION_LABEL)
+
+/// KILL - This instruction is a noop that is used only to adjust the
+/// liveness of registers. This can be useful when dealing with
+/// sub-registers.
+HANDLE_TARGET_OPCODE(KILL)
+
+/// EXTRACT_SUBREG - This instruction takes two operands: a register
+/// that has subregisters, and a subregister index. It returns the
+/// extracted subregister value. This is commonly used to implement
+/// truncation operations on target architectures which support it.
+HANDLE_TARGET_OPCODE(EXTRACT_SUBREG)
+
+/// INSERT_SUBREG - This instruction takes three operands: a register that
+/// has subregisters, a register providing an insert value, and a
+/// subregister index. It returns the value of the first register with the
+/// value of the second register inserted. The first register is often
+/// defined by an IMPLICIT_DEF, because it is commonly used to implement
+/// anyext operations on target architectures which support it.
+HANDLE_TARGET_OPCODE(INSERT_SUBREG)
+
+/// IMPLICIT_DEF - This is the MachineInstr-level equivalent of undef.
+HANDLE_TARGET_OPCODE(IMPLICIT_DEF)
+
+/// SUBREG_TO_REG - Assert the value of bits in a super register.
+/// The result of this instruction is the value of the second operand inserted
+/// into the subregister specified by the third operand. All other bits are
+/// assumed to be equal to the bits in the immediate integer constant in the
+/// first operand. This instruction just communicates information; No code
+/// should be generated.
+/// This is typically used after an instruction where the write to a subregister
+/// implicitly cleared the bits in the super registers.
+HANDLE_TARGET_OPCODE(SUBREG_TO_REG)
+
+/// COPY_TO_REGCLASS - This instruction is a placeholder for a plain
+/// register-to-register copy into a specific register class. This is only
+/// used between instruction selection and MachineInstr creation, before
+/// virtual registers have been created for all the instructions, and it's
+/// only needed in cases where the register classes implied by the
+/// instructions are insufficient. It is emitted as a COPY MachineInstr.
+ HANDLE_TARGET_OPCODE(COPY_TO_REGCLASS)
+
+/// DBG_VALUE - a mapping of the llvm.dbg.value intrinsic
+HANDLE_TARGET_OPCODE(DBG_VALUE)
+
+/// DBG_LABEL - a mapping of the llvm.dbg.label intrinsic
+HANDLE_TARGET_OPCODE(DBG_LABEL)
+
+/// REG_SEQUENCE - This variadic instruction is used to form a register that
+/// represents a consecutive sequence of sub-registers. It's used as a
+/// register coalescing / allocation aid and must be eliminated before code
+/// emission.
+// In SDNode form, the first operand encodes the register class created by
+// the REG_SEQUENCE, while each subsequent pair names a vreg + subreg index
+// pair. Once it has been lowered to a MachineInstr, the regclass operand
+// is no longer present.
+/// e.g. v1027 = REG_SEQUENCE v1024, 3, v1025, 4, v1026, 5
+/// After register coalescing references of v1024 should be replace with
+/// v1027:3, v1025 with v1027:4, etc.
+ HANDLE_TARGET_OPCODE(REG_SEQUENCE)
+
+/// COPY - Target-independent register copy. This instruction can also be
+/// used to copy between subregisters of virtual registers.
+ HANDLE_TARGET_OPCODE(COPY)
+
+/// BUNDLE - This instruction represents an instruction bundle. Instructions
+/// which immediately follow a BUNDLE instruction which are marked with
+/// 'InsideBundle' flag are inside the bundle.
+HANDLE_TARGET_OPCODE(BUNDLE)
+
+/// Lifetime markers.
+HANDLE_TARGET_OPCODE(LIFETIME_START)
+HANDLE_TARGET_OPCODE(LIFETIME_END)
+
+/// A Stackmap instruction captures the location of live variables at its
+/// position in the instruction stream. It is followed by a shadow of bytes
+/// that must lie within the function and not contain another stackmap.
+HANDLE_TARGET_OPCODE(STACKMAP)
+
+/// FEntry all - This is a marker instruction which gets translated into a raw fentry call.
+HANDLE_TARGET_OPCODE(FENTRY_CALL)
+
+/// Patchable call instruction - this instruction represents a call to a
+/// constant address, followed by a series of NOPs. It is intended to
+/// support optimizations for dynamic languages (such as javascript) that
+/// rewrite calls to runtimes with more efficient code sequences.
+/// This also implies a stack map.
+HANDLE_TARGET_OPCODE(PATCHPOINT)
+
+/// This pseudo-instruction loads the stack guard value. Targets which need
+/// to prevent the stack guard value or address from being spilled to the
+/// stack should override TargetLowering::emitLoadStackGuardNode and
+/// additionally expand this pseudo after register allocation.
+HANDLE_TARGET_OPCODE(LOAD_STACK_GUARD)
+
+/// Call instruction with associated vm state for deoptimization and list
+/// of live pointers for relocation by the garbage collector. It is
+/// intended to support garbage collection with fully precise relocating
+/// collectors and deoptimizations in either the callee or caller.
+HANDLE_TARGET_OPCODE(STATEPOINT)
+
+/// Instruction that records the offset of a local stack allocation passed to
+/// llvm.localescape. It has two arguments: the symbol for the label and the
+/// frame index of the local stack allocation.
+HANDLE_TARGET_OPCODE(LOCAL_ESCAPE)
+
+/// Wraps a machine instruction which can fault, bundled with associated
+/// information on how to handle such a fault.
+/// For example loading instruction that may page fault, bundled with associated
+/// information on how to handle such a page fault. It is intended to support
+/// "zero cost" null checks in managed languages by allowing LLVM to fold
+/// comparisons into existing memory operations.
+HANDLE_TARGET_OPCODE(FAULTING_OP)
+
+/// Wraps a machine instruction to add patchability constraints. An
+/// instruction wrapped in PATCHABLE_OP has to either have a minimum
+/// size or be preceded with a nop of that size. The first operand is
+/// an immediate denoting the minimum size of the instruction, the
+/// second operand is an immediate denoting the opcode of the original
+/// instruction. The rest of the operands are the operands of the
+/// original instruction.
+HANDLE_TARGET_OPCODE(PATCHABLE_OP)
+
+/// This is a marker instruction which gets translated into a nop sled, useful
+/// for inserting instrumentation instructions at runtime.
+HANDLE_TARGET_OPCODE(PATCHABLE_FUNCTION_ENTER)
+
+/// Wraps a return instruction and its operands to enable adding nop sleds
+/// either before or after the return. The nop sleds are useful for inserting
+/// instrumentation instructions at runtime.
+/// The patch here replaces the return instruction.
+HANDLE_TARGET_OPCODE(PATCHABLE_RET)
+
+/// This is a marker instruction which gets translated into a nop sled, useful
+/// for inserting instrumentation instructions at runtime.
+/// The patch here prepends the return instruction.
+/// The same thing as in x86_64 is not possible for ARM because it has multiple
+/// return instructions. Furthermore, CPU allows parametrized and even
+/// conditional return instructions. In the current ARM implementation we are
+/// making use of the fact that currently LLVM doesn't seem to generate
+/// conditional return instructions.
+/// On ARM, the same instruction can be used for popping multiple registers
+/// from the stack and returning (it just pops pc register too), and LLVM
+/// generates it sometimes. So we can't insert the sled between this stack
+/// adjustment and the return without splitting the original instruction into 2
+/// instructions. So on ARM, rather than jumping into the exit trampoline, we
+/// call it, it does the tracing, preserves the stack and returns.
+HANDLE_TARGET_OPCODE(PATCHABLE_FUNCTION_EXIT)
+
+/// Wraps a tail call instruction and its operands to enable adding nop sleds
+/// either before or after the tail exit. We use this as a disambiguation from
+/// PATCHABLE_RET which specifically only works for return instructions.
+HANDLE_TARGET_OPCODE(PATCHABLE_TAIL_CALL)
+
+/// Wraps a logging call and its arguments with nop sleds. At runtime, this can
+/// be patched to insert instrumentation instructions.
+HANDLE_TARGET_OPCODE(PATCHABLE_EVENT_CALL)
+
+/// Wraps a typed logging call and its argument with nop sleds. At runtime, this
+/// can be patched to insert instrumentation instructions.
+HANDLE_TARGET_OPCODE(PATCHABLE_TYPED_EVENT_CALL)
+
+HANDLE_TARGET_OPCODE(ICALL_BRANCH_FUNNEL)
+
+/// The following generic opcodes are not supposed to appear after ISel.
+/// This is something we might want to relax, but for now, this is convenient
+/// to produce diagnostics.
+
+/// Generic ADD instruction. This is an integer add.
+HANDLE_TARGET_OPCODE(G_ADD)
+HANDLE_TARGET_OPCODE_MARKER(PRE_ISEL_GENERIC_OPCODE_START, G_ADD)
+
+/// Generic SUB instruction. This is an integer sub.
+HANDLE_TARGET_OPCODE(G_SUB)
+
+// Generic multiply instruction.
+HANDLE_TARGET_OPCODE(G_MUL)
+
+// Generic signed division instruction.
+HANDLE_TARGET_OPCODE(G_SDIV)
+
+// Generic unsigned division instruction.
+HANDLE_TARGET_OPCODE(G_UDIV)
+
+// Generic signed remainder instruction.
+HANDLE_TARGET_OPCODE(G_SREM)
+
+// Generic unsigned remainder instruction.
+HANDLE_TARGET_OPCODE(G_UREM)
+
+/// Generic bitwise and instruction.
+HANDLE_TARGET_OPCODE(G_AND)
+
+/// Generic bitwise or instruction.
+HANDLE_TARGET_OPCODE(G_OR)
+
+/// Generic bitwise exclusive-or instruction.
+HANDLE_TARGET_OPCODE(G_XOR)
+
+
+HANDLE_TARGET_OPCODE(G_IMPLICIT_DEF)
+
+/// Generic PHI instruction with types.
+HANDLE_TARGET_OPCODE(G_PHI)
+
+/// Generic instruction to materialize the address of an alloca or other
+/// stack-based object.
+HANDLE_TARGET_OPCODE(G_FRAME_INDEX)
+
+/// Generic reference to global value.
+HANDLE_TARGET_OPCODE(G_GLOBAL_VALUE)
+
+/// Generic instruction to extract blocks of bits from the register given
+/// (typically a sub-register COPY after instruction selection).
+HANDLE_TARGET_OPCODE(G_EXTRACT)
+
+HANDLE_TARGET_OPCODE(G_UNMERGE_VALUES)
+
+/// Generic instruction to insert blocks of bits from the registers given into
+/// the source.
+HANDLE_TARGET_OPCODE(G_INSERT)
+
+/// Generic instruction to paste a variable number of components together into a
+/// larger register.
+HANDLE_TARGET_OPCODE(G_MERGE_VALUES)
+
+/// Generic pointer to int conversion.
+HANDLE_TARGET_OPCODE(G_PTRTOINT)
+
+/// Generic int to pointer conversion.
+HANDLE_TARGET_OPCODE(G_INTTOPTR)
+
+/// Generic bitcast. The source and destination types must be different, or a
+/// COPY is the relevant instruction.
+HANDLE_TARGET_OPCODE(G_BITCAST)
+
+/// Generic load (including anyext load)
+HANDLE_TARGET_OPCODE(G_LOAD)
+
+/// Generic signext load
+HANDLE_TARGET_OPCODE(G_SEXTLOAD)
+
+/// Generic zeroext load
+HANDLE_TARGET_OPCODE(G_ZEXTLOAD)
+
+/// Generic store.
+HANDLE_TARGET_OPCODE(G_STORE)
+
+/// Generic atomic cmpxchg with internal success check.
+HANDLE_TARGET_OPCODE(G_ATOMIC_CMPXCHG_WITH_SUCCESS)
+
+/// Generic atomic cmpxchg.
+HANDLE_TARGET_OPCODE(G_ATOMIC_CMPXCHG)
+
+/// Generic atomicrmw.
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_XCHG)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_ADD)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_SUB)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_AND)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_NAND)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_OR)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_XOR)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_MAX)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_MIN)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_UMAX)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_UMIN)
+
+/// Generic conditional branch instruction.
+HANDLE_TARGET_OPCODE(G_BRCOND)
+
+/// Generic indirect branch instruction.
+HANDLE_TARGET_OPCODE(G_BRINDIRECT)
+
+/// Generic intrinsic use (without side effects).
+HANDLE_TARGET_OPCODE(G_INTRINSIC)
+
+/// Generic intrinsic use (with side effects).
+HANDLE_TARGET_OPCODE(G_INTRINSIC_W_SIDE_EFFECTS)
+
+/// Generic extension allowing rubbish in high bits.
+HANDLE_TARGET_OPCODE(G_ANYEXT)
+
+/// Generic instruction to discard the high bits of a register. This differs
+/// from (G_EXTRACT val, 0) on its action on vectors: G_TRUNC will truncate
+/// each element individually, G_EXTRACT will typically discard the high
+/// elements of the vector.
+HANDLE_TARGET_OPCODE(G_TRUNC)
+
+/// Generic integer constant.
+HANDLE_TARGET_OPCODE(G_CONSTANT)
+
+/// Generic floating constant.
+HANDLE_TARGET_OPCODE(G_FCONSTANT)
+
+/// Generic va_start instruction. Stores to its one pointer operand.
+HANDLE_TARGET_OPCODE(G_VASTART)
+
+/// Generic va_start instruction. Stores to its one pointer operand.
+HANDLE_TARGET_OPCODE(G_VAARG)
+
+// Generic sign extend
+HANDLE_TARGET_OPCODE(G_SEXT)
+
+// Generic zero extend
+HANDLE_TARGET_OPCODE(G_ZEXT)
+
+// Generic left-shift
+HANDLE_TARGET_OPCODE(G_SHL)
+
+// Generic logical right-shift
+HANDLE_TARGET_OPCODE(G_LSHR)
+
+// Generic arithmetic right-shift
+HANDLE_TARGET_OPCODE(G_ASHR)
+
+/// Generic integer-base comparison, also applicable to vectors of integers.
+HANDLE_TARGET_OPCODE(G_ICMP)
+
+/// Generic floating-point comparison, also applicable to vectors.
+HANDLE_TARGET_OPCODE(G_FCMP)
+
+/// Generic select.
+HANDLE_TARGET_OPCODE(G_SELECT)
+
+/// Generic unsigned add instruction, consuming the normal operands plus a carry
+/// flag, and similarly producing the result and a carry flag.
+HANDLE_TARGET_OPCODE(G_UADDE)
+
+/// Generic unsigned subtract instruction, consuming the normal operands plus a
+/// carry flag, and similarly producing the result and a carry flag.
+HANDLE_TARGET_OPCODE(G_USUBE)
+
+/// Generic signed add instruction, producing the result and a signed overflow
+/// flag.
+HANDLE_TARGET_OPCODE(G_SADDO)
+
+/// Generic signed subtract instruction, producing the result and a signed
+/// overflow flag.
+HANDLE_TARGET_OPCODE(G_SSUBO)
+
+/// Generic unsigned multiply instruction, producing the result and a signed
+/// overflow flag.
+HANDLE_TARGET_OPCODE(G_UMULO)
+
+/// Generic signed multiply instruction, producing the result and a signed
+/// overflow flag.
+HANDLE_TARGET_OPCODE(G_SMULO)
+
+// Multiply two numbers at twice the incoming bit width (unsigned) and return
+// the high half of the result.
+HANDLE_TARGET_OPCODE(G_UMULH)
+
+// Multiply two numbers at twice the incoming bit width (signed) and return
+// the high half of the result.
+HANDLE_TARGET_OPCODE(G_SMULH)
+
+/// Generic FP addition.
+HANDLE_TARGET_OPCODE(G_FADD)
+
+/// Generic FP subtraction.
+HANDLE_TARGET_OPCODE(G_FSUB)
+
+/// Generic FP multiplication.
+HANDLE_TARGET_OPCODE(G_FMUL)
+
+/// Generic FMA multiplication. Behaves like llvm fma intrinsic
+HANDLE_TARGET_OPCODE(G_FMA)
+
+/// Generic FP division.
+HANDLE_TARGET_OPCODE(G_FDIV)
+
+/// Generic FP remainder.
+HANDLE_TARGET_OPCODE(G_FREM)
+
+/// Generic FP exponentiation.
+HANDLE_TARGET_OPCODE(G_FPOW)
+
+/// Generic base-e exponential of a value.
+HANDLE_TARGET_OPCODE(G_FEXP)
+
+/// Generic base-2 exponential of a value.
+HANDLE_TARGET_OPCODE(G_FEXP2)
+
+/// Floating point base-e logarithm of a value.
+HANDLE_TARGET_OPCODE(G_FLOG)
+
+/// Floating point base-2 logarithm of a value.
+HANDLE_TARGET_OPCODE(G_FLOG2)
+
+/// Generic FP negation.
+HANDLE_TARGET_OPCODE(G_FNEG)
+
+/// Generic FP extension.
+HANDLE_TARGET_OPCODE(G_FPEXT)
+
+/// Generic float to signed-int conversion
+HANDLE_TARGET_OPCODE(G_FPTRUNC)
+
+/// Generic float to signed-int conversion
+HANDLE_TARGET_OPCODE(G_FPTOSI)
+
+/// Generic float to unsigned-int conversion
+HANDLE_TARGET_OPCODE(G_FPTOUI)
+
+/// Generic signed-int to float conversion
+HANDLE_TARGET_OPCODE(G_SITOFP)
+
+/// Generic unsigned-int to float conversion
+HANDLE_TARGET_OPCODE(G_UITOFP)
+
+/// Generic FP absolute value.
+HANDLE_TARGET_OPCODE(G_FABS)
+
+/// Generic pointer offset
+HANDLE_TARGET_OPCODE(G_GEP)
+
+/// Clear the specified number of low bits in a pointer. This rounds the value
+/// *down* to the given alignment.
+HANDLE_TARGET_OPCODE(G_PTR_MASK)
+
+/// Generic BRANCH instruction. This is an unconditional branch.
+HANDLE_TARGET_OPCODE(G_BR)
+
+/// Generic insertelement.
+HANDLE_TARGET_OPCODE(G_INSERT_VECTOR_ELT)
+
+/// Generic extractelement.
+HANDLE_TARGET_OPCODE(G_EXTRACT_VECTOR_ELT)
+
+/// Generic shufflevector.
+HANDLE_TARGET_OPCODE(G_SHUFFLE_VECTOR)
+
+/// Generic byte swap.
+HANDLE_TARGET_OPCODE(G_BSWAP)
+
+/// Generic AddressSpaceCast.
+HANDLE_TARGET_OPCODE(G_ADDRSPACE_CAST)
+
+// TODO: Add more generic opcodes as we move along.
+
+/// Marker for the end of the generic opcode.
+/// This is used to check if an opcode is in the range of the
+/// generic opcodes.
+HANDLE_TARGET_OPCODE_MARKER(PRE_ISEL_GENERIC_OPCODE_END, G_ADDRSPACE_CAST)
+
+/// BUILTIN_OP_END - This must be the last enum value in this list.
+/// The target-specific post-isel opcode values start here.
+HANDLE_TARGET_OPCODE_MARKER(GENERIC_OP_END, PRE_ISEL_GENERIC_OPCODE_END)
diff --git a/include/llvm/Support/TargetParser.h b/include/llvm/Support/TargetParser.h
index 13b7befb8ce4..08ad42dda3eb 100644
--- a/include/llvm/Support/TargetParser.h
+++ b/include/llvm/Support/TargetParser.h
@@ -86,6 +86,8 @@ enum ArchExtKind : unsigned {
AEK_RAS = 1 << 12,
AEK_SVE = 1 << 13,
AEK_DOTPROD = 1 << 14,
+ AEK_SHA2 = 1 << 15,
+ AEK_AES = 1 << 16,
// Unsupported extensions.
AEK_OS = 0x8000000,
AEK_IWMMXT = 0x10000000,
@@ -137,6 +139,7 @@ unsigned parseFPU(StringRef FPU);
ArchKind parseArch(StringRef Arch);
unsigned parseArchExt(StringRef ArchExt);
ArchKind parseCPUArch(StringRef CPU);
+void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values);
ISAKind parseArchISA(StringRef Arch);
EndianKind parseArchEndian(StringRef Arch);
ProfileKind parseArchProfile(StringRef Arch);
@@ -170,7 +173,11 @@ enum ArchExtKind : unsigned {
AEK_SVE = 1 << 9,
AEK_DOTPROD = 1 << 10,
AEK_RCPC = 1 << 11,
- AEK_RDM = 1 << 12
+ AEK_RDM = 1 << 12,
+ AEK_SM4 = 1 << 13,
+ AEK_SHA3 = 1 << 14,
+ AEK_SHA2 = 1 << 15,
+ AEK_AES = 1 << 16,
};
StringRef getCanonicalArchName(StringRef Arch);
@@ -199,17 +206,21 @@ unsigned checkArchVersion(StringRef Arch);
unsigned getDefaultFPU(StringRef CPU, ArchKind AK);
unsigned getDefaultExtensions(StringRef CPU, ArchKind AK);
StringRef getDefaultCPU(StringRef Arch);
+AArch64::ArchKind getCPUArchKind(StringRef CPU);
// Parser
unsigned parseFPU(StringRef FPU);
AArch64::ArchKind parseArch(StringRef Arch);
-unsigned parseArchExt(StringRef ArchExt);
+ArchExtKind parseArchExt(StringRef ArchExt);
ArchKind parseCPUArch(StringRef CPU);
+void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values);
ARM::ISAKind parseArchISA(StringRef Arch);
ARM::EndianKind parseArchEndian(StringRef Arch);
ARM::ProfileKind parseArchProfile(StringRef Arch);
unsigned parseArchVersion(StringRef Arch);
+bool isX18ReservedByDefault(const Triple &TT);
+
} // namespace AArch64
namespace X86 {
diff --git a/include/llvm/Support/TargetRegistry.h b/include/llvm/Support/TargetRegistry.h
index bd096e2f74f6..1bafc4e687da 100644
--- a/include/llvm/Support/TargetRegistry.h
+++ b/include/llvm/Support/TargetRegistry.h
@@ -19,7 +19,7 @@
#ifndef LLVM_SUPPORT_TARGETREGISTRY_H
#define LLVM_SUPPORT_TARGETREGISTRY_H
-#include "llvm-c/Disassembler.h"
+#include "llvm-c/DisassemblerTypes.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
@@ -46,6 +46,7 @@ class MCDisassembler;
class MCInstPrinter;
class MCInstrAnalysis;
class MCInstrInfo;
+class MCObjectWriter;
class MCRegisterInfo;
class MCRelocationInfo;
class MCStreamer;
@@ -60,27 +61,44 @@ class TargetMachine;
class TargetOptions;
MCStreamer *createNullStreamer(MCContext &Ctx);
-MCStreamer *createAsmStreamer(MCContext &Ctx,
- std::unique_ptr<formatted_raw_ostream> OS,
- bool isVerboseAsm, bool useDwarfDirectory,
- MCInstPrinter *InstPrint, MCCodeEmitter *CE,
- MCAsmBackend *TAB, bool ShowInst);
+// Takes ownership of \p TAB and \p CE.
+
+/// Create a machine code streamer which will print out assembly for the native
+/// target, suitable for compiling with a native assembler.
+///
+/// \param InstPrint - If given, the instruction printer to use. If not given
+/// the MCInst representation will be printed. This method takes ownership of
+/// InstPrint.
+///
+/// \param CE - If given, a code emitter to use to show the instruction
+/// encoding inline with the assembly. This method takes ownership of \p CE.
+///
+/// \param TAB - If given, a target asm backend to use to show the fixup
+/// information in conjunction with encoding information. This method takes
+/// ownership of \p TAB.
+///
+/// \param ShowInst - Whether to show the MCInst representation inline with
+/// the assembly.
+MCStreamer *
+createAsmStreamer(MCContext &Ctx, std::unique_ptr<formatted_raw_ostream> OS,
+ bool isVerboseAsm, bool useDwarfDirectory,
+ MCInstPrinter *InstPrint, std::unique_ptr<MCCodeEmitter> &&CE,
+ std::unique_ptr<MCAsmBackend> &&TAB, bool ShowInst);
-/// Takes ownership of \p TAB and \p CE.
MCStreamer *createELFStreamer(MCContext &Ctx,
std::unique_ptr<MCAsmBackend> &&TAB,
- raw_pwrite_stream &OS,
+ std::unique_ptr<MCObjectWriter> &&OW,
std::unique_ptr<MCCodeEmitter> &&CE,
bool RelaxAll);
MCStreamer *createMachOStreamer(MCContext &Ctx,
std::unique_ptr<MCAsmBackend> &&TAB,
- raw_pwrite_stream &OS,
+ std::unique_ptr<MCObjectWriter> &&OW,
std::unique_ptr<MCCodeEmitter> &&CE,
bool RelaxAll, bool DWARFMustBeAtTheEnd,
bool LabelSections = false);
MCStreamer *createWasmStreamer(MCContext &Ctx,
std::unique_ptr<MCAsmBackend> &&TAB,
- raw_pwrite_stream &OS,
+ std::unique_ptr<MCObjectWriter> &&OW,
std::unique_ptr<MCCodeEmitter> &&CE,
bool RelaxAll);
@@ -123,8 +141,8 @@ public:
using AsmPrinterCtorTy = AsmPrinter *(*)(
TargetMachine &TM, std::unique_ptr<MCStreamer> &&Streamer);
using MCAsmBackendCtorTy = MCAsmBackend *(*)(const Target &T,
+ const MCSubtargetInfo &STI,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU,
const MCTargetOptions &Options);
using MCAsmParserCtorTy = MCTargetAsmParser *(*)(
const MCSubtargetInfo &STI, MCAsmParser &P, const MCInstrInfo &MII,
@@ -143,22 +161,22 @@ public:
using ELFStreamerCtorTy =
MCStreamer *(*)(const Triple &T, MCContext &Ctx,
std::unique_ptr<MCAsmBackend> &&TAB,
- raw_pwrite_stream &OS,
+ std::unique_ptr<MCObjectWriter> &&OW,
std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll);
using MachOStreamerCtorTy =
MCStreamer *(*)(MCContext &Ctx, std::unique_ptr<MCAsmBackend> &&TAB,
- raw_pwrite_stream &OS,
+ std::unique_ptr<MCObjectWriter> &&OW,
std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll,
bool DWARFMustBeAtTheEnd);
using COFFStreamerCtorTy =
MCStreamer *(*)(MCContext &Ctx, std::unique_ptr<MCAsmBackend> &&TAB,
- raw_pwrite_stream &OS,
+ std::unique_ptr<MCObjectWriter> &&OW,
std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll,
bool IncrementalLinkerCompatible);
using WasmStreamerCtorTy =
MCStreamer *(*)(const Triple &T, MCContext &Ctx,
std::unique_ptr<MCAsmBackend> &&TAB,
- raw_pwrite_stream &OS,
+ std::unique_ptr<MCObjectWriter> &&OW,
std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll);
using NullTargetStreamerCtorTy = MCTargetStreamer *(*)(MCStreamer &S);
using AsmTargetStreamerCtorTy = MCTargetStreamer *(*)(
@@ -381,15 +399,12 @@ public:
}
/// createMCAsmBackend - Create a target specific assembly parser.
- ///
- /// \param TheTriple The target triple string.
- MCAsmBackend *createMCAsmBackend(const MCRegisterInfo &MRI,
- StringRef TheTriple, StringRef CPU,
- const MCTargetOptions &Options)
- const {
+ MCAsmBackend *createMCAsmBackend(const MCSubtargetInfo &STI,
+ const MCRegisterInfo &MRI,
+ const MCTargetOptions &Options) const {
if (!MCAsmBackendCtorFn)
return nullptr;
- return MCAsmBackendCtorFn(*this, MRI, Triple(TheTriple), CPU, Options);
+ return MCAsmBackendCtorFn(*this, STI, MRI, Options);
}
/// createMCAsmParser - Create a target specific assembly parser.
@@ -444,12 +459,12 @@ public:
/// \param T The target triple.
/// \param Ctx The target context.
/// \param TAB The target assembler backend object. Takes ownership.
- /// \param OS The stream object.
+ /// \param OW The stream object.
/// \param Emitter The target independent assembler object.Takes ownership.
/// \param RelaxAll Relax all fixups?
MCStreamer *createMCObjectStreamer(const Triple &T, MCContext &Ctx,
std::unique_ptr<MCAsmBackend> &&TAB,
- raw_pwrite_stream &OS,
+ std::unique_ptr<MCObjectWriter> &&OW,
std::unique_ptr<MCCodeEmitter> &&Emitter,
const MCSubtargetInfo &STI, bool RelaxAll,
bool IncrementalLinkerCompatible,
@@ -460,32 +475,35 @@ public:
llvm_unreachable("Unknown object format");
case Triple::COFF:
assert(T.isOSWindows() && "only Windows COFF is supported");
- S = COFFStreamerCtorFn(Ctx, std::move(TAB), OS, std::move(Emitter),
- RelaxAll, IncrementalLinkerCompatible);
+ S = COFFStreamerCtorFn(Ctx, std::move(TAB), std::move(OW),
+ std::move(Emitter), RelaxAll,
+ IncrementalLinkerCompatible);
break;
case Triple::MachO:
if (MachOStreamerCtorFn)
- S = MachOStreamerCtorFn(Ctx, std::move(TAB), OS, std::move(Emitter),
- RelaxAll, DWARFMustBeAtTheEnd);
+ S = MachOStreamerCtorFn(Ctx, std::move(TAB), std::move(OW),
+ std::move(Emitter), RelaxAll,
+ DWARFMustBeAtTheEnd);
else
- S = createMachOStreamer(Ctx, std::move(TAB), OS, std::move(Emitter),
- RelaxAll, DWARFMustBeAtTheEnd);
+ S = createMachOStreamer(Ctx, std::move(TAB), std::move(OW),
+ std::move(Emitter), RelaxAll,
+ DWARFMustBeAtTheEnd);
break;
case Triple::ELF:
if (ELFStreamerCtorFn)
- S = ELFStreamerCtorFn(T, Ctx, std::move(TAB), OS, std::move(Emitter),
- RelaxAll);
+ S = ELFStreamerCtorFn(T, Ctx, std::move(TAB), std::move(OW),
+ std::move(Emitter), RelaxAll);
else
- S = createELFStreamer(Ctx, std::move(TAB), OS, std::move(Emitter),
- RelaxAll);
+ S = createELFStreamer(Ctx, std::move(TAB), std::move(OW),
+ std::move(Emitter), RelaxAll);
break;
case Triple::Wasm:
if (WasmStreamerCtorFn)
- S = WasmStreamerCtorFn(T, Ctx, std::move(TAB), OS, std::move(Emitter),
- RelaxAll);
+ S = WasmStreamerCtorFn(T, Ctx, std::move(TAB), std::move(OW),
+ std::move(Emitter), RelaxAll);
else
- S = createWasmStreamer(Ctx, std::move(TAB), OS, std::move(Emitter),
- RelaxAll);
+ S = createWasmStreamer(Ctx, std::move(TAB), std::move(OW),
+ std::move(Emitter), RelaxAll);
break;
}
if (ObjectTargetStreamerCtorFn)
@@ -496,12 +514,14 @@ public:
MCStreamer *createAsmStreamer(MCContext &Ctx,
std::unique_ptr<formatted_raw_ostream> OS,
bool IsVerboseAsm, bool UseDwarfDirectory,
- MCInstPrinter *InstPrint, MCCodeEmitter *CE,
- MCAsmBackend *TAB, bool ShowInst) const {
+ MCInstPrinter *InstPrint,
+ std::unique_ptr<MCCodeEmitter> &&CE,
+ std::unique_ptr<MCAsmBackend> &&TAB,
+ bool ShowInst) const {
formatted_raw_ostream &OSRef = *OS;
- MCStreamer *S = llvm::createAsmStreamer(Ctx, std::move(OS), IsVerboseAsm,
- UseDwarfDirectory, InstPrint, CE,
- TAB, ShowInst);
+ MCStreamer *S = llvm::createAsmStreamer(
+ Ctx, std::move(OS), IsVerboseAsm, UseDwarfDirectory, InstPrint,
+ std::move(CE), std::move(TAB), ShowInst);
createAsmTargetStreamer(*S, OSRef, InstPrint, IsVerboseAsm);
return S;
}
@@ -1106,10 +1126,10 @@ template <class MCAsmBackendImpl> struct RegisterMCAsmBackend {
}
private:
- static MCAsmBackend *Allocator(const Target &T, const MCRegisterInfo &MRI,
- const Triple &TheTriple, StringRef CPU,
+ static MCAsmBackend *Allocator(const Target &T, const MCSubtargetInfo &STI,
+ const MCRegisterInfo &MRI,
const MCTargetOptions &Options) {
- return new MCAsmBackendImpl(T, MRI, TheTriple, CPU);
+ return new MCAsmBackendImpl(T, STI, MRI);
}
};
diff --git a/include/llvm/Support/TaskQueue.h b/include/llvm/Support/TaskQueue.h
new file mode 100644
index 000000000000..49981adb763d
--- /dev/null
+++ b/include/llvm/Support/TaskQueue.h
@@ -0,0 +1,139 @@
+//===-- llvm/Support/TaskQueue.h - A TaskQueue implementation ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a crude C++11 based task queue.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_TASK_QUEUE_H
+#define LLVM_SUPPORT_TASK_QUEUE_H
+
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/ThreadPool.h"
+#include "llvm/Support/thread.h"
+
+#include <atomic>
+#include <cassert>
+#include <condition_variable>
+#include <deque>
+#include <functional>
+#include <future>
+#include <memory>
+#include <mutex>
+#include <utility>
+
+namespace llvm {
+/// TaskQueue executes serialized work on a user-defined Thread Pool. It
+/// guarantees that if task B is enqueued after task A, task B begins after
+/// task A completes and there is no overlap between the two.
+class TaskQueue {
+ // Because we don't have init capture to use move-only local variables that
+ // are captured into a lambda, we create the promise inside an explicit
+ // callable struct. We want to do as much of the wrapping in the
+ // type-specialized domain (before type erasure) and then erase this into a
+ // std::function.
+ template <typename Callable> struct Task {
+ using ResultTy = typename std::result_of<Callable()>::type;
+ explicit Task(Callable C, TaskQueue &Parent)
+ : C(std::move(C)), P(std::make_shared<std::promise<ResultTy>>()),
+ Parent(&Parent) {}
+
+ template<typename T>
+ void invokeCallbackAndSetPromise(T*) {
+ P->set_value(C());
+ }
+
+ void invokeCallbackAndSetPromise(void*) {
+ C();
+ P->set_value();
+ }
+
+ void operator()() noexcept {
+ ResultTy *Dummy = nullptr;
+ invokeCallbackAndSetPromise(Dummy);
+ Parent->completeTask();
+ }
+
+ Callable C;
+ std::shared_ptr<std::promise<ResultTy>> P;
+ TaskQueue *Parent;
+ };
+
+public:
+ /// Construct a task queue with no work.
+ TaskQueue(ThreadPool &Scheduler) : Scheduler(Scheduler) { (void)Scheduler; }
+
+ /// Blocking destructor: the queue will wait for all work to complete.
+ ~TaskQueue() {
+ Scheduler.wait();
+ assert(Tasks.empty());
+ }
+
+ /// Asynchronous submission of a task to the queue. The returned future can be
+ /// used to wait for the task (and all previous tasks that have not yet
+ /// completed) to finish.
+ template <typename Callable>
+ std::future<typename std::result_of<Callable()>::type> async(Callable &&C) {
+#if !LLVM_ENABLE_THREADS
+ static_assert(false,
+ "TaskQueue requires building with LLVM_ENABLE_THREADS!");
+#endif
+ Task<Callable> T{std::move(C), *this};
+ using ResultTy = typename std::result_of<Callable()>::type;
+ std::future<ResultTy> F = T.P->get_future();
+ {
+ std::lock_guard<std::mutex> Lock(QueueLock);
+ // If there's already a task in flight, just queue this one up. If
+ // there is not a task in flight, bypass the queue and schedule this
+ // task immediately.
+ if (IsTaskInFlight)
+ Tasks.push_back(std::move(T));
+ else {
+ Scheduler.async(std::move(T));
+ IsTaskInFlight = true;
+ }
+ }
+ return std::move(F);
+ }
+
+private:
+ void completeTask() {
+ // We just completed a task. If there are no more tasks in the queue,
+ // update IsTaskInFlight to false and stop doing work. Otherwise
+ // schedule the next task (while not holding the lock).
+ std::function<void()> Continuation;
+ {
+ std::lock_guard<std::mutex> Lock(QueueLock);
+ if (Tasks.empty()) {
+ IsTaskInFlight = false;
+ return;
+ }
+
+ Continuation = std::move(Tasks.front());
+ Tasks.pop_front();
+ }
+ Scheduler.async(std::move(Continuation));
+ }
+
+ /// The thread pool on which to run the work.
+ ThreadPool &Scheduler;
+
+ /// State which indicates whether the queue currently is currently processing
+ /// any work.
+ bool IsTaskInFlight = false;
+
+ /// Mutex for synchronizing access to the Tasks array.
+ std::mutex QueueLock;
+
+ /// Tasks waiting for execution in the queue.
+ std::deque<std::function<void()>> Tasks;
+};
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_TASK_QUEUE_H
diff --git a/include/llvm/Support/ThreadLocal.h b/include/llvm/Support/ThreadLocal.h
index 427a67e2a96d..885bd18e8356 100644
--- a/include/llvm/Support/ThreadLocal.h
+++ b/include/llvm/Support/ThreadLocal.h
@@ -24,7 +24,7 @@ namespace llvm {
// YOU SHOULD NEVER USE THIS DIRECTLY.
class ThreadLocalImpl {
typedef uint64_t ThreadLocalDataTy;
- /// \brief Platform-specific thread local data.
+ /// Platform-specific thread local data.
///
/// This is embedded in the class and we avoid malloc'ing/free'ing it,
/// to make this class more safe for use along with CrashRecoveryContext.
diff --git a/include/llvm/Support/ThreadPool.h b/include/llvm/Support/ThreadPool.h
index fb8255900510..4fdbd528b212 100644
--- a/include/llvm/Support/ThreadPool.h
+++ b/include/llvm/Support/ThreadPool.h
@@ -14,6 +14,7 @@
#ifndef LLVM_SUPPORT_THREAD_POOL_H
#define LLVM_SUPPORT_THREAD_POOL_H
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/thread.h"
#include <future>
diff --git a/include/llvm/Support/Threading.h b/include/llvm/Support/Threading.h
index 6d813bccb93f..e8021f648b0d 100644
--- a/include/llvm/Support/Threading.h
+++ b/include/llvm/Support/Threading.h
@@ -72,7 +72,7 @@ void llvm_execute_on_thread(void (*UserFn)(void *), void *UserData,
enum InitStatus { Uninitialized = 0, Wait = 1, Done = 2 };
- /// \brief The llvm::once_flag structure
+ /// The llvm::once_flag structure
///
/// This type is modeled after std::once_flag to use with llvm::call_once.
/// This structure must be used as an opaque object. It is a struct to force
@@ -83,7 +83,7 @@ void llvm_execute_on_thread(void (*UserFn)(void *), void *UserData,
#endif
- /// \brief Execute the function specified as a parameter once.
+ /// Execute the function specified as a parameter once.
///
/// Typical usage:
/// \code
@@ -139,17 +139,17 @@ void llvm_execute_on_thread(void (*UserFn)(void *), void *UserData,
/// not available.
unsigned hardware_concurrency();
- /// \brief Return the current thread id, as used in various OS system calls.
+ /// Return the current thread id, as used in various OS system calls.
/// Note that not all platforms guarantee that the value returned will be
/// unique across the entire system, so portable code should not assume
/// this.
uint64_t get_threadid();
- /// \brief Get the maximum length of a thread name on this platform.
+ /// Get the maximum length of a thread name on this platform.
/// A value of 0 means there is no limit.
uint32_t get_max_thread_name_length();
- /// \brief Set the name of the current thread. Setting a thread's name can
+ /// Set the name of the current thread. Setting a thread's name can
/// be helpful for enabling useful diagnostics under a debugger or when
/// logging. The level of support for setting a thread's name varies
/// wildly across operating systems, and we only make a best effort to
@@ -157,7 +157,7 @@ void llvm_execute_on_thread(void (*UserFn)(void *), void *UserData,
/// or failure is returned.
void set_thread_name(const Twine &Name);
- /// \brief Get the name of the current thread. The level of support for
+ /// Get the name of the current thread. The level of support for
/// getting a thread's name varies wildly across operating systems, and it
/// is not even guaranteed that if you can successfully set a thread's name
/// that you can later get it back. This function is intended for diagnostic
diff --git a/include/llvm/Support/Timer.h b/include/llvm/Support/Timer.h
index 198855ae0377..bfffbc3157b1 100644
--- a/include/llvm/Support/Timer.h
+++ b/include/llvm/Support/Timer.h
@@ -10,6 +10,7 @@
#ifndef LLVM_SUPPORT_TIMER_H
#define LLVM_SUPPORT_TIMER_H
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/DataTypes.h"
#include <cassert>
@@ -194,6 +195,10 @@ class TimerGroup {
public:
explicit TimerGroup(StringRef Name, StringRef Description);
+
+ explicit TimerGroup(StringRef Name, StringRef Description,
+ const StringMap<TimeRecord> &Records);
+
~TimerGroup();
void setName(StringRef NewName, StringRef NewDescription) {
@@ -207,6 +212,8 @@ public:
/// This static method prints all timers and clears them all out.
static void printAll(raw_ostream &OS);
+ const char *printJSONValues(raw_ostream &OS, const char *delim);
+
/// Prints all timers as JSON key/value pairs, and clears them all out.
static const char *printAllJSONValues(raw_ostream &OS, const char *delim);
@@ -223,7 +230,6 @@ private:
void PrintQueuedTimers(raw_ostream &OS);
void printJSONValue(raw_ostream &OS, const PrintRecord &R,
const char *suffix, double Value);
- const char *printJSONValues(raw_ostream &OS, const char *delim);
};
} // end namespace llvm
diff --git a/include/llvm/Support/ToolOutputFile.h b/include/llvm/Support/ToolOutputFile.h
index b41ca5a6edaa..cf3bc2fb0171 100644
--- a/include/llvm/Support/ToolOutputFile.h
+++ b/include/llvm/Support/ToolOutputFile.h
@@ -35,7 +35,7 @@ class ToolOutputFile {
/// The flag which indicates whether we should not delete the file.
bool Keep;
- explicit CleanupInstaller(StringRef ilename);
+ explicit CleanupInstaller(StringRef Filename);
~CleanupInstaller();
} Installer;
@@ -43,7 +43,7 @@ class ToolOutputFile {
raw_fd_ostream OS;
public:
- /// This constructor's arguments are passed to to raw_fd_ostream's
+ /// This constructor's arguments are passed to raw_fd_ostream's
/// constructor.
ToolOutputFile(StringRef Filename, std::error_code &EC,
sys::fs::OpenFlags Flags);
diff --git a/include/llvm/Support/TrailingObjects.h b/include/llvm/Support/TrailingObjects.h
index cb5a52b0d861..490bd94f4cd5 100644
--- a/include/llvm/Support/TrailingObjects.h
+++ b/include/llvm/Support/TrailingObjects.h
@@ -89,25 +89,25 @@ protected:
};
/// This helper template works-around MSVC 2013's lack of useful
-/// alignas() support. The argument to LLVM_ALIGNAS(), in MSVC, is
+/// alignas() support. The argument to alignas(), in MSVC, is
/// required to be a literal integer. But, you *can* use template
-/// specialization to select between a bunch of different LLVM_ALIGNAS
+/// specialization to select between a bunch of different alignas()
/// expressions...
template <int Align>
class TrailingObjectsAligner : public TrailingObjectsBase {};
template <>
-class LLVM_ALIGNAS(1) TrailingObjectsAligner<1> : public TrailingObjectsBase {};
+class alignas(1) TrailingObjectsAligner<1> : public TrailingObjectsBase {};
template <>
-class LLVM_ALIGNAS(2) TrailingObjectsAligner<2> : public TrailingObjectsBase {};
+class alignas(2) TrailingObjectsAligner<2> : public TrailingObjectsBase {};
template <>
-class LLVM_ALIGNAS(4) TrailingObjectsAligner<4> : public TrailingObjectsBase {};
+class alignas(4) TrailingObjectsAligner<4> : public TrailingObjectsBase {};
template <>
-class LLVM_ALIGNAS(8) TrailingObjectsAligner<8> : public TrailingObjectsBase {};
+class alignas(8) TrailingObjectsAligner<8> : public TrailingObjectsBase {};
template <>
-class LLVM_ALIGNAS(16) TrailingObjectsAligner<16> : public TrailingObjectsBase {
+class alignas(16) TrailingObjectsAligner<16> : public TrailingObjectsBase {
};
template <>
-class LLVM_ALIGNAS(32) TrailingObjectsAligner<32> : public TrailingObjectsBase {
+class alignas(32) TrailingObjectsAligner<32> : public TrailingObjectsBase {
};
// Just a little helper for transforming a type pack into the same
diff --git a/include/llvm/Support/Unicode.h b/include/llvm/Support/Unicode.h
index adedb1ed83a6..983acaf03635 100644
--- a/include/llvm/Support/Unicode.h
+++ b/include/llvm/Support/Unicode.h
@@ -60,6 +60,10 @@ bool isPrintable(int UCS);
/// * 1 for each of the remaining characters.
int columnWidthUTF8(StringRef Text);
+/// Fold input unicode character according the Simple unicode case folding
+/// rules.
+int foldCharSimple(int C);
+
} // namespace unicode
} // namespace sys
} // namespace llvm
diff --git a/include/llvm/Support/UnicodeCharRanges.h b/include/llvm/Support/UnicodeCharRanges.h
index 4c655833b396..3cf4a6d96602 100644
--- a/include/llvm/Support/UnicodeCharRanges.h
+++ b/include/llvm/Support/UnicodeCharRanges.h
@@ -23,7 +23,7 @@
namespace llvm {
namespace sys {
-/// \brief Represents a closed range of Unicode code points [Lower, Upper].
+/// Represents a closed range of Unicode code points [Lower, Upper].
struct UnicodeCharRange {
uint32_t Lower;
uint32_t Upper;
@@ -36,14 +36,14 @@ inline bool operator<(UnicodeCharRange Range, uint32_t Value) {
return Range.Upper < Value;
}
-/// \brief Holds a reference to an ordered array of UnicodeCharRange and allows
+/// Holds a reference to an ordered array of UnicodeCharRange and allows
/// to quickly check if a code point is contained in the set represented by this
/// array.
class UnicodeCharSet {
public:
typedef ArrayRef<UnicodeCharRange> CharRanges;
- /// \brief Constructs a UnicodeCharSet instance from an array of
+ /// Constructs a UnicodeCharSet instance from an array of
/// UnicodeCharRanges.
///
/// Array pointed by \p Ranges should have the lifetime at least as long as
@@ -63,31 +63,31 @@ public:
}
#endif
- /// \brief Returns true if the character set contains the Unicode code point
+ /// Returns true if the character set contains the Unicode code point
/// \p C.
bool contains(uint32_t C) const {
return std::binary_search(Ranges.begin(), Ranges.end(), C);
}
private:
- /// \brief Returns true if each of the ranges is a proper closed range
+ /// Returns true if each of the ranges is a proper closed range
/// [min, max], and if the ranges themselves are ordered and non-overlapping.
bool rangesAreValid() const {
uint32_t Prev = 0;
for (CharRanges::const_iterator I = Ranges.begin(), E = Ranges.end();
I != E; ++I) {
if (I != Ranges.begin() && Prev >= I->Lower) {
- DEBUG(dbgs() << "Upper bound 0x");
- DEBUG(dbgs().write_hex(Prev));
- DEBUG(dbgs() << " should be less than succeeding lower bound 0x");
- DEBUG(dbgs().write_hex(I->Lower) << "\n");
+ LLVM_DEBUG(dbgs() << "Upper bound 0x");
+ LLVM_DEBUG(dbgs().write_hex(Prev));
+ LLVM_DEBUG(dbgs() << " should be less than succeeding lower bound 0x");
+ LLVM_DEBUG(dbgs().write_hex(I->Lower) << "\n");
return false;
}
if (I->Upper < I->Lower) {
- DEBUG(dbgs() << "Upper bound 0x");
- DEBUG(dbgs().write_hex(I->Lower));
- DEBUG(dbgs() << " should not be less than lower bound 0x");
- DEBUG(dbgs().write_hex(I->Upper) << "\n");
+ LLVM_DEBUG(dbgs() << "Upper bound 0x");
+ LLVM_DEBUG(dbgs().write_hex(I->Lower));
+ LLVM_DEBUG(dbgs() << " should not be less than lower bound 0x");
+ LLVM_DEBUG(dbgs().write_hex(I->Upper) << "\n");
return false;
}
Prev = I->Upper;
diff --git a/include/llvm/Support/UniqueLock.h b/include/llvm/Support/UniqueLock.h
index b4675f4b43ae..91dc911036d5 100644
--- a/include/llvm/Support/UniqueLock.h
+++ b/include/llvm/Support/UniqueLock.h
@@ -24,7 +24,7 @@ namespace llvm {
/// an associated mutex, which is guaranteed to be locked upon creation
/// and unlocked after destruction. unique_lock can also unlock the mutex
/// and re-lock it freely during its lifetime.
- /// @brief Guard a section of code with a mutex.
+ /// Guard a section of code with a mutex.
template<typename MutexT>
class unique_lock {
MutexT *M = nullptr;
diff --git a/include/llvm/Support/VersionTuple.h b/include/llvm/Support/VersionTuple.h
new file mode 100644
index 000000000000..e85a188e54b4
--- /dev/null
+++ b/include/llvm/Support/VersionTuple.h
@@ -0,0 +1,154 @@
+//===- VersionTuple.h - Version Number Handling -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Defines the llvm::VersionTuple class, which represents a version in
+/// the form major[.minor[.subminor]].
+///
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_SUPPORT_VERSIONTUPLE_H
+#define LLVM_SUPPORT_VERSIONTUPLE_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+#include <tuple>
+
+namespace llvm {
+
+/// Represents a version number in the form major[.minor[.subminor[.build]]].
+class VersionTuple {
+ unsigned Major : 32;
+
+ unsigned Minor : 31;
+ unsigned HasMinor : 1;
+
+ unsigned Subminor : 31;
+ unsigned HasSubminor : 1;
+
+ unsigned Build : 31;
+ unsigned HasBuild : 1;
+
+public:
+ VersionTuple()
+ : Major(0), Minor(0), HasMinor(false), Subminor(0), HasSubminor(false),
+ Build(0), HasBuild(false) {}
+
+ explicit VersionTuple(unsigned Major)
+ : Major(Major), Minor(0), HasMinor(false), Subminor(0),
+ HasSubminor(false), Build(0), HasBuild(false) {}
+
+ explicit VersionTuple(unsigned Major, unsigned Minor)
+ : Major(Major), Minor(Minor), HasMinor(true), Subminor(0),
+ HasSubminor(false), Build(0), HasBuild(false) {}
+
+ explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor)
+ : Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor),
+ HasSubminor(true), Build(0), HasBuild(false) {}
+
+ explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor,
+ unsigned Build)
+ : Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor),
+ HasSubminor(true), Build(Build), HasBuild(true) {}
+
+ /// Determine whether this version information is empty
+ /// (e.g., all version components are zero).
+ bool empty() const {
+ return Major == 0 && Minor == 0 && Subminor == 0 && Build == 0;
+ }
+
+ /// Retrieve the major version number.
+ unsigned getMajor() const { return Major; }
+
+ /// Retrieve the minor version number, if provided.
+ Optional<unsigned> getMinor() const {
+ if (!HasMinor)
+ return None;
+ return Minor;
+ }
+
+ /// Retrieve the subminor version number, if provided.
+ Optional<unsigned> getSubminor() const {
+ if (!HasSubminor)
+ return None;
+ return Subminor;
+ }
+
+ /// Retrieve the build version number, if provided.
+ Optional<unsigned> getBuild() const {
+ if (!HasBuild)
+ return None;
+ return Build;
+ }
+
+ /// Determine if two version numbers are equivalent. If not
+ /// provided, minor and subminor version numbers are considered to be zero.
+ friend bool operator==(const VersionTuple &X, const VersionTuple &Y) {
+ return X.Major == Y.Major && X.Minor == Y.Minor &&
+ X.Subminor == Y.Subminor && X.Build == Y.Build;
+ }
+
+ /// Determine if two version numbers are not equivalent.
+ ///
+ /// If not provided, minor and subminor version numbers are considered to be
+ /// zero.
+ friend bool operator!=(const VersionTuple &X, const VersionTuple &Y) {
+ return !(X == Y);
+ }
+
+ /// Determine whether one version number precedes another.
+ ///
+ /// If not provided, minor and subminor version numbers are considered to be
+ /// zero.
+ friend bool operator<(const VersionTuple &X, const VersionTuple &Y) {
+ return std::tie(X.Major, X.Minor, X.Subminor, X.Build) <
+ std::tie(Y.Major, Y.Minor, Y.Subminor, Y.Build);
+ }
+
+ /// Determine whether one version number follows another.
+ ///
+ /// If not provided, minor and subminor version numbers are considered to be
+ /// zero.
+ friend bool operator>(const VersionTuple &X, const VersionTuple &Y) {
+ return Y < X;
+ }
+
+ /// Determine whether one version number precedes or is
+ /// equivalent to another.
+ ///
+ /// If not provided, minor and subminor version numbers are considered to be
+ /// zero.
+ friend bool operator<=(const VersionTuple &X, const VersionTuple &Y) {
+ return !(Y < X);
+ }
+
+ /// Determine whether one version number follows or is
+ /// equivalent to another.
+ ///
+ /// If not provided, minor and subminor version numbers are considered to be
+ /// zero.
+ friend bool operator>=(const VersionTuple &X, const VersionTuple &Y) {
+ return !(X < Y);
+ }
+
+ /// Retrieve a string representation of the version number.
+ std::string getAsString() const;
+
+ /// Try to parse the given string as a version number.
+ /// \returns \c true if the string does not match the regular expression
+ /// [0-9]+(\.[0-9]+){0,3}
+ bool tryParse(StringRef string);
+};
+
+/// Print a version number.
+raw_ostream &operator<<(raw_ostream &Out, const VersionTuple &V);
+
+} // end namespace llvm
+#endif // LLVM_SUPPORT_VERSIONTUPLE_H
diff --git a/include/llvm/Support/Win64EH.h b/include/llvm/Support/Win64EH.h
index f6c492794875..928eb906de0c 100644
--- a/include/llvm/Support/Win64EH.h
+++ b/include/llvm/Support/Win64EH.h
@@ -101,40 +101,40 @@ struct UnwindInfo {
// For more information please see MSDN at:
// http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
- /// \brief Return pointer to language specific data part of UnwindInfo.
+ /// Return pointer to language specific data part of UnwindInfo.
void *getLanguageSpecificData() {
return reinterpret_cast<void *>(&UnwindCodes[(NumCodes+1) & ~1]);
}
- /// \brief Return pointer to language specific data part of UnwindInfo.
+ /// Return pointer to language specific data part of UnwindInfo.
const void *getLanguageSpecificData() const {
return reinterpret_cast<const void *>(&UnwindCodes[(NumCodes + 1) & ~1]);
}
- /// \brief Return image-relative offset of language-specific exception handler.
+ /// Return image-relative offset of language-specific exception handler.
uint32_t getLanguageSpecificHandlerOffset() const {
return *reinterpret_cast<const support::ulittle32_t *>(
getLanguageSpecificData());
}
- /// \brief Set image-relative offset of language-specific exception handler.
+ /// Set image-relative offset of language-specific exception handler.
void setLanguageSpecificHandlerOffset(uint32_t offset) {
*reinterpret_cast<support::ulittle32_t *>(getLanguageSpecificData()) =
offset;
}
- /// \brief Return pointer to exception-specific data.
+ /// Return pointer to exception-specific data.
void *getExceptionData() {
return reinterpret_cast<void *>(reinterpret_cast<uint32_t *>(
getLanguageSpecificData())+1);
}
- /// \brief Return pointer to chained unwind info.
+ /// Return pointer to chained unwind info.
RuntimeFunction *getChainedFunctionEntry() {
return reinterpret_cast<RuntimeFunction *>(getLanguageSpecificData());
}
- /// \brief Return pointer to chained unwind info.
+ /// Return pointer to chained unwind info.
const RuntimeFunction *getChainedFunctionEntry() const {
return reinterpret_cast<const RuntimeFunction *>(getLanguageSpecificData());
}
diff --git a/include/llvm/Support/WithColor.h b/include/llvm/Support/WithColor.h
new file mode 100644
index 000000000000..85fc5fa0cf14
--- /dev/null
+++ b/include/llvm/Support/WithColor.h
@@ -0,0 +1,67 @@
+//===- WithColor.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_WITHCOLOR_H
+#define LLVM_SUPPORT_WITHCOLOR_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/CommandLine.h"
+
+namespace llvm {
+
+extern cl::OptionCategory ColorCategory;
+
+class raw_ostream;
+
+// Symbolic names for various syntax elements.
+enum class HighlightColor {
+ Address,
+ String,
+ Tag,
+ Attribute,
+ Enumerator,
+ Macro,
+ Error,
+ Warning,
+ Note
+};
+
+/// An RAII object that temporarily switches an output stream to a specific
+/// color.
+class WithColor {
+ raw_ostream &OS;
+ /// Determine whether colors should be displayed.
+ bool colorsEnabled(raw_ostream &OS);
+
+public:
+ /// To be used like this: WithColor(OS, HighlightColor::String) << "text";
+ WithColor(raw_ostream &OS, HighlightColor S);
+ ~WithColor();
+
+ raw_ostream &get() { return OS; }
+ operator raw_ostream &() { return OS; }
+
+ /// Convenience method for printing "error: " to stderr.
+ static raw_ostream &error();
+ /// Convenience method for printing "warning: " to stderr.
+ static raw_ostream &warning();
+ /// Convenience method for printing "note: " to stderr.
+ static raw_ostream &note();
+
+ /// Convenience method for printing "error: " to the given stream.
+ static raw_ostream &error(raw_ostream &OS, StringRef Prefix = "");
+ /// Convenience method for printing "warning: " to the given stream.
+ static raw_ostream &warning(raw_ostream &OS, StringRef Prefix = "");
+ /// Convenience method for printing "note: " to the given stream.
+ static raw_ostream &note(raw_ostream &OS, StringRef Prefix = "");
+};
+
+} // end namespace llvm
+
+#endif // LLVM_LIB_DEBUGINFO_WITHCOLOR_H
diff --git a/include/llvm/Support/X86DisassemblerDecoderCommon.h b/include/llvm/Support/X86DisassemblerDecoderCommon.h
new file mode 100644
index 000000000000..185b357efef5
--- /dev/null
+++ b/include/llvm/Support/X86DisassemblerDecoderCommon.h
@@ -0,0 +1,475 @@
+//===-- X86DisassemblerDecoderCommon.h - Disassembler decoder ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is part of the X86 Disassembler.
+// It contains common definitions used by both the disassembler and the table
+// generator.
+// Documentation for the disassembler can be found in X86Disassembler.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_X86_DISASSEMBLER_X86DISASSEMBLERDECODERCOMMON_H
+#define LLVM_LIB_TARGET_X86_DISASSEMBLER_X86DISASSEMBLERDECODERCOMMON_H
+
+#include "llvm/Support/DataTypes.h"
+
+namespace llvm {
+namespace X86Disassembler {
+
+#define INSTRUCTIONS_SYM x86DisassemblerInstrSpecifiers
+#define CONTEXTS_SYM x86DisassemblerContexts
+#define ONEBYTE_SYM x86DisassemblerOneByteOpcodes
+#define TWOBYTE_SYM x86DisassemblerTwoByteOpcodes
+#define THREEBYTE38_SYM x86DisassemblerThreeByte38Opcodes
+#define THREEBYTE3A_SYM x86DisassemblerThreeByte3AOpcodes
+#define XOP8_MAP_SYM x86DisassemblerXOP8Opcodes
+#define XOP9_MAP_SYM x86DisassemblerXOP9Opcodes
+#define XOPA_MAP_SYM x86DisassemblerXOPAOpcodes
+#define THREEDNOW_MAP_SYM x86Disassembler3DNowOpcodes
+
+#define INSTRUCTIONS_STR "x86DisassemblerInstrSpecifiers"
+#define CONTEXTS_STR "x86DisassemblerContexts"
+#define ONEBYTE_STR "x86DisassemblerOneByteOpcodes"
+#define TWOBYTE_STR "x86DisassemblerTwoByteOpcodes"
+#define THREEBYTE38_STR "x86DisassemblerThreeByte38Opcodes"
+#define THREEBYTE3A_STR "x86DisassemblerThreeByte3AOpcodes"
+#define XOP8_MAP_STR "x86DisassemblerXOP8Opcodes"
+#define XOP9_MAP_STR "x86DisassemblerXOP9Opcodes"
+#define XOPA_MAP_STR "x86DisassemblerXOPAOpcodes"
+#define THREEDNOW_MAP_STR "x86Disassembler3DNowOpcodes"
+
+// Attributes of an instruction that must be known before the opcode can be
+// processed correctly. Most of these indicate the presence of particular
+// prefixes, but ATTR_64BIT is simply an attribute of the decoding context.
+#define ATTRIBUTE_BITS \
+ ENUM_ENTRY(ATTR_NONE, 0x00) \
+ ENUM_ENTRY(ATTR_64BIT, (0x1 << 0)) \
+ ENUM_ENTRY(ATTR_XS, (0x1 << 1)) \
+ ENUM_ENTRY(ATTR_XD, (0x1 << 2)) \
+ ENUM_ENTRY(ATTR_REXW, (0x1 << 3)) \
+ ENUM_ENTRY(ATTR_OPSIZE, (0x1 << 4)) \
+ ENUM_ENTRY(ATTR_ADSIZE, (0x1 << 5)) \
+ ENUM_ENTRY(ATTR_VEX, (0x1 << 6)) \
+ ENUM_ENTRY(ATTR_VEXL, (0x1 << 7)) \
+ ENUM_ENTRY(ATTR_EVEX, (0x1 << 8)) \
+ ENUM_ENTRY(ATTR_EVEXL, (0x1 << 9)) \
+ ENUM_ENTRY(ATTR_EVEXL2, (0x1 << 10)) \
+ ENUM_ENTRY(ATTR_EVEXK, (0x1 << 11)) \
+ ENUM_ENTRY(ATTR_EVEXKZ, (0x1 << 12)) \
+ ENUM_ENTRY(ATTR_EVEXB, (0x1 << 13))
+
+#define ENUM_ENTRY(n, v) n = v,
+enum attributeBits {
+ ATTRIBUTE_BITS
+ ATTR_max
+};
+#undef ENUM_ENTRY
+
+// Combinations of the above attributes that are relevant to instruction
+// decode. Although other combinations are possible, they can be reduced to
+// these without affecting the ultimately decoded instruction.
+
+// Class name Rank Rationale for rank assignment
+#define INSTRUCTION_CONTEXTS \
+ ENUM_ENTRY(IC, 0, "says nothing about the instruction") \
+ ENUM_ENTRY(IC_64BIT, 1, "says the instruction applies in " \
+ "64-bit mode but no more") \
+ ENUM_ENTRY(IC_OPSIZE, 3, "requires an OPSIZE prefix, so " \
+ "operands change width") \
+ ENUM_ENTRY(IC_ADSIZE, 3, "requires an ADSIZE prefix, so " \
+ "operands change width") \
+ ENUM_ENTRY(IC_OPSIZE_ADSIZE, 4, "requires ADSIZE and OPSIZE prefixes") \
+ ENUM_ENTRY(IC_XD, 2, "may say something about the opcode " \
+ "but not the operands") \
+ ENUM_ENTRY(IC_XS, 2, "may say something about the opcode " \
+ "but not the operands") \
+ ENUM_ENTRY(IC_XD_OPSIZE, 3, "requires an OPSIZE prefix, so " \
+ "operands change width") \
+ ENUM_ENTRY(IC_XS_OPSIZE, 3, "requires an OPSIZE prefix, so " \
+ "operands change width") \
+ ENUM_ENTRY(IC_XD_ADSIZE, 3, "requires an ADSIZE prefix, so " \
+ "operands change width") \
+ ENUM_ENTRY(IC_XS_ADSIZE, 3, "requires an ADSIZE prefix, so " \
+ "operands change width") \
+ ENUM_ENTRY(IC_64BIT_REXW, 5, "requires a REX.W prefix, so operands "\
+ "change width; overrides IC_OPSIZE") \
+ ENUM_ENTRY(IC_64BIT_REXW_ADSIZE, 6, "requires a REX.W prefix and 0x67 " \
+ "prefix") \
+ ENUM_ENTRY(IC_64BIT_OPSIZE, 3, "Just as meaningful as IC_OPSIZE") \
+ ENUM_ENTRY(IC_64BIT_ADSIZE, 3, "Just as meaningful as IC_ADSIZE") \
+ ENUM_ENTRY(IC_64BIT_OPSIZE_ADSIZE, 4, "Just as meaningful as IC_OPSIZE/" \
+ "IC_ADSIZE") \
+ ENUM_ENTRY(IC_64BIT_XD, 6, "XD instructions are SSE; REX.W is " \
+ "secondary") \
+ ENUM_ENTRY(IC_64BIT_XS, 6, "Just as meaningful as IC_64BIT_XD") \
+ ENUM_ENTRY(IC_64BIT_XD_OPSIZE, 3, "Just as meaningful as IC_XD_OPSIZE") \
+ ENUM_ENTRY(IC_64BIT_XS_OPSIZE, 3, "Just as meaningful as IC_XS_OPSIZE") \
+ ENUM_ENTRY(IC_64BIT_XD_ADSIZE, 3, "Just as meaningful as IC_XD_ADSIZE") \
+ ENUM_ENTRY(IC_64BIT_XS_ADSIZE, 3, "Just as meaningful as IC_XS_ADSIZE") \
+ ENUM_ENTRY(IC_64BIT_REXW_XS, 7, "OPSIZE could mean a different " \
+ "opcode") \
+ ENUM_ENTRY(IC_64BIT_REXW_XD, 7, "Just as meaningful as " \
+ "IC_64BIT_REXW_XS") \
+ ENUM_ENTRY(IC_64BIT_REXW_OPSIZE, 8, "The Dynamic Duo! Prefer over all " \
+ "else because this changes most " \
+ "operands' meaning") \
+ ENUM_ENTRY(IC_VEX, 1, "requires a VEX prefix") \
+ ENUM_ENTRY(IC_VEX_XS, 2, "requires VEX and the XS prefix") \
+ ENUM_ENTRY(IC_VEX_XD, 2, "requires VEX and the XD prefix") \
+ ENUM_ENTRY(IC_VEX_OPSIZE, 2, "requires VEX and the OpSize prefix") \
+ ENUM_ENTRY(IC_VEX_W, 3, "requires VEX and the W prefix") \
+ ENUM_ENTRY(IC_VEX_W_XS, 4, "requires VEX, W, and XS prefix") \
+ ENUM_ENTRY(IC_VEX_W_XD, 4, "requires VEX, W, and XD prefix") \
+ ENUM_ENTRY(IC_VEX_W_OPSIZE, 4, "requires VEX, W, and OpSize") \
+ ENUM_ENTRY(IC_VEX_L, 3, "requires VEX and the L prefix") \
+ ENUM_ENTRY(IC_VEX_L_XS, 4, "requires VEX and the L and XS prefix")\
+ ENUM_ENTRY(IC_VEX_L_XD, 4, "requires VEX and the L and XD prefix")\
+ ENUM_ENTRY(IC_VEX_L_OPSIZE, 4, "requires VEX, L, and OpSize") \
+ ENUM_ENTRY(IC_VEX_L_W, 4, "requires VEX, L and W") \
+ ENUM_ENTRY(IC_VEX_L_W_XS, 5, "requires VEX, L, W and XS prefix") \
+ ENUM_ENTRY(IC_VEX_L_W_XD, 5, "requires VEX, L, W and XD prefix") \
+ ENUM_ENTRY(IC_VEX_L_W_OPSIZE, 5, "requires VEX, L, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX, 1, "requires an EVEX prefix") \
+ ENUM_ENTRY(IC_EVEX_XS, 2, "requires EVEX and the XS prefix") \
+ ENUM_ENTRY(IC_EVEX_XD, 2, "requires EVEX and the XD prefix") \
+ ENUM_ENTRY(IC_EVEX_OPSIZE, 2, "requires EVEX and the OpSize prefix") \
+ ENUM_ENTRY(IC_EVEX_W, 3, "requires EVEX and the W prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XS, 4, "requires EVEX, W, and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XD, 4, "requires EVEX, W, and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_W_OPSIZE, 4, "requires EVEX, W, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L, 3, "requires EVEX and the L prefix") \
+ ENUM_ENTRY(IC_EVEX_L_XS, 4, "requires EVEX and the L and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L_XD, 4, "requires EVEX and the L and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L_OPSIZE, 4, "requires EVEX, L, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_W, 3, "requires EVEX, L and W") \
+ ENUM_ENTRY(IC_EVEX_L_W_XS, 4, "requires EVEX, L, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_XD, 4, "requires EVEX, L, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_OPSIZE, 4, "requires EVEX, L, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2, 3, "requires EVEX and the L2 prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_XS, 4, "requires EVEX and the L2 and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_XD, 4, "requires EVEX and the L2 and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_OPSIZE, 4, "requires EVEX, L2, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_W, 3, "requires EVEX, L2 and W") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XS, 4, "requires EVEX, L2, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XD, 4, "requires EVEX, L2, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE, 4, "requires EVEX, L2, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_K, 1, "requires an EVEX_K prefix") \
+ ENUM_ENTRY(IC_EVEX_XS_K, 2, "requires EVEX_K and the XS prefix") \
+ ENUM_ENTRY(IC_EVEX_XD_K, 2, "requires EVEX_K and the XD prefix") \
+ ENUM_ENTRY(IC_EVEX_OPSIZE_K, 2, "requires EVEX_K and the OpSize prefix") \
+ ENUM_ENTRY(IC_EVEX_W_K, 3, "requires EVEX_K and the W prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XS_K, 4, "requires EVEX_K, W, and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XD_K, 4, "requires EVEX_K, W, and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_W_OPSIZE_K, 4, "requires EVEX_K, W, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_K, 3, "requires EVEX_K and the L prefix") \
+ ENUM_ENTRY(IC_EVEX_L_XS_K, 4, "requires EVEX_K and the L and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L_XD_K, 4, "requires EVEX_K and the L and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L_OPSIZE_K, 4, "requires EVEX_K, L, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_W_K, 3, "requires EVEX_K, L and W") \
+ ENUM_ENTRY(IC_EVEX_L_W_XS_K, 4, "requires EVEX_K, L, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_XD_K, 4, "requires EVEX_K, L, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_OPSIZE_K, 4, "requires EVEX_K, L, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_K, 3, "requires EVEX_K and the L2 prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_XS_K, 4, "requires EVEX_K and the L2 and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_XD_K, 4, "requires EVEX_K and the L2 and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_OPSIZE_K, 4, "requires EVEX_K, L2, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_W_K, 3, "requires EVEX_K, L2 and W") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XS_K, 4, "requires EVEX_K, L2, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XD_K, 4, "requires EVEX_K, L2, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_K, 4, "requires EVEX_K, L2, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_B, 1, "requires an EVEX_B prefix") \
+ ENUM_ENTRY(IC_EVEX_XS_B, 2, "requires EVEX_B and the XS prefix") \
+ ENUM_ENTRY(IC_EVEX_XD_B, 2, "requires EVEX_B and the XD prefix") \
+ ENUM_ENTRY(IC_EVEX_OPSIZE_B, 2, "requires EVEX_B and the OpSize prefix") \
+ ENUM_ENTRY(IC_EVEX_W_B, 3, "requires EVEX_B and the W prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XS_B, 4, "requires EVEX_B, W, and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XD_B, 4, "requires EVEX_B, W, and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_W_OPSIZE_B, 4, "requires EVEX_B, W, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_B, 3, "requires EVEX_B and the L prefix") \
+ ENUM_ENTRY(IC_EVEX_L_XS_B, 4, "requires EVEX_B and the L and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L_XD_B, 4, "requires EVEX_B and the L and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L_OPSIZE_B, 4, "requires EVEX_B, L, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_W_B, 3, "requires EVEX_B, L and W") \
+ ENUM_ENTRY(IC_EVEX_L_W_XS_B, 4, "requires EVEX_B, L, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_XD_B, 4, "requires EVEX_B, L, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_OPSIZE_B, 4, "requires EVEX_B, L, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_B, 3, "requires EVEX_B and the L2 prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_XS_B, 4, "requires EVEX_B and the L2 and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_XD_B, 4, "requires EVEX_B and the L2 and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_OPSIZE_B, 4, "requires EVEX_B, L2, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_W_B, 3, "requires EVEX_B, L2 and W") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XS_B, 4, "requires EVEX_B, L2, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XD_B, 4, "requires EVEX_B, L2, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_B, 4, "requires EVEX_B, L2, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_K_B, 1, "requires EVEX_B and EVEX_K prefix") \
+ ENUM_ENTRY(IC_EVEX_XS_K_B, 2, "requires EVEX_B, EVEX_K and the XS prefix") \
+ ENUM_ENTRY(IC_EVEX_XD_K_B, 2, "requires EVEX_B, EVEX_K and the XD prefix") \
+ ENUM_ENTRY(IC_EVEX_OPSIZE_K_B, 2, "requires EVEX_B, EVEX_K and the OpSize prefix") \
+ ENUM_ENTRY(IC_EVEX_W_K_B, 3, "requires EVEX_B, EVEX_K and the W prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XS_K_B, 4, "requires EVEX_B, EVEX_K, W, and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XD_K_B, 4, "requires EVEX_B, EVEX_K, W, and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_W_OPSIZE_K_B, 4, "requires EVEX_B, EVEX_K, W, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_K_B, 3, "requires EVEX_B, EVEX_K and the L prefix") \
+ ENUM_ENTRY(IC_EVEX_L_XS_K_B, 4, "requires EVEX_B, EVEX_K and the L and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L_XD_K_B, 4, "requires EVEX_B, EVEX_K and the L and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L_OPSIZE_K_B, 4, "requires EVEX_B, EVEX_K, L, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_W_K_B, 3, "requires EVEX_B, EVEX_K, L and W") \
+ ENUM_ENTRY(IC_EVEX_L_W_XS_K_B, 4, "requires EVEX_B, EVEX_K, L, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_XD_K_B, 4, "requires EVEX_B, EVEX_K, L, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_OPSIZE_K_B,4, "requires EVEX_B, EVEX_K, L, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_K_B, 3, "requires EVEX_B, EVEX_K and the L2 prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_XS_K_B, 4, "requires EVEX_B, EVEX_K and the L2 and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_XD_K_B, 4, "requires EVEX_B, EVEX_K and the L2 and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_OPSIZE_K_B, 4, "requires EVEX_B, EVEX_K, L2, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_W_K_B, 3, "requires EVEX_B, EVEX_K, L2 and W") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XS_K_B, 4, "requires EVEX_B, EVEX_K, L2, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XD_K_B, 4, "requires EVEX_B, EVEX_K, L2, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_K_B,4, "requires EVEX_B, EVEX_K, L2, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_KZ_B, 1, "requires EVEX_B and EVEX_KZ prefix") \
+ ENUM_ENTRY(IC_EVEX_XS_KZ_B, 2, "requires EVEX_B, EVEX_KZ and the XS prefix") \
+ ENUM_ENTRY(IC_EVEX_XD_KZ_B, 2, "requires EVEX_B, EVEX_KZ and the XD prefix") \
+ ENUM_ENTRY(IC_EVEX_OPSIZE_KZ_B, 2, "requires EVEX_B, EVEX_KZ and the OpSize prefix") \
+ ENUM_ENTRY(IC_EVEX_W_KZ_B, 3, "requires EVEX_B, EVEX_KZ and the W prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XS_KZ_B, 4, "requires EVEX_B, EVEX_KZ, W, and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XD_KZ_B, 4, "requires EVEX_B, EVEX_KZ, W, and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_W_OPSIZE_KZ_B, 4, "requires EVEX_B, EVEX_KZ, W, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_KZ_B, 3, "requires EVEX_B, EVEX_KZ and the L prefix") \
+ ENUM_ENTRY(IC_EVEX_L_XS_KZ_B, 4, "requires EVEX_B, EVEX_KZ and the L and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L_XD_KZ_B, 4, "requires EVEX_B, EVEX_KZ and the L and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L_OPSIZE_KZ_B, 4, "requires EVEX_B, EVEX_KZ, L, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_W_KZ_B, 3, "requires EVEX_B, EVEX_KZ, L and W") \
+ ENUM_ENTRY(IC_EVEX_L_W_XS_KZ_B, 4, "requires EVEX_B, EVEX_KZ, L, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_XD_KZ_B, 4, "requires EVEX_B, EVEX_KZ, L, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_OPSIZE_KZ_B, 4, "requires EVEX_B, EVEX_KZ, L, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_KZ_B, 3, "requires EVEX_B, EVEX_KZ and the L2 prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_XS_KZ_B, 4, "requires EVEX_B, EVEX_KZ and the L2 and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_XD_KZ_B, 4, "requires EVEX_B, EVEX_KZ and the L2 and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_OPSIZE_KZ_B, 4, "requires EVEX_B, EVEX_KZ, L2, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_W_KZ_B, 3, "requires EVEX_B, EVEX_KZ, L2 and W") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XS_KZ_B, 4, "requires EVEX_B, EVEX_KZ, L2, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XD_KZ_B, 4, "requires EVEX_B, EVEX_KZ, L2, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_KZ_B, 4, "requires EVEX_B, EVEX_KZ, L2, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_KZ, 1, "requires an EVEX_KZ prefix") \
+ ENUM_ENTRY(IC_EVEX_XS_KZ, 2, "requires EVEX_KZ and the XS prefix") \
+ ENUM_ENTRY(IC_EVEX_XD_KZ, 2, "requires EVEX_KZ and the XD prefix") \
+ ENUM_ENTRY(IC_EVEX_OPSIZE_KZ, 2, "requires EVEX_KZ and the OpSize prefix") \
+ ENUM_ENTRY(IC_EVEX_W_KZ, 3, "requires EVEX_KZ and the W prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XS_KZ, 4, "requires EVEX_KZ, W, and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XD_KZ, 4, "requires EVEX_KZ, W, and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_W_OPSIZE_KZ, 4, "requires EVEX_KZ, W, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_KZ, 3, "requires EVEX_KZ and the L prefix") \
+ ENUM_ENTRY(IC_EVEX_L_XS_KZ, 4, "requires EVEX_KZ and the L and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L_XD_KZ, 4, "requires EVEX_KZ and the L and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L_OPSIZE_KZ, 4, "requires EVEX_KZ, L, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_W_KZ, 3, "requires EVEX_KZ, L and W") \
+ ENUM_ENTRY(IC_EVEX_L_W_XS_KZ, 4, "requires EVEX_KZ, L, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_XD_KZ, 4, "requires EVEX_KZ, L, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_OPSIZE_KZ, 4, "requires EVEX_KZ, L, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_KZ, 3, "requires EVEX_KZ and the L2 prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_XS_KZ, 4, "requires EVEX_KZ and the L2 and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_XD_KZ, 4, "requires EVEX_KZ and the L2 and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_OPSIZE_KZ, 4, "requires EVEX_KZ, L2, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_W_KZ, 3, "requires EVEX_KZ, L2 and W") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XS_KZ, 4, "requires EVEX_KZ, L2, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XD_KZ, 4, "requires EVEX_KZ, L2, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_KZ, 4, "requires EVEX_KZ, L2, W and OpSize")
+
+#define ENUM_ENTRY(n, r, d) n,
+enum InstructionContext {
+ INSTRUCTION_CONTEXTS
+ IC_max
+};
+#undef ENUM_ENTRY
+
+// Opcode types, which determine which decode table to use, both in the Intel
+// manual and also for the decoder.
+enum OpcodeType {
+ ONEBYTE = 0,
+ TWOBYTE = 1,
+ THREEBYTE_38 = 2,
+ THREEBYTE_3A = 3,
+ XOP8_MAP = 4,
+ XOP9_MAP = 5,
+ XOPA_MAP = 6,
+ THREEDNOW_MAP = 7
+};
+
+// The following structs are used for the hierarchical decode table. After
+// determining the instruction's class (i.e., which IC_* constant applies to
+// it), the decoder reads the opcode. Some instructions require specific
+// values of the ModR/M byte, so the ModR/M byte indexes into the final table.
+//
+// If a ModR/M byte is not required, "required" is left unset, and the values
+// for each instructionID are identical.
+typedef uint16_t InstrUID;
+
+// ModRMDecisionType - describes the type of ModR/M decision, allowing the
+// consumer to determine the number of entries in it.
+//
+// MODRM_ONEENTRY - No matter what the value of the ModR/M byte is, the decoded
+// instruction is the same.
+// MODRM_SPLITRM - If the ModR/M byte is between 0x00 and 0xbf, the opcode
+// corresponds to one instruction; otherwise, it corresponds to
+// a different instruction.
+// MODRM_SPLITMISC- If the ModR/M byte is between 0x00 and 0xbf, ModR/M byte
+// divided by 8 is used to select instruction; otherwise, each
+// value of the ModR/M byte could correspond to a different
+// instruction.
+// MODRM_SPLITREG - ModR/M byte divided by 8 is used to select instruction. This
+// corresponds to instructions that use reg field as opcode
+// MODRM_FULL - Potentially, each value of the ModR/M byte could correspond
+// to a different instruction.
+#define MODRMTYPES \
+ ENUM_ENTRY(MODRM_ONEENTRY) \
+ ENUM_ENTRY(MODRM_SPLITRM) \
+ ENUM_ENTRY(MODRM_SPLITMISC) \
+ ENUM_ENTRY(MODRM_SPLITREG) \
+ ENUM_ENTRY(MODRM_FULL)
+
+#define ENUM_ENTRY(n) n,
+enum ModRMDecisionType {
+ MODRMTYPES
+ MODRM_max
+};
+#undef ENUM_ENTRY
+
+#define CASE_ENCODING_RM \
+ case ENCODING_RM: \
+ case ENCODING_RM_CD2: \
+ case ENCODING_RM_CD4: \
+ case ENCODING_RM_CD8: \
+ case ENCODING_RM_CD16: \
+ case ENCODING_RM_CD32: \
+ case ENCODING_RM_CD64
+
+#define CASE_ENCODING_VSIB \
+ case ENCODING_VSIB: \
+ case ENCODING_VSIB_CD2: \
+ case ENCODING_VSIB_CD4: \
+ case ENCODING_VSIB_CD8: \
+ case ENCODING_VSIB_CD16: \
+ case ENCODING_VSIB_CD32: \
+ case ENCODING_VSIB_CD64
+
+// Physical encodings of instruction operands.
+#define ENCODINGS \
+ ENUM_ENTRY(ENCODING_NONE, "") \
+ ENUM_ENTRY(ENCODING_REG, "Register operand in ModR/M byte.") \
+ ENUM_ENTRY(ENCODING_RM, "R/M operand in ModR/M byte.") \
+ ENUM_ENTRY(ENCODING_RM_CD2, "R/M operand with CDisp scaling of 2") \
+ ENUM_ENTRY(ENCODING_RM_CD4, "R/M operand with CDisp scaling of 4") \
+ ENUM_ENTRY(ENCODING_RM_CD8, "R/M operand with CDisp scaling of 8") \
+ ENUM_ENTRY(ENCODING_RM_CD16,"R/M operand with CDisp scaling of 16") \
+ ENUM_ENTRY(ENCODING_RM_CD32,"R/M operand with CDisp scaling of 32") \
+ ENUM_ENTRY(ENCODING_RM_CD64,"R/M operand with CDisp scaling of 64") \
+ ENUM_ENTRY(ENCODING_VSIB, "VSIB operand in ModR/M byte.") \
+ ENUM_ENTRY(ENCODING_VSIB_CD2, "VSIB operand with CDisp scaling of 2") \
+ ENUM_ENTRY(ENCODING_VSIB_CD4, "VSIB operand with CDisp scaling of 4") \
+ ENUM_ENTRY(ENCODING_VSIB_CD8, "VSIB operand with CDisp scaling of 8") \
+ ENUM_ENTRY(ENCODING_VSIB_CD16,"VSIB operand with CDisp scaling of 16") \
+ ENUM_ENTRY(ENCODING_VSIB_CD32,"VSIB operand with CDisp scaling of 32") \
+ ENUM_ENTRY(ENCODING_VSIB_CD64,"VSIB operand with CDisp scaling of 64") \
+ ENUM_ENTRY(ENCODING_VVVV, "Register operand in VEX.vvvv byte.") \
+ ENUM_ENTRY(ENCODING_WRITEMASK, "Register operand in EVEX.aaa byte.") \
+ ENUM_ENTRY(ENCODING_IB, "1-byte immediate") \
+ ENUM_ENTRY(ENCODING_IW, "2-byte") \
+ ENUM_ENTRY(ENCODING_ID, "4-byte") \
+ ENUM_ENTRY(ENCODING_IO, "8-byte") \
+ ENUM_ENTRY(ENCODING_RB, "(AL..DIL, R8L..R15L) Register code added to " \
+ "the opcode byte") \
+ ENUM_ENTRY(ENCODING_RW, "(AX..DI, R8W..R15W)") \
+ ENUM_ENTRY(ENCODING_RD, "(EAX..EDI, R8D..R15D)") \
+ ENUM_ENTRY(ENCODING_RO, "(RAX..RDI, R8..R15)") \
+ ENUM_ENTRY(ENCODING_FP, "Position on floating-point stack in ModR/M " \
+ "byte.") \
+ \
+ ENUM_ENTRY(ENCODING_Iv, "Immediate of operand size") \
+ ENUM_ENTRY(ENCODING_Ia, "Immediate of address size") \
+ ENUM_ENTRY(ENCODING_IRC, "Immediate for static rounding control") \
+ ENUM_ENTRY(ENCODING_Rv, "Register code of operand size added to the " \
+ "opcode byte") \
+ ENUM_ENTRY(ENCODING_DUP, "Duplicate of another operand; ID is encoded " \
+ "in type") \
+ ENUM_ENTRY(ENCODING_SI, "Source index; encoded in OpSize/Adsize prefix") \
+ ENUM_ENTRY(ENCODING_DI, "Destination index; encoded in prefixes")
+
+#define ENUM_ENTRY(n, d) n,
+enum OperandEncoding {
+ ENCODINGS
+ ENCODING_max
+};
+#undef ENUM_ENTRY
+
+// Semantic interpretations of instruction operands.
+#define TYPES \
+ ENUM_ENTRY(TYPE_NONE, "") \
+ ENUM_ENTRY(TYPE_REL, "immediate address") \
+ ENUM_ENTRY(TYPE_R8, "1-byte register operand") \
+ ENUM_ENTRY(TYPE_R16, "2-byte") \
+ ENUM_ENTRY(TYPE_R32, "4-byte") \
+ ENUM_ENTRY(TYPE_R64, "8-byte") \
+ ENUM_ENTRY(TYPE_IMM, "immediate operand") \
+ ENUM_ENTRY(TYPE_IMM3, "1-byte immediate operand between 0 and 7") \
+ ENUM_ENTRY(TYPE_IMM5, "1-byte immediate operand between 0 and 31") \
+ ENUM_ENTRY(TYPE_AVX512ICC, "1-byte immediate operand for AVX512 icmp") \
+ ENUM_ENTRY(TYPE_UIMM8, "1-byte unsigned immediate operand") \
+ ENUM_ENTRY(TYPE_M, "Memory operand") \
+ ENUM_ENTRY(TYPE_MVSIBX, "Memory operand using XMM index") \
+ ENUM_ENTRY(TYPE_MVSIBY, "Memory operand using YMM index") \
+ ENUM_ENTRY(TYPE_MVSIBZ, "Memory operand using ZMM index") \
+ ENUM_ENTRY(TYPE_SRCIDX, "memory at source index") \
+ ENUM_ENTRY(TYPE_DSTIDX, "memory at destination index") \
+ ENUM_ENTRY(TYPE_MOFFS, "memory offset (relative to segment base)") \
+ ENUM_ENTRY(TYPE_ST, "Position on the floating-point stack") \
+ ENUM_ENTRY(TYPE_MM64, "8-byte MMX register") \
+ ENUM_ENTRY(TYPE_XMM, "16-byte") \
+ ENUM_ENTRY(TYPE_YMM, "32-byte") \
+ ENUM_ENTRY(TYPE_ZMM, "64-byte") \
+ ENUM_ENTRY(TYPE_VK, "mask register") \
+ ENUM_ENTRY(TYPE_SEGMENTREG, "Segment register operand") \
+ ENUM_ENTRY(TYPE_DEBUGREG, "Debug register operand") \
+ ENUM_ENTRY(TYPE_CONTROLREG, "Control register operand") \
+ ENUM_ENTRY(TYPE_BNDR, "MPX bounds register") \
+ \
+ ENUM_ENTRY(TYPE_Rv, "Register operand of operand size") \
+ ENUM_ENTRY(TYPE_RELv, "Immediate address of operand size") \
+ ENUM_ENTRY(TYPE_DUP0, "Duplicate of operand 0") \
+ ENUM_ENTRY(TYPE_DUP1, "operand 1") \
+ ENUM_ENTRY(TYPE_DUP2, "operand 2") \
+ ENUM_ENTRY(TYPE_DUP3, "operand 3") \
+ ENUM_ENTRY(TYPE_DUP4, "operand 4") \
+
+#define ENUM_ENTRY(n, d) n,
+enum OperandType {
+ TYPES
+ TYPE_max
+};
+#undef ENUM_ENTRY
+
+/// The specification for how to extract and interpret one operand.
+struct OperandSpecifier {
+ uint8_t encoding;
+ uint8_t type;
+};
+
+static const unsigned X86_MAX_OPERANDS = 6;
+
+/// Decoding mode for the Intel disassembler. 16-bit, 32-bit, and 64-bit mode
+/// are supported, and represent real mode, IA-32e, and IA-32e in 64-bit mode,
+/// respectively.
+enum DisassemblerMode {
+ MODE_16BIT,
+ MODE_32BIT,
+ MODE_64BIT
+};
+
+} // namespace X86Disassembler
+} // namespace llvm
+
+#endif
diff --git a/include/llvm/Support/X86TargetParser.def b/include/llvm/Support/X86TargetParser.def
index 5c8c576b1027..e4af0657a350 100644
--- a/include/llvm/Support/X86TargetParser.def
+++ b/include/llvm/Support/X86TargetParser.def
@@ -65,6 +65,8 @@ X86_CPU_TYPE ("athlon-xp", AMD_ATHLON_XP)
X86_CPU_TYPE ("k8", AMD_K8)
X86_CPU_TYPE ("k8-sse3", AMD_K8SSE3)
X86_CPU_TYPE ("goldmont", INTEL_GOLDMONT)
+X86_CPU_TYPE ("goldmont-plus", INTEL_GOLDMONT_PLUS)
+X86_CPU_TYPE ("tremont", INTEL_TREMONT)
#undef X86_CPU_TYPE_COMPAT_WITH_ALIAS
#undef X86_CPU_TYPE_COMPAT
#undef X86_CPU_TYPE
diff --git a/include/llvm/Support/YAMLParser.h b/include/llvm/Support/YAMLParser.h
index c907a99ddb59..5b031a9a4270 100644
--- a/include/llvm/Support/YAMLParser.h
+++ b/include/llvm/Support/YAMLParser.h
@@ -64,23 +64,26 @@ class Node;
class Scanner;
struct Token;
-/// \brief Dump all the tokens in this stream to OS.
+/// Dump all the tokens in this stream to OS.
/// \returns true if there was an error, false otherwise.
bool dumpTokens(StringRef Input, raw_ostream &);
-/// \brief Scans all tokens in input without outputting anything. This is used
+/// Scans all tokens in input without outputting anything. This is used
/// for benchmarking the tokenizer.
/// \returns true if there was an error, false otherwise.
bool scanTokens(StringRef Input);
-/// \brief Escape \a Input for a double quoted scalar.
-std::string escape(StringRef Input);
+/// Escape \a Input for a double quoted scalar; if \p EscapePrintable
+/// is true, all UTF8 sequences will be escaped, if \p EscapePrintable is
+/// false, those UTF8 sequences encoding printable unicode scalars will not be
+/// escaped, but emitted verbatim.
+std::string escape(StringRef Input, bool EscapePrintable = true);
-/// \brief This class represents a YAML stream potentially containing multiple
+/// This class represents a YAML stream potentially containing multiple
/// documents.
class Stream {
public:
- /// \brief This keeps a reference to the string referenced by \p Input.
+ /// This keeps a reference to the string referenced by \p Input.
Stream(StringRef Input, SourceMgr &, bool ShowColors = true,
std::error_code *EC = nullptr);
@@ -107,7 +110,7 @@ private:
std::unique_ptr<Document> CurrentDoc;
};
-/// \brief Abstract base class for all Nodes.
+/// Abstract base class for all Nodes.
class Node {
virtual void anchor();
@@ -125,6 +128,11 @@ public:
Node(unsigned int Type, std::unique_ptr<Document> &, StringRef Anchor,
StringRef Tag);
+ // It's not safe to copy YAML nodes; the document is streamed and the position
+ // is part of the state.
+ Node(const Node &) = delete;
+ void operator=(const Node &) = delete;
+
void *operator new(size_t Size, BumpPtrAllocator &Alloc,
size_t Alignment = 16) noexcept {
return Alloc.Allocate(Size, Alignment);
@@ -137,15 +145,15 @@ public:
void operator delete(void *) noexcept = delete;
- /// \brief Get the value of the anchor attached to this node. If it does not
+ /// Get the value of the anchor attached to this node. If it does not
/// have one, getAnchor().size() will be 0.
StringRef getAnchor() const { return Anchor; }
- /// \brief Get the tag as it was written in the document. This does not
+ /// Get the tag as it was written in the document. This does not
/// perform tag resolution.
StringRef getRawTag() const { return Tag; }
- /// \brief Get the verbatium tag for a given Node. This performs tag resoluton
+ /// Get the verbatium tag for a given Node. This performs tag resoluton
/// and substitution.
std::string getVerbatimTag() const;
@@ -173,11 +181,11 @@ protected:
private:
unsigned int TypeID;
StringRef Anchor;
- /// \brief The tag as typed in the document.
+ /// The tag as typed in the document.
StringRef Tag;
};
-/// \brief A null value.
+/// A null value.
///
/// Example:
/// !!null null
@@ -191,7 +199,7 @@ public:
static bool classof(const Node *N) { return N->getType() == NK_Null; }
};
-/// \brief A scalar node is an opaque datum that can be presented as a
+/// A scalar node is an opaque datum that can be presented as a
/// series of zero or more Unicode scalar values.
///
/// Example:
@@ -213,7 +221,7 @@ public:
// utf8).
StringRef getRawValue() const { return Value; }
- /// \brief Gets the value of this node as a StringRef.
+ /// Gets the value of this node as a StringRef.
///
/// \param Storage is used to store the content of the returned StringRef iff
/// it requires any modification from how it appeared in the source.
@@ -232,7 +240,7 @@ private:
SmallVectorImpl<char> &Storage) const;
};
-/// \brief A block scalar node is an opaque datum that can be presented as a
+/// A block scalar node is an opaque datum that can be presented as a
/// series of zero or more Unicode scalar values.
///
/// Example:
@@ -251,7 +259,7 @@ public:
SourceRange = SMRange(Start, End);
}
- /// \brief Gets the value of this node as a StringRef.
+ /// Gets the value of this node as a StringRef.
StringRef getValue() const { return Value; }
static bool classof(const Node *N) {
@@ -262,7 +270,7 @@ private:
StringRef Value;
};
-/// \brief A key and value pair. While not technically a Node under the YAML
+/// A key and value pair. While not technically a Node under the YAML
/// representation graph, it is easier to treat them this way.
///
/// TODO: Consider making this not a child of Node.
@@ -276,14 +284,14 @@ public:
KeyValueNode(std::unique_ptr<Document> &D)
: Node(NK_KeyValue, D, StringRef(), StringRef()) {}
- /// \brief Parse and return the key.
+ /// Parse and return the key.
///
/// This may be called multiple times.
///
/// \returns The key, or nullptr if failed() == true.
Node *getKey();
- /// \brief Parse and return the value.
+ /// Parse and return the value.
///
/// This may be called multiple times.
///
@@ -307,7 +315,7 @@ private:
Node *Value = nullptr;
};
-/// \brief This is an iterator abstraction over YAML collections shared by both
+/// This is an iterator abstraction over YAML collections shared by both
/// sequences and maps.
///
/// BaseT must have a ValueT* member named CurrentEntry and a member function
@@ -387,7 +395,7 @@ template <class CollectionType> void skip(CollectionType &C) {
i->skip();
}
-/// \brief Represents a YAML map created from either a block map for a flow map.
+/// Represents a YAML map created from either a block map for a flow map.
///
/// This parses the YAML stream as increment() is called.
///
@@ -434,7 +442,7 @@ private:
void increment();
};
-/// \brief Represents a YAML sequence created from either a block sequence for a
+/// Represents a YAML sequence created from either a block sequence for a
/// flow sequence.
///
/// This parses the YAML stream as increment() is called.
@@ -490,7 +498,7 @@ private:
Node *CurrentEntry = nullptr;
};
-/// \brief Represents an alias to a Node with an anchor.
+/// Represents an alias to a Node with an anchor.
///
/// Example:
/// *AnchorName
@@ -510,20 +518,20 @@ private:
StringRef Name;
};
-/// \brief A YAML Stream is a sequence of Documents. A document contains a root
+/// A YAML Stream is a sequence of Documents. A document contains a root
/// node.
class Document {
public:
Document(Stream &ParentStream);
- /// \brief Root for parsing a node. Returns a single node.
+ /// Root for parsing a node. Returns a single node.
Node *parseBlockNode();
- /// \brief Finish parsing the current document and return true if there are
+ /// Finish parsing the current document and return true if there are
/// more. Return false otherwise.
bool skip();
- /// \brief Parse and return the root level node.
+ /// Parse and return the root level node.
Node *getRoot() {
if (Root)
return Root;
@@ -536,18 +544,18 @@ private:
friend class Node;
friend class document_iterator;
- /// \brief Stream to read tokens from.
+ /// Stream to read tokens from.
Stream &stream;
- /// \brief Used to allocate nodes to. All are destroyed without calling their
+ /// Used to allocate nodes to. All are destroyed without calling their
/// destructor when the document is destroyed.
BumpPtrAllocator NodeAllocator;
- /// \brief The root node. Used to support skipping a partially parsed
+ /// The root node. Used to support skipping a partially parsed
/// document.
Node *Root;
- /// \brief Maps tag prefixes to their expansion.
+ /// Maps tag prefixes to their expansion.
std::map<StringRef, StringRef> TagMap;
Token &peekNext();
@@ -555,20 +563,20 @@ private:
void setError(const Twine &Message, Token &Location) const;
bool failed() const;
- /// \brief Parse %BLAH directives and return true if any were encountered.
+ /// Parse %BLAH directives and return true if any were encountered.
bool parseDirectives();
- /// \brief Parse %YAML
+ /// Parse %YAML
void parseYAMLDirective();
- /// \brief Parse %TAG
+ /// Parse %TAG
void parseTAGDirective();
- /// \brief Consume the next token and error if it is not \a TK.
+ /// Consume the next token and error if it is not \a TK.
bool expectToken(int TK);
};
-/// \brief Iterator abstraction for Documents over a Stream.
+/// Iterator abstraction for Documents over a Stream.
class document_iterator {
public:
document_iterator() = default;
diff --git a/include/llvm/Support/YAMLTraits.h b/include/llvm/Support/YAMLTraits.h
index 674c78a11695..4b8c4e958288 100644
--- a/include/llvm/Support/YAMLTraits.h
+++ b/include/llvm/Support/YAMLTraits.h
@@ -511,8 +511,6 @@ inline QuotingType needsQuotes(StringRef S) {
return QuotingType::Single;
if (isspace(S.front()) || isspace(S.back()))
return QuotingType::Single;
- if (S.front() == ',')
- return QuotingType::Single;
if (isNull(S))
return QuotingType::Single;
if (isBool(S))
@@ -520,6 +518,13 @@ inline QuotingType needsQuotes(StringRef S) {
if (isNumeric(S))
return QuotingType::Single;
+ // 7.3.3 Plain Style
+ // Plain scalars must not begin with most indicators, as this would cause
+ // ambiguity with other YAML constructs.
+ static constexpr char Indicators[] = R"(-?:\,[]{}#&*!|>'"%@`)";
+ if (S.find_first_of(Indicators) == 0)
+ return QuotingType::Single;
+
QuotingType MaxQuotingNeeded = QuotingType::None;
for (unsigned char C : S) {
// Alphanum is safe.
@@ -535,11 +540,14 @@ inline QuotingType needsQuotes(StringRef S) {
case '.':
case ',':
case ' ':
- // TAB (0x9), LF (0xA), CR (0xD) and NEL (0x85) are allowed.
+ // TAB (0x9) is allowed in unquoted strings.
case 0x9:
+ continue;
+ // LF(0xA) and CR(0xD) may delimit values and so require at least single
+ // quotes.
case 0xA:
case 0xD:
- case 0x85:
+ MaxQuotingNeeded = QuotingType::Single;
continue;
// DEL (0x7F) are excluded from the allowed character range.
case 0x7F:
@@ -1306,7 +1314,7 @@ public:
Output(raw_ostream &, void *Ctxt = nullptr, int WrapColumn = 70);
~Output() override;
- /// \brief Set whether or not to output optional values which are equal
+ /// Set whether or not to output optional values which are equal
/// to the default value. By default, when outputting if you attempt
/// to write a value that is equal to the default, the value gets ignored.
/// Sometimes, it is useful to be able to see these in the resulting YAML
diff --git a/include/llvm/Support/raw_ostream.h b/include/llvm/Support/raw_ostream.h
index d11f5a837796..b9ea9b5817f2 100644
--- a/include/llvm/Support/raw_ostream.h
+++ b/include/llvm/Support/raw_ostream.h
@@ -33,7 +33,9 @@ class FormattedBytes;
namespace sys {
namespace fs {
+enum FileAccess : unsigned;
enum OpenFlags : unsigned;
+enum CreationDisposition : unsigned;
} // end namespace fs
} // end namespace sys
@@ -218,7 +220,7 @@ public:
raw_ostream &write_uuid(const uuid_t UUID);
/// Output \p Str, turning '\\', '\t', '\n', '"', and anything that doesn't
- /// satisfy std::isprint into an escape sequence.
+ /// satisfy llvm::isPrint into an escape sequence.
raw_ostream &write_escaped(StringRef Str, bool UseHexEscapes = false);
raw_ostream &write(unsigned char C);
@@ -242,6 +244,9 @@ public:
/// indent - Insert 'NumSpaces' spaces.
raw_ostream &indent(unsigned NumSpaces);
+ /// write_zeros - Insert 'NumZeros' nulls.
+ raw_ostream &write_zeros(unsigned NumZeros);
+
/// Changes the foreground color of text that will be output from this point
/// forward.
/// @param Color ANSI color to use, the special SAVEDCOLOR can be used to
@@ -293,9 +298,6 @@ private:
/// \invariant { Size > 0 }
virtual void write_impl(const char *Ptr, size_t Size) = 0;
- // An out of line virtual method to provide a home for the class vtable.
- virtual void handle();
-
/// Return the current position within the stream, not counting the bytes
/// currently in the buffer.
virtual uint64_t current_pos() const = 0;
@@ -329,6 +331,8 @@ private:
/// Copy data into the buffer. Size must not be greater than the number of
/// unused bytes in the buffer.
void copy_to_buffer(const char *Ptr, size_t Size);
+
+ virtual void anchor();
};
/// An abstract base class for streams implementations that also support a
@@ -336,6 +340,7 @@ private:
/// but needs to patch in a header that needs to know the output size.
class raw_pwrite_stream : public raw_ostream {
virtual void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) = 0;
+ void anchor() override;
public:
explicit raw_pwrite_stream(bool Unbuffered = false)
@@ -383,6 +388,8 @@ class raw_fd_ostream : public raw_pwrite_stream {
/// Set the flag indicating that an output error has been encountered.
void error_detected(std::error_code EC) { this->EC = EC; }
+ void anchor() override;
+
public:
/// Open the specified file for writing. If an error occurs, information
/// about the error is put into EC, and the stream should be immediately
@@ -392,7 +399,15 @@ public:
/// As a special case, if Filename is "-", then the stream will use
/// STDOUT_FILENO instead of opening a file. This will not close the stdout
/// descriptor.
+ raw_fd_ostream(StringRef Filename, std::error_code &EC);
+ raw_fd_ostream(StringRef Filename, std::error_code &EC,
+ sys::fs::CreationDisposition Disp);
+ raw_fd_ostream(StringRef Filename, std::error_code &EC,
+ sys::fs::FileAccess Access);
+ raw_fd_ostream(StringRef Filename, std::error_code &EC,
+ sys::fs::OpenFlags Flags);
raw_fd_ostream(StringRef Filename, std::error_code &EC,
+ sys::fs::CreationDisposition Disp, sys::fs::FileAccess Access,
sys::fs::OpenFlags Flags);
/// FD is the file descriptor that this writes to. If ShouldClose is true,
diff --git a/include/llvm/Support/type_traits.h b/include/llvm/Support/type_traits.h
index cc0878358800..55d84f138f07 100644
--- a/include/llvm/Support/type_traits.h
+++ b/include/llvm/Support/type_traits.h
@@ -54,7 +54,7 @@ struct isPodLike<std::pair<T, U>> {
static const bool value = isPodLike<T>::value && isPodLike<U>::value;
};
-/// \brief Metafunction that determines whether the given type is either an
+/// Metafunction that determines whether the given type is either an
/// integral type or an enumeration type, including enum classes.
///
/// Note that this accepts potentially more integral types than is_integral
@@ -73,7 +73,7 @@ public:
std::is_convertible<UnderlyingT, unsigned long long>::value);
};
-/// \brief If T is a pointer, just return it. If it is not, return T&.
+/// If T is a pointer, just return it. If it is not, return T&.
template<typename T, typename Enable = void>
struct add_lvalue_reference_if_not_pointer { using type = T &; };
@@ -83,7 +83,7 @@ struct add_lvalue_reference_if_not_pointer<
using type = T;
};
-/// \brief If T is a pointer to X, return a pointer to const X. If it is not,
+/// If T is a pointer to X, return a pointer to const X. If it is not,
/// return const T.
template<typename T, typename Enable = void>
struct add_const_past_pointer { using type = const T; };
@@ -104,12 +104,51 @@ struct const_pointer_or_const_ref<
using type = typename add_const_past_pointer<T>::type;
};
+namespace detail {
+/// Internal utility to detect trivial copy construction.
+template<typename T> union copy_construction_triviality_helper {
+ T t;
+ copy_construction_triviality_helper() = default;
+ copy_construction_triviality_helper(const copy_construction_triviality_helper&) = default;
+ ~copy_construction_triviality_helper() = default;
+};
+/// Internal utility to detect trivial move construction.
+template<typename T> union move_construction_triviality_helper {
+ T t;
+ move_construction_triviality_helper() = default;
+ move_construction_triviality_helper(move_construction_triviality_helper&&) = default;
+ ~move_construction_triviality_helper() = default;
+};
+} // end namespace detail
+
+/// An implementation of `std::is_trivially_copy_constructible` since we have
+/// users with STLs that don't yet include it.
+template <typename T>
+struct is_trivially_copy_constructible
+ : std::is_copy_constructible<
+ ::llvm::detail::copy_construction_triviality_helper<T>> {};
+template <typename T>
+struct is_trivially_copy_constructible<T &> : std::true_type {};
+template <typename T>
+struct is_trivially_copy_constructible<T &&> : std::false_type {};
+
+/// An implementation of `std::is_trivially_move_constructible` since we have
+/// users with STLs that don't yet include it.
+template <typename T>
+struct is_trivially_move_constructible
+ : std::is_move_constructible<
+ ::llvm::detail::move_construction_triviality_helper<T>> {};
+template <typename T>
+struct is_trivially_move_constructible<T &> : std::true_type {};
+template <typename T>
+struct is_trivially_move_constructible<T &&> : std::true_type {};
+
} // end namespace llvm
// If the compiler supports detecting whether a class is final, define
// an LLVM_IS_FINAL macro. If it cannot be defined properly, this
// macro will be left undefined.
-#if __cplusplus >= 201402L
+#if __cplusplus >= 201402L || defined(_MSC_VER)
#define LLVM_IS_FINAL(Ty) std::is_final<Ty>()
#elif __has_feature(is_final) || LLVM_GNUC_PREREQ(4, 7, 0)
#define LLVM_IS_FINAL(Ty) __is_final(Ty)