diff options
Diffstat (limited to 'include/llvm/Support')
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 ¤t_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 ¤t_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 ¬e(); + + /// 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 ¬e(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) |