diff options
Diffstat (limited to 'llvm/include/llvm/Support')
105 files changed, 3806 insertions, 1767 deletions
diff --git a/llvm/include/llvm/Support/AArch64TargetParser.def b/llvm/include/llvm/Support/AArch64TargetParser.def index 6b25ef2ca435f..13b7cfc4b5cd9 100644 --- a/llvm/include/llvm/Support/AArch64TargetParser.def +++ b/llvm/include/llvm/Support/AArch64TargetParser.def @@ -44,6 +44,13 @@ AARCH64_ARCH("armv8.5-a", ARMV8_5A, "8.5-A", "v8.5a", (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)) +AARCH64_ARCH("armv8.6-a", ARMV8_6A, "8.6-A", "v8.6a", + ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8, + (AArch64::AEK_CRC | AArch64::AEK_FP | + AArch64::AEK_SIMD | AArch64::AEK_RAS | AArch64::AEK_LSE | + AArch64::AEK_RDM | AArch64::AEK_RCPC | AArch64::AEK_DOTPROD | + AArch64::AEK_SM4 | AArch64::AEK_SHA3 | AArch64::AEK_BF16 | + AArch64::AEK_SHA2 | AArch64::AEK_AES | AArch64::AEK_I8MM)) #undef AARCH64_ARCH #ifndef AARCH64_ARCH_EXT_NAME @@ -79,12 +86,18 @@ AARCH64_ARCH_EXT_NAME("memtag", AArch64::AEK_MTE, "+mte", "-mte" AARCH64_ARCH_EXT_NAME("ssbs", AArch64::AEK_SSBS, "+ssbs", "-ssbs") AARCH64_ARCH_EXT_NAME("sb", AArch64::AEK_SB, "+sb", "-sb") AARCH64_ARCH_EXT_NAME("predres", AArch64::AEK_PREDRES, "+predres", "-predres") +AARCH64_ARCH_EXT_NAME("bf16", AArch64::AEK_BF16, "+bf16", "-bf16") +AARCH64_ARCH_EXT_NAME("i8mm", AArch64::AEK_I8MM, "+i8mm", "-i8mm") +AARCH64_ARCH_EXT_NAME("f32mm", AArch64::AEK_F32MM, "+f32mm", "-f32mm") +AARCH64_ARCH_EXT_NAME("f64mm", AArch64::AEK_F64MM, "+f64mm", "-f64mm") AARCH64_ARCH_EXT_NAME("tme", AArch64::AEK_TME, "+tme", "-tme") #undef AARCH64_ARCH_EXT_NAME #ifndef AARCH64_CPU_NAME #define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) #endif +AARCH64_CPU_NAME("cortex-a34", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_CRC)) AARCH64_CPU_NAME("cortex-a35", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, (AArch64::AEK_CRC)) AARCH64_CPU_NAME("cortex-a53", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, true, @@ -111,6 +124,15 @@ AARCH64_CPU_NAME("cortex-a76", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, AARCH64_CPU_NAME("cortex-a76ae", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, (AArch64::AEK_FP16 | AArch64::AEK_DOTPROD | AArch64::AEK_RCPC | AArch64::AEK_SSBS)) +AARCH64_CPU_NAME("cortex-a77", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_FP16 | AArch64::AEK_RCPC | AArch64::AEK_DOTPROD | + AArch64::AEK_SSBS)) +AARCH64_CPU_NAME("cortex-a78", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_FP16 | AArch64::AEK_DOTPROD | AArch64::AEK_RCPC | + AArch64::AEK_SSBS)) +AARCH64_CPU_NAME("cortex-x1", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_FP16 | AArch64::AEK_DOTPROD | AArch64::AEK_RCPC | + AArch64::AEK_SSBS)) AARCH64_CPU_NAME("neoverse-e1", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, (AArch64::AEK_DOTPROD | AArch64::AEK_FP16 | AArch64::AEK_RAS | AArch64::AEK_RCPC | AArch64::AEK_SSBS)) @@ -152,6 +174,10 @@ AARCH64_CPU_NAME("kryo", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, (AArch64::AEK_CRC)) AARCH64_CPU_NAME("thunderx2t99", ARMV8_1A, FK_CRYPTO_NEON_FP_ARMV8, false, (AArch64::AEK_NONE)) +AARCH64_CPU_NAME("thunderx3t110", ARMV8_3A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_CRC | AEK_CRYPTO | AEK_FP | AEK_SIMD | + AEK_LSE | AEK_RAND | AArch64::AEK_PROFILE | + AArch64::AEK_RAS)) AARCH64_CPU_NAME("thunderx", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, (AArch64::AEK_CRC | AArch64::AEK_PROFILE)) AARCH64_CPU_NAME("thunderxt88", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, @@ -164,6 +190,10 @@ AARCH64_CPU_NAME("tsv110", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, (AArch64::AEK_DOTPROD | AArch64::AEK_FP16 | AArch64::AEK_FP16FML | AArch64::AEK_PROFILE)) +AARCH64_CPU_NAME("a64fx", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_FP16 | AArch64::AEK_SVE)) +AARCH64_CPU_NAME("carmel", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + AArch64::AEK_FP16) // Invalid CPU AARCH64_CPU_NAME("invalid", INVALID, FK_INVALID, true, AArch64::AEK_INVALID) #undef AARCH64_CPU_NAME diff --git a/llvm/include/llvm/Support/AArch64TargetParser.h b/llvm/include/llvm/Support/AArch64TargetParser.h index fbe08945a038e..b045e31bc92aa 100644 --- a/llvm/include/llvm/Support/AArch64TargetParser.h +++ b/llvm/include/llvm/Support/AArch64TargetParser.h @@ -14,17 +14,20 @@ #ifndef LLVM_SUPPORT_AARCH64TARGETPARSERCOMMON_H #define LLVM_SUPPORT_AARCH64TARGETPARSERCOMMON_H +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" #include "llvm/Support/ARMTargetParser.h" #include <vector> // FIXME:This should be made into class design,to avoid dupplication. namespace llvm { + +class Triple; + namespace AArch64 { // Arch extension modifiers for CPUs. -enum ArchExtKind : unsigned { +enum ArchExtKind : uint64_t { AEK_INVALID = 0, AEK_NONE = 1, AEK_CRC = 1 << 1, @@ -55,6 +58,10 @@ enum ArchExtKind : unsigned { AEK_SVE2SHA3 = 1 << 26, AEK_SVE2BITPERM = 1 << 27, AEK_TME = 1 << 28, + AEK_BF16 = 1 << 29, + AEK_I8MM = 1 << 30, + AEK_F32MM = 1ULL << 31, + AEK_F64MM = 1ULL << 32, }; enum class ArchKind { diff --git a/llvm/include/llvm/Support/AMDGPUMetadata.h b/llvm/include/llvm/Support/AMDGPUMetadata.h index eeef4e699c3e0..920c97f7e112c 100644 --- a/llvm/include/llvm/Support/AMDGPUMetadata.h +++ b/llvm/include/llvm/Support/AMDGPUMetadata.h @@ -79,7 +79,8 @@ enum class ValueKind : uint8_t { Unknown = 0xff }; -/// Value types. +/// Value types. This is deprecated and only remains for compatibility parsing +/// of old metadata. enum class ValueType : uint8_t { Struct = 0, I8 = 1, @@ -164,7 +165,7 @@ constexpr char Offset[] = "Offset"; constexpr char Align[] = "Align"; /// Key for Kernel::Arg::Metadata::mValueKind. constexpr char ValueKind[] = "ValueKind"; -/// Key for Kernel::Arg::Metadata::mValueType. +/// Key for Kernel::Arg::Metadata::mValueType. (deprecated) constexpr char ValueType[] = "ValueType"; /// Key for Kernel::Arg::Metadata::mPointeeAlign. constexpr char PointeeAlign[] = "PointeeAlign"; @@ -198,8 +199,6 @@ struct Metadata final { uint32_t mAlign = 0; /// Value kind. Required. ValueKind mValueKind = ValueKind::Unknown; - /// Value type. Required. - ValueType mValueType = ValueType::Unknown; /// Pointee alignment in bytes. Optional. uint32_t mPointeeAlign = 0; /// Address space qualifier. Optional. diff --git a/llvm/include/llvm/Support/ARMAttributeParser.h b/llvm/include/llvm/Support/ARMAttributeParser.h index f6c39abb4f211..bf85ea14cfe33 100644 --- a/llvm/include/llvm/Support/ARMAttributeParser.h +++ b/llvm/include/llvm/Support/ARMAttributeParser.h @@ -1,4 +1,4 @@ -//===--- ARMAttributeParser.h - ARM Attribute Information Printer ---------===// +//===- ARMAttributeParser.h - ARM Attribute Information Printer -*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,132 +10,71 @@ #define LLVM_SUPPORT_ARMATTRIBUTEPARSER_H #include "ARMBuildAttributes.h" +#include "ELFAttributeParser.h" #include "ScopedPrinter.h" - -#include <map> +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" namespace llvm { class StringRef; -class ARMAttributeParser { - ScopedPrinter *SW; - - std::map<unsigned, unsigned> Attributes; - +class ARMAttributeParser : public ELFAttributeParser { struct DisplayHandler { - ARMBuildAttrs::AttrType Attribute; - void (ARMAttributeParser::*Routine)(ARMBuildAttrs::AttrType, - const uint8_t *, uint32_t &); + ARMBuildAttrs::AttrType attribute; + Error (ARMAttributeParser::*routine)(ARMBuildAttrs::AttrType); }; - static const DisplayHandler DisplayRoutines[]; - - uint64_t ParseInteger(const uint8_t *Data, uint32_t &Offset); - StringRef ParseString(const uint8_t *Data, uint32_t &Offset); - - void IntegerAttribute(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void StringAttribute(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - - void PrintAttribute(unsigned Tag, unsigned Value, StringRef ValueDesc); - - void CPU_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void CPU_arch_profile(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ARM_ISA_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void THUMB_ISA_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void FP_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void WMMX_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void Advanced_SIMD_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void MVE_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void PCS_config(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_PCS_R9_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_PCS_RW_data(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_PCS_RO_data(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_PCS_GOT_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_PCS_wchar_t(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_FP_rounding(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_FP_denormal(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_FP_exceptions(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_FP_user_exceptions(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_FP_number_model(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_align_needed(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_align_preserved(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_enum_size(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_HardFP_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_VFP_args(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_WMMX_args(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_optimization_goals(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_FP_optimization_goals(ARMBuildAttrs::AttrType Tag, - const uint8_t *Data, uint32_t &Offset); - void compatibility(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void CPU_unaligned_access(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void FP_HP_extension(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void ABI_FP_16bit_format(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void MPextension_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void DIV_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void DSP_extension(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void T2EE_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void Virtualization_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); - void nodefaults(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, - uint32_t &Offset); + static const DisplayHandler displayRoutines[]; + + Error handler(uint64_t tag, bool &handled) override; + + Error stringAttribute(ARMBuildAttrs::AttrType tag); + + Error CPU_arch(ARMBuildAttrs::AttrType tag); + Error CPU_arch_profile(ARMBuildAttrs::AttrType tag); + Error ARM_ISA_use(ARMBuildAttrs::AttrType tag); + Error THUMB_ISA_use(ARMBuildAttrs::AttrType tag); + Error FP_arch(ARMBuildAttrs::AttrType tag); + Error WMMX_arch(ARMBuildAttrs::AttrType tag); + Error Advanced_SIMD_arch(ARMBuildAttrs::AttrType tag); + Error MVE_arch(ARMBuildAttrs::AttrType tag); + Error PCS_config(ARMBuildAttrs::AttrType tag); + Error ABI_PCS_R9_use(ARMBuildAttrs::AttrType tag); + Error ABI_PCS_RW_data(ARMBuildAttrs::AttrType tag); + Error ABI_PCS_RO_data(ARMBuildAttrs::AttrType tag); + Error ABI_PCS_GOT_use(ARMBuildAttrs::AttrType tag); + Error ABI_PCS_wchar_t(ARMBuildAttrs::AttrType tag); + Error ABI_FP_rounding(ARMBuildAttrs::AttrType tag); + Error ABI_FP_denormal(ARMBuildAttrs::AttrType tag); + Error ABI_FP_exceptions(ARMBuildAttrs::AttrType tag); + Error ABI_FP_user_exceptions(ARMBuildAttrs::AttrType tag); + Error ABI_FP_number_model(ARMBuildAttrs::AttrType tag); + Error ABI_align_needed(ARMBuildAttrs::AttrType tag); + Error ABI_align_preserved(ARMBuildAttrs::AttrType tag); + Error ABI_enum_size(ARMBuildAttrs::AttrType tag); + Error ABI_HardFP_use(ARMBuildAttrs::AttrType tag); + Error ABI_VFP_args(ARMBuildAttrs::AttrType tag); + Error ABI_WMMX_args(ARMBuildAttrs::AttrType tag); + Error ABI_optimization_goals(ARMBuildAttrs::AttrType tag); + Error ABI_FP_optimization_goals(ARMBuildAttrs::AttrType tag); + Error compatibility(ARMBuildAttrs::AttrType tag); + Error CPU_unaligned_access(ARMBuildAttrs::AttrType tag); + Error FP_HP_extension(ARMBuildAttrs::AttrType tag); + Error ABI_FP_16bit_format(ARMBuildAttrs::AttrType tag); + Error MPextension_use(ARMBuildAttrs::AttrType tag); + Error DIV_use(ARMBuildAttrs::AttrType tag); + Error DSP_extension(ARMBuildAttrs::AttrType tag); + Error T2EE_use(ARMBuildAttrs::AttrType tag); + Error Virtualization_use(ARMBuildAttrs::AttrType tag); + Error nodefaults(ARMBuildAttrs::AttrType tag); - void ParseAttributeList(const uint8_t *Data, uint32_t &Offset, - uint32_t Length); - void ParseIndexList(const uint8_t *Data, uint32_t &Offset, - SmallVectorImpl<uint8_t> &IndexList); - void ParseSubsection(const uint8_t *Data, uint32_t Length); public: - ARMAttributeParser(ScopedPrinter *SW) : SW(SW) {} - - ARMAttributeParser() : SW(nullptr) { } - - void Parse(ArrayRef<uint8_t> Section, bool isLittle); - - bool hasAttribute(unsigned Tag) const { - return Attributes.count(Tag); - } - - unsigned getAttributeValue(unsigned Tag) const { - return Attributes.find(Tag)->second; - } + ARMAttributeParser(ScopedPrinter *sw) + : ELFAttributeParser(sw, ARMBuildAttrs::ARMAttributeTags, "aeabi") {} + ARMAttributeParser() + : ELFAttributeParser(ARMBuildAttrs::ARMAttributeTags, "aeabi") {} }; - } #endif - diff --git a/llvm/include/llvm/Support/ARMBuildAttributes.h b/llvm/include/llvm/Support/ARMBuildAttributes.h index 90481eaa1677c..5a06fd6ca7be7 100644 --- a/llvm/include/llvm/Support/ARMBuildAttributes.h +++ b/llvm/include/llvm/Support/ARMBuildAttributes.h @@ -18,77 +18,70 @@ #ifndef LLVM_SUPPORT_ARMBUILDATTRIBUTES_H #define LLVM_SUPPORT_ARMBUILDATTRIBUTES_H -namespace llvm { -class StringRef; +#include "llvm/Support/ELFAttributes.h" +namespace llvm { namespace ARMBuildAttrs { +extern const TagNameMap ARMAttributeTags; + enum SpecialAttr { // This is for the .cpu asm attr. It translates into one or more // AttrType (below) entries in the .ARM.attributes section in the ELF. SEL_CPU }; -enum AttrType { +enum AttrType : unsigned { // Rest correspond to ELF/.ARM.attributes - File = 1, - CPU_raw_name = 4, - CPU_name = 5, - CPU_arch = 6, - CPU_arch_profile = 7, - ARM_ISA_use = 8, - THUMB_ISA_use = 9, - FP_arch = 10, - WMMX_arch = 11, - Advanced_SIMD_arch = 12, - PCS_config = 13, - ABI_PCS_R9_use = 14, - ABI_PCS_RW_data = 15, - ABI_PCS_RO_data = 16, - ABI_PCS_GOT_use = 17, - ABI_PCS_wchar_t = 18, - ABI_FP_rounding = 19, - ABI_FP_denormal = 20, - ABI_FP_exceptions = 21, - ABI_FP_user_exceptions = 22, - ABI_FP_number_model = 23, - ABI_align_needed = 24, - ABI_align_preserved = 25, - ABI_enum_size = 26, - ABI_HardFP_use = 27, - ABI_VFP_args = 28, - ABI_WMMX_args = 29, - ABI_optimization_goals = 30, + File = 1, + CPU_raw_name = 4, + CPU_name = 5, + CPU_arch = 6, + CPU_arch_profile = 7, + ARM_ISA_use = 8, + THUMB_ISA_use = 9, + FP_arch = 10, + WMMX_arch = 11, + Advanced_SIMD_arch = 12, + PCS_config = 13, + ABI_PCS_R9_use = 14, + ABI_PCS_RW_data = 15, + ABI_PCS_RO_data = 16, + ABI_PCS_GOT_use = 17, + ABI_PCS_wchar_t = 18, + ABI_FP_rounding = 19, + ABI_FP_denormal = 20, + ABI_FP_exceptions = 21, + ABI_FP_user_exceptions = 22, + ABI_FP_number_model = 23, + ABI_align_needed = 24, + ABI_align_preserved = 25, + ABI_enum_size = 26, + ABI_HardFP_use = 27, + ABI_VFP_args = 28, + ABI_WMMX_args = 29, + ABI_optimization_goals = 30, ABI_FP_optimization_goals = 31, - compatibility = 32, - CPU_unaligned_access = 34, - FP_HP_extension = 36, - ABI_FP_16bit_format = 38, - MPextension_use = 42, // recoded from 70 (ABI r2.08) - DIV_use = 44, - DSP_extension = 46, - MVE_arch = 48, - also_compatible_with = 65, - conformance = 67, - Virtualization_use = 68, + compatibility = 32, + CPU_unaligned_access = 34, + FP_HP_extension = 36, + ABI_FP_16bit_format = 38, + MPextension_use = 42, // recoded from 70 (ABI r2.08) + DIV_use = 44, + DSP_extension = 46, + MVE_arch = 48, + also_compatible_with = 65, + conformance = 67, + Virtualization_use = 68, /// Legacy Tags - Section = 2, // deprecated (ABI r2.09) - Symbol = 3, // deprecated (ABI r2.09) - ABI_align8_needed = 24, // renamed to ABI_align_needed (ABI r2.09) - ABI_align8_preserved = 25, // renamed to ABI_align_preserved (ABI r2.09) - nodefaults = 64, // deprecated (ABI r2.09) - T2EE_use = 66, // deprecated (ABI r2.09) - MPextension_use_old = 70 // recoded to MPextension_use (ABI r2.08) -}; - -StringRef AttrTypeAsString(unsigned Attr, bool HasTagPrefix = true); -StringRef AttrTypeAsString(AttrType Attr, bool HasTagPrefix = true); -int AttrTypeFromString(StringRef Tag); - -// Magic numbers for .ARM.attributes -enum AttrMagic { - Format_Version = 0x41 + Section = 2, // deprecated (ABI r2.09) + Symbol = 3, // deprecated (ABI r2.09) + ABI_align8_needed = 24, // renamed to ABI_align_needed (ABI r2.09) + ABI_align8_preserved = 25, // renamed to ABI_align_preserved (ABI r2.09) + nodefaults = 64, // deprecated (ABI r2.09) + T2EE_use = 66, // deprecated (ABI r2.09) + MPextension_use_old = 70 // recoded to MPextension_use (ABI r2.08) }; // Legal Values for CPU_arch, (=6), uleb128 diff --git a/llvm/include/llvm/Support/ARMTargetParser.def b/llvm/include/llvm/Support/ARMTargetParser.def index 7f03d9a1320af..9f51c841e4296 100644 --- a/llvm/include/llvm/Support/ARMTargetParser.def +++ b/llvm/include/llvm/Support/ARMTargetParser.def @@ -112,6 +112,12 @@ ARM_ARCH("armv8.5-a", ARMV8_5A, "8.5-A", "v8.5a", (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.6-a", ARMV8_6A, "8.6-A", "v8.6a", + 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::AEK_BF16 | ARM::AEK_SHA2 | ARM::AEK_AES | + ARM::AEK_I8MM)) 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 | @@ -164,8 +170,18 @@ ARM_ARCH_EXT_NAME("iwmmxt2", ARM::AEK_IWMMXT2, nullptr, nullptr) ARM_ARCH_EXT_NAME("maverick", ARM::AEK_MAVERICK, nullptr, nullptr) ARM_ARCH_EXT_NAME("xscale", ARM::AEK_XSCALE, nullptr, nullptr) ARM_ARCH_EXT_NAME("fp16fml", ARM::AEK_FP16FML, "+fp16fml", "-fp16fml") +ARM_ARCH_EXT_NAME("bf16", ARM::AEK_BF16, "+bf16", "-bf16") ARM_ARCH_EXT_NAME("sb", ARM::AEK_SB, "+sb", "-sb") +ARM_ARCH_EXT_NAME("i8mm", ARM::AEK_I8MM, "+i8mm", "-i8mm") ARM_ARCH_EXT_NAME("lob", ARM::AEK_LOB, "+lob", "-lob") +ARM_ARCH_EXT_NAME("cdecp0", ARM::AEK_CDECP0, "+cdecp0", "-cdecp0") +ARM_ARCH_EXT_NAME("cdecp1", ARM::AEK_CDECP1, "+cdecp1", "-cdecp1") +ARM_ARCH_EXT_NAME("cdecp2", ARM::AEK_CDECP2, "+cdecp2", "-cdecp2") +ARM_ARCH_EXT_NAME("cdecp3", ARM::AEK_CDECP3, "+cdecp3", "-cdecp3") +ARM_ARCH_EXT_NAME("cdecp4", ARM::AEK_CDECP4, "+cdecp4", "-cdecp4") +ARM_ARCH_EXT_NAME("cdecp5", ARM::AEK_CDECP5, "+cdecp5", "-cdecp5") +ARM_ARCH_EXT_NAME("cdecp6", ARM::AEK_CDECP6, "+cdecp6", "-cdecp6") +ARM_ARCH_EXT_NAME("cdecp7", ARM::AEK_CDECP7, "+cdecp7", "-cdecp7") #undef ARM_ARCH_EXT_NAME #ifndef ARM_HW_DIV_NAME @@ -260,6 +276,8 @@ ARM_CPU_NAME("cortex-m7", ARMV7EM, FK_FPV5_D16, false, ARM::AEK_NONE) ARM_CPU_NAME("cortex-m23", ARMV8MBaseline, FK_NONE, false, ARM::AEK_NONE) ARM_CPU_NAME("cortex-m33", ARMV8MMainline, FK_FPV5_SP_D16, false, ARM::AEK_DSP) ARM_CPU_NAME("cortex-m35p", ARMV8MMainline, FK_FPV5_SP_D16, false, ARM::AEK_DSP) +ARM_CPU_NAME("cortex-m55", ARMV8_1MMainline, FK_FP_ARMV8_FULLFP16_D16, false, + (ARM::AEK_DSP | ARM::AEK_SIMD | ARM::AEK_FP | ARM::AEK_FP16)) ARM_CPU_NAME("cortex-a32", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) ARM_CPU_NAME("cortex-a35", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) ARM_CPU_NAME("cortex-a53", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) @@ -274,6 +292,12 @@ ARM_CPU_NAME("cortex-a76", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, (ARM::AEK_FP16 | ARM::AEK_DOTPROD)) ARM_CPU_NAME("cortex-a76ae", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, (ARM::AEK_FP16 | ARM::AEK_DOTPROD)) +ARM_CPU_NAME("cortex-a77", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (ARM::AEK_FP16 | ARM::AEK_DOTPROD)) +ARM_CPU_NAME("cortex-a78",ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (ARM::AEK_FP16 | ARM::AEK_DOTPROD)) +ARM_CPU_NAME("cortex-x1", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, + (ARM::AEK_FP16 | ARM::AEK_DOTPROD)) ARM_CPU_NAME("neoverse-n1", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false, (ARM::AEK_FP16 | ARM::AEK_DOTPROD)) ARM_CPU_NAME("cyclone", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) diff --git a/llvm/include/llvm/Support/ARMTargetParser.h b/llvm/include/llvm/Support/ARMTargetParser.h index 02d4c975129fb..4e76b3c4b83e0 100644 --- a/llvm/include/llvm/Support/ARMTargetParser.h +++ b/llvm/include/llvm/Support/ARMTargetParser.h @@ -14,17 +14,20 @@ #ifndef LLVM_SUPPORT_ARMTARGETPARSER_H #define LLVM_SUPPORT_ARMTARGETPARSER_H +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" #include "llvm/Support/ARMBuildAttributes.h" #include <vector> namespace llvm { + +class Triple; + namespace ARM { // Arch extension modifiers for CPUs. // Note that this is not the same as the AArch64 list -enum ArchExtKind : unsigned { +enum ArchExtKind : uint64_t { AEK_INVALID = 0, AEK_NONE = 1, AEK_CRC = 1 << 1, @@ -46,12 +49,23 @@ enum ArchExtKind : unsigned { AEK_SB = 1 << 17, AEK_FP_DP = 1 << 18, AEK_LOB = 1 << 19, + AEK_BF16 = 1 << 20, + AEK_I8MM = 1 << 21, + AEK_CDECP0 = 1 << 22, + AEK_CDECP1 = 1 << 23, + AEK_CDECP2 = 1 << 24, + AEK_CDECP3 = 1 << 25, + AEK_CDECP4 = 1 << 26, + AEK_CDECP5 = 1 << 27, + AEK_CDECP6 = 1 << 28, + AEK_CDECP7 = 1 << 29, + // Unsupported extensions. - AEK_OS = 0x8000000, - AEK_IWMMXT = 0x10000000, - AEK_IWMMXT2 = 0x20000000, - AEK_MAVERICK = 0x40000000, - AEK_XSCALE = 0x80000000, + AEK_OS = 1ULL << 59, + AEK_IWMMXT = 1ULL << 60, + AEK_IWMMXT2 = 1ULL << 61, + AEK_MAVERICK = 1ULL << 62, + AEK_XSCALE = 1ULL << 63, }; // List of Arch Extension names. @@ -59,7 +73,7 @@ enum ArchExtKind : unsigned { struct ExtName { const char *NameCStr; size_t NameLength; - unsigned ID; + uint64_t ID; const char *Feature; const char *NegFeature; @@ -78,7 +92,7 @@ const ExtName ARCHExtNames[] = { const struct { const char *NameCStr; size_t NameLength; - unsigned ID; + uint64_t ID; StringRef getName() const { return StringRef(NameCStr, NameLength); } } HWDivNames[] = { @@ -102,7 +116,7 @@ template <typename T> struct CpuNames { size_t NameLength; T ArchID; bool Default; // is $Name the default CPU for $ArchID ? - unsigned DefaultExtensions; + uint64_t DefaultExtensions; StringRef getName() const { return StringRef(NameCStr, NameLength); } }; @@ -193,7 +207,7 @@ template <typename T> struct ArchNames { const char *SubArchCStr; size_t SubArchLength; unsigned DefaultFPU; - unsigned ArchBaseExtensions; + uint64_t ArchBaseExtensions; T ID; ARMBuildAttrs::CPUArch ArchAttr; // Arch ID in build attributes. @@ -225,33 +239,33 @@ FPURestriction getFPURestriction(unsigned FPUKind); // FIXME: These should be moved to TargetTuple once it exists bool getFPUFeatures(unsigned FPUKind, std::vector<StringRef> &Features); -bool getHWDivFeatures(unsigned HWDivKind, std::vector<StringRef> &Features); -bool getExtensionFeatures(unsigned Extensions, +bool getHWDivFeatures(uint64_t HWDivKind, std::vector<StringRef> &Features); +bool getExtensionFeatures(uint64_t Extensions, std::vector<StringRef> &Features); StringRef getArchName(ArchKind AK); unsigned getArchAttr(ArchKind AK); StringRef getCPUAttr(ArchKind AK); StringRef getSubArch(ArchKind AK); -StringRef getArchExtName(unsigned ArchExtKind); +StringRef getArchExtName(uint64_t ArchExtKind); StringRef getArchExtFeature(StringRef ArchExt); bool appendArchExtFeatures(StringRef CPU, ARM::ArchKind AK, StringRef ArchExt, std::vector<StringRef> &Features); -StringRef getHWDivName(unsigned HWDivKind); +StringRef getHWDivName(uint64_t HWDivKind); // Information by Name unsigned getDefaultFPU(StringRef CPU, ArchKind AK); -unsigned getDefaultExtensions(StringRef CPU, ArchKind AK); +uint64_t getDefaultExtensions(StringRef CPU, ArchKind AK); StringRef getDefaultCPU(StringRef Arch); StringRef getCanonicalArchName(StringRef Arch); StringRef getFPUSynonym(StringRef FPU); StringRef getArchSynonym(StringRef Arch); // Parser -unsigned parseHWDiv(StringRef HWDiv); +uint64_t parseHWDiv(StringRef HWDiv); unsigned parseFPU(StringRef FPU); ArchKind parseArch(StringRef Arch); -unsigned parseArchExt(StringRef ArchExt); +uint64_t parseArchExt(StringRef ArchExt); ArchKind parseCPUArch(StringRef CPU); ISAKind parseArchISA(StringRef Arch); EndianKind parseArchEndian(StringRef Arch); diff --git a/llvm/include/llvm/Support/Alignment.h b/llvm/include/llvm/Support/Alignment.h index 72fad87dd0d4d..667434e8a407f 100644 --- a/llvm/include/llvm/Support/Alignment.h +++ b/llvm/include/llvm/Support/Alignment.h @@ -22,17 +22,16 @@ #define LLVM_SUPPORT_ALIGNMENT_H_ #include "llvm/ADT/Optional.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/MathExtras.h" #include <cassert> -#include <limits> +#ifndef NDEBUG +#include <string> +#endif // NDEBUG namespace llvm { #define ALIGN_CHECK_ISPOSITIVE(decl) \ assert(decl > 0 && (#decl " should be defined")) -#define ALIGN_CHECK_ISSET(decl) \ - assert(decl.hasValue() && (#decl " should be defined")) /// This struct is a compact representation of a valid (non-zero power of two) /// alignment. @@ -86,11 +85,14 @@ public: uint64_t value() const { return uint64_t(1) << ShiftValue; } /// Returns a default constructed Align which corresponds to no alignment. - /// This is useful to test for unalignment as it conveys clear semantic. - /// `if (A != Align::None())` - /// would be better than - /// `if (A > Align(1))` - constexpr static const Align None() { return Align(); } + /// It was decided to deprecate Align::None because it's too close to + /// llvm::None which can be used to initialize `MaybeAlign`. + /// MaybeAlign = llvm::None means unspecified alignment, + /// Align = Align::None() means alignment of one byte. + LLVM_ATTRIBUTE_DEPRECATED(constexpr static const Align None(), + "Use Align() or Align(1) instead") { + return Align(); + } /// Allow constructions of constexpr Align. template <size_t kValue> constexpr static LogValue Constant() { @@ -147,13 +149,6 @@ inline bool isAligned(Align Lhs, uint64_t SizeInBytes) { return SizeInBytes % Lhs.value() == 0; } -/// Checks that SizeInBytes is a multiple of the alignment. -/// Returns false if the alignment is undefined. -inline bool isAligned(MaybeAlign Lhs, uint64_t SizeInBytes) { - ALIGN_CHECK_ISSET(Lhs); - return SizeInBytes % (*Lhs).value() == 0; -} - /// Checks that Addr is a multiple of the alignment. inline bool isAddrAligned(Align Lhs, const void *Addr) { return isAligned(Lhs, reinterpret_cast<uintptr_t>(Addr)); @@ -161,17 +156,34 @@ inline bool isAddrAligned(Align Lhs, const void *Addr) { /// Returns a multiple of A needed to store `Size` bytes. inline uint64_t alignTo(uint64_t Size, Align A) { - const uint64_t value = A.value(); - // The following line is equivalent to `(Size + value - 1) / value * value`. + const uint64_t Value = A.value(); + // The following line is equivalent to `(Size + Value - 1) / Value * Value`. // The division followed by a multiplication can be thought of as a right // shift followed by a left shift which zeros out the extra bits produced in - // the bump; `~(value - 1)` is a mask where all those bits being zeroed out + // the bump; `~(Value - 1)` is a mask where all those bits being zeroed out // are just zero. // Most compilers can generate this code but the pattern may be missed when // multiple functions gets inlined. - return (Size + value - 1) & ~(value - 1); + return (Size + Value - 1) & ~(Value - 1U); +} + +/// If non-zero \p Skew is specified, the return value will be a minimal integer +/// that is greater than or equal to \p Size and equal to \p A * N + \p Skew for +/// some integer N. If \p Skew is larger than \p A, its value is adjusted to '\p +/// Skew mod \p A'. +/// +/// Examples: +/// \code +/// alignTo(5, Align(8), 7) = 7 +/// alignTo(17, Align(8), 1) = 17 +/// alignTo(~0LL, Align(8), 3) = 3 +/// \endcode +inline uint64_t alignTo(uint64_t Size, Align A, uint64_t Skew) { + const uint64_t Value = A.value(); + Skew %= Value; + return ((Size + Value - 1 - Skew) & ~(Value - 1U)) + Skew; } /// Returns a multiple of A needed to store `Size` bytes. @@ -184,7 +196,8 @@ inline uint64_t alignTo(uint64_t Size, MaybeAlign A) { inline uintptr_t alignAddr(const void *Addr, Align Alignment) { uintptr_t ArithAddr = reinterpret_cast<uintptr_t>(Addr); assert(static_cast<uintptr_t>(ArithAddr + Alignment.value() - 1) >= - ArithAddr && "Overflow"); + ArithAddr && + "Overflow"); return alignTo(ArithAddr, Alignment); } @@ -203,13 +216,6 @@ inline uint64_t offsetToAlignedAddr(const void *Addr, Align Alignment) { /// Returns the log2 of the alignment. inline unsigned Log2(Align A) { return A.ShiftValue; } -/// Returns the log2 of the alignment. -/// \pre A must be defined. -inline unsigned Log2(MaybeAlign A) { - ALIGN_CHECK_ISSET(A); - return Log2(A.getValue()); -} - /// Returns the alignment that satisfies both alignments. /// Same semantic as MinAlign. inline Align commonAlignment(Align A, Align B) { return std::min(A, B); } @@ -281,26 +287,6 @@ inline bool operator==(MaybeAlign Lhs, uint64_t Rhs) { inline bool operator!=(MaybeAlign Lhs, uint64_t Rhs) { return Lhs ? (*Lhs).value() != Rhs : Rhs != 0; } -inline bool operator<=(MaybeAlign Lhs, uint64_t Rhs) { - ALIGN_CHECK_ISSET(Lhs); - ALIGN_CHECK_ISPOSITIVE(Rhs); - return (*Lhs).value() <= Rhs; -} -inline bool operator>=(MaybeAlign Lhs, uint64_t Rhs) { - ALIGN_CHECK_ISSET(Lhs); - ALIGN_CHECK_ISPOSITIVE(Rhs); - return (*Lhs).value() >= Rhs; -} -inline bool operator<(MaybeAlign Lhs, uint64_t Rhs) { - ALIGN_CHECK_ISSET(Lhs); - ALIGN_CHECK_ISPOSITIVE(Rhs); - return (*Lhs).value() < Rhs; -} -inline bool operator>(MaybeAlign Lhs, uint64_t Rhs) { - ALIGN_CHECK_ISSET(Lhs); - ALIGN_CHECK_ISPOSITIVE(Rhs); - return (*Lhs).value() > Rhs; -} /// Comparisons operators between Align. inline bool operator==(Align Lhs, Align Rhs) { @@ -322,56 +308,30 @@ inline bool operator>(Align Lhs, Align Rhs) { return Lhs.ShiftValue > Rhs.ShiftValue; } -/// Comparisons operators between Align and MaybeAlign. -inline bool operator==(Align Lhs, MaybeAlign Rhs) { - ALIGN_CHECK_ISSET(Rhs); - return Lhs.value() == (*Rhs).value(); -} -inline bool operator!=(Align Lhs, MaybeAlign Rhs) { - ALIGN_CHECK_ISSET(Rhs); - return Lhs.value() != (*Rhs).value(); -} -inline bool operator<=(Align Lhs, MaybeAlign Rhs) { - ALIGN_CHECK_ISSET(Rhs); - return Lhs.value() <= (*Rhs).value(); -} -inline bool operator>=(Align Lhs, MaybeAlign Rhs) { - ALIGN_CHECK_ISSET(Rhs); - return Lhs.value() >= (*Rhs).value(); -} -inline bool operator<(Align Lhs, MaybeAlign Rhs) { - ALIGN_CHECK_ISSET(Rhs); - return Lhs.value() < (*Rhs).value(); -} -inline bool operator>(Align Lhs, MaybeAlign Rhs) { - ALIGN_CHECK_ISSET(Rhs); - return Lhs.value() > (*Rhs).value(); -} +// Don't allow relational comparisons with MaybeAlign. +bool operator<=(Align Lhs, MaybeAlign Rhs) = delete; +bool operator>=(Align Lhs, MaybeAlign Rhs) = delete; +bool operator<(Align Lhs, MaybeAlign Rhs) = delete; +bool operator>(Align Lhs, MaybeAlign Rhs) = delete; -/// Comparisons operators between MaybeAlign and Align. -inline bool operator==(MaybeAlign Lhs, Align Rhs) { - ALIGN_CHECK_ISSET(Lhs); - return Lhs && (*Lhs).value() == Rhs.value(); -} -inline bool operator!=(MaybeAlign Lhs, Align Rhs) { - ALIGN_CHECK_ISSET(Lhs); - return Lhs && (*Lhs).value() != Rhs.value(); -} -inline bool operator<=(MaybeAlign Lhs, Align Rhs) { - ALIGN_CHECK_ISSET(Lhs); - return Lhs && (*Lhs).value() <= Rhs.value(); -} -inline bool operator>=(MaybeAlign Lhs, Align Rhs) { - ALIGN_CHECK_ISSET(Lhs); - return Lhs && (*Lhs).value() >= Rhs.value(); -} -inline bool operator<(MaybeAlign Lhs, Align Rhs) { - ALIGN_CHECK_ISSET(Lhs); - return Lhs && (*Lhs).value() < Rhs.value(); +bool operator<=(MaybeAlign Lhs, Align Rhs) = delete; +bool operator>=(MaybeAlign Lhs, Align Rhs) = delete; +bool operator<(MaybeAlign Lhs, Align Rhs) = delete; +bool operator>(MaybeAlign Lhs, Align Rhs) = delete; + +bool operator<=(MaybeAlign Lhs, MaybeAlign Rhs) = delete; +bool operator>=(MaybeAlign Lhs, MaybeAlign Rhs) = delete; +bool operator<(MaybeAlign Lhs, MaybeAlign Rhs) = delete; +bool operator>(MaybeAlign Lhs, MaybeAlign Rhs) = delete; + +inline Align operator*(Align Lhs, uint64_t Rhs) { + assert(Rhs > 0 && "Rhs must be positive"); + return Align(Lhs.value() * Rhs); } -inline bool operator>(MaybeAlign Lhs, Align Rhs) { - ALIGN_CHECK_ISSET(Lhs); - return Lhs && (*Lhs).value() > Rhs.value(); + +inline MaybeAlign operator*(MaybeAlign Lhs, uint64_t Rhs) { + assert(Rhs > 0 && "Rhs must be positive"); + return Lhs ? Lhs.getValue() * Rhs : MaybeAlign(); } inline Align operator/(Align Lhs, uint64_t Divisor) { @@ -395,8 +355,20 @@ inline Align max(Align Lhs, MaybeAlign Rhs) { return Rhs && *Rhs > Lhs ? *Rhs : Lhs; } +#ifndef NDEBUG +// For usage in LLVM_DEBUG macros. +inline std::string DebugStr(const Align &A) { + return std::to_string(A.value()); +} +// For usage in LLVM_DEBUG macros. +inline std::string DebugStr(const MaybeAlign &MA) { + if (MA) + return std::to_string(MA->value()); + return "None"; +} +#endif // NDEBUG + #undef ALIGN_CHECK_ISPOSITIVE -#undef ALIGN_CHECK_ISSET } // namespace llvm diff --git a/llvm/include/llvm/Support/Allocator.h b/llvm/include/llvm/Support/Allocator.h index 670335ffecbcb..40c967ccc4857 100644 --- a/llvm/include/llvm/Support/Allocator.h +++ b/llvm/include/llvm/Support/Allocator.h @@ -7,13 +7,10 @@ //===----------------------------------------------------------------------===// /// \file /// -/// This file defines the MallocAllocator and BumpPtrAllocator interfaces. Both -/// of these conform to an LLVM "Allocator" concept which consists of an -/// Allocate method accepting a size and alignment, and a Deallocate accepting -/// a pointer and size. Further, the LLVM "Allocator" concept has overloads of -/// Allocate and Deallocate for setting size and alignment based on the final -/// type. These overloads are typically provided by a base class template \c -/// AllocatorBase. +/// This file defines the BumpPtrAllocator interface. BumpPtrAllocator conforms +/// to the LLVM "Allocator" concept and is similar to MallocAllocator, but +/// objects cannot be deallocated. Their lifetime is tied to the lifetime of the +/// allocator. /// //===----------------------------------------------------------------------===// @@ -23,6 +20,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Alignment.h" +#include "llvm/Support/AllocatorBase.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" @@ -38,81 +36,6 @@ namespace llvm { -/// 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 -/// LLVM-style allocators, and redirects all of the overloads to a single core -/// set of methods which the derived class must define. -template <typename DerivedT> class AllocatorBase { -public: - /// 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__ - static_assert(static_cast<void *(AllocatorBase::*)(size_t, size_t)>( - &AllocatorBase::Allocate) != - static_cast<void *(DerivedT::*)(size_t, size_t)>( - &DerivedT::Allocate), - "Class derives from AllocatorBase without implementing the " - "core Allocate(size_t, size_t) overload!"); -#endif - return static_cast<DerivedT *>(this)->Allocate(Size, Alignment); - } - - /// Deallocate \a Ptr to \a Size bytes of memory allocated by this - /// allocator. - void Deallocate(const void *Ptr, size_t Size) { -#ifdef __clang__ - static_assert(static_cast<void (AllocatorBase::*)(const void *, size_t)>( - &AllocatorBase::Deallocate) != - static_cast<void (DerivedT::*)(const void *, size_t)>( - &DerivedT::Deallocate), - "Class derives from AllocatorBase without implementing the " - "core Deallocate(void *) overload!"); -#endif - return static_cast<DerivedT *>(this)->Deallocate(Ptr, Size); - } - - // The rest of these methods are helpers that redirect to one of the above - // core methods. - - /// 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))); - } - - /// 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 - Deallocate(T *Ptr, size_t Num = 1) { - Deallocate(static_cast<const void *>(Ptr), Num * sizeof(T)); - } -}; - -class MallocAllocator : public AllocatorBase<MallocAllocator> { -public: - void Reset() {} - - LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t Size, - size_t /*Alignment*/) { - return safe_malloc(Size); - } - - // Pull in base class overloads. - using AllocatorBase<MallocAllocator>::Allocate; - - void Deallocate(const void *Ptr, size_t /*Size*/) { - free(const_cast<void *>(Ptr)); - } - - // Pull in base class overloads. - using AllocatorBase<MallocAllocator>::Deallocate; - - void PrintStats() const {} -}; - namespace detail { // We call out to an external function to actually print the message as the @@ -136,16 +59,22 @@ void printBumpPtrAllocatorStats(unsigned NumSlabs, size_t BytesAllocated, /// The BumpPtrAllocatorImpl template defaults to using a MallocAllocator /// object, which wraps malloc, to allocate memory, but it can be changed to /// use a custom allocator. +/// +/// The GrowthDelay specifies after how many allocated slabs the allocator +/// increases the size of the slabs. template <typename AllocatorT = MallocAllocator, size_t SlabSize = 4096, - size_t SizeThreshold = SlabSize> + size_t SizeThreshold = SlabSize, size_t GrowthDelay = 128> class BumpPtrAllocatorImpl - : public AllocatorBase< - BumpPtrAllocatorImpl<AllocatorT, SlabSize, SizeThreshold>> { + : public AllocatorBase<BumpPtrAllocatorImpl<AllocatorT, SlabSize, + SizeThreshold, GrowthDelay>> { public: static_assert(SizeThreshold <= SlabSize, "The SizeThreshold must be at most the SlabSize to ensure " "that objects larger than a slab go into their own memory " "allocation."); + static_assert(GrowthDelay > 0, + "GrowthDelay must be at least 1 which already increases the" + "slab size after each allocated slab."); BumpPtrAllocatorImpl() = default; @@ -241,7 +170,7 @@ public: // If Size is really big, allocate a separate slab for it. size_t PaddedSize = SizeToAllocate + Alignment.value() - 1; if (PaddedSize > SizeThreshold) { - void *NewSlab = Allocator.Allocate(PaddedSize, 0); + void *NewSlab = Allocator.Allocate(PaddedSize, alignof(std::max_align_t)); // We own the new slab and don't want anyone reading anyting other than // pieces returned from this method. So poison the whole slab. __asan_poison_memory_region(NewSlab, PaddedSize); @@ -279,7 +208,7 @@ public: // Bump pointer allocators are expected to never free their storage; and // clients expect pointers to remain valid for non-dereferencing uses even // after deallocation. - void Deallocate(const void *Ptr, size_t Size) { + void Deallocate(const void *Ptr, size_t Size, size_t /*Alignment*/) { __asan_poison_memory_region(Ptr, Size); } @@ -391,10 +320,11 @@ private: static size_t computeSlabSize(unsigned SlabIdx) { // Scale the actual allocated slab size based on the number of slabs - // allocated. Every 128 slabs allocated, we double the allocated size to - // reduce allocation frequency, but saturate at multiplying the slab size by - // 2^30. - return SlabSize * ((size_t)1 << std::min<size_t>(30, SlabIdx / 128)); + // allocated. Every GrowthDelay slabs allocated, we double + // the allocated size to reduce allocation frequency, but saturate at + // multiplying the slab size by 2^30. + return SlabSize * + ((size_t)1 << std::min<size_t>(30, SlabIdx / GrowthDelay)); } /// Allocate a new slab and move the bump pointers over into the new @@ -402,7 +332,8 @@ private: void StartNewSlab() { size_t AllocatedSlabSize = computeSlabSize(Slabs.size()); - void *NewSlab = Allocator.Allocate(AllocatedSlabSize, 0); + void *NewSlab = + Allocator.Allocate(AllocatedSlabSize, alignof(std::max_align_t)); // We own the new slab and don't want anyone reading anything other than // pieces returned from this method. So poison the whole slab. __asan_poison_memory_region(NewSlab, AllocatedSlabSize); @@ -418,7 +349,7 @@ private: for (; I != E; ++I) { size_t AllocatedSlabSize = computeSlabSize(std::distance(Slabs.begin(), I)); - Allocator.Deallocate(*I, AllocatedSlabSize); + Allocator.Deallocate(*I, AllocatedSlabSize, alignof(std::max_align_t)); } } @@ -427,7 +358,7 @@ private: for (auto &PtrAndSize : CustomSizedSlabs) { void *Ptr = PtrAndSize.first; size_t Size = PtrAndSize.second; - Allocator.Deallocate(Ptr, Size); + Allocator.Deallocate(Ptr, Size, alignof(std::max_align_t)); } } @@ -498,26 +429,21 @@ public: } // end namespace llvm -template <typename AllocatorT, size_t SlabSize, size_t SizeThreshold> -void *operator new(size_t Size, - llvm::BumpPtrAllocatorImpl<AllocatorT, SlabSize, - SizeThreshold> &Allocator) { - struct S { - char c; - union { - double D; - long double LD; - long long L; - void *P; - } x; - }; - return Allocator.Allocate( - Size, std::min((size_t)llvm::NextPowerOf2(Size), offsetof(S, x))); +template <typename AllocatorT, size_t SlabSize, size_t SizeThreshold, + size_t GrowthDelay> +void * +operator new(size_t Size, + llvm::BumpPtrAllocatorImpl<AllocatorT, SlabSize, SizeThreshold, + GrowthDelay> &Allocator) { + return Allocator.Allocate(Size, std::min((size_t)llvm::NextPowerOf2(Size), + alignof(std::max_align_t))); } -template <typename AllocatorT, size_t SlabSize, size_t SizeThreshold> -void operator delete( - void *, llvm::BumpPtrAllocatorImpl<AllocatorT, SlabSize, SizeThreshold> &) { +template <typename AllocatorT, size_t SlabSize, size_t SizeThreshold, + size_t GrowthDelay> +void operator delete(void *, + llvm::BumpPtrAllocatorImpl<AllocatorT, SlabSize, + SizeThreshold, GrowthDelay> &) { } #endif // LLVM_SUPPORT_ALLOCATOR_H diff --git a/llvm/include/llvm/Support/AllocatorBase.h b/llvm/include/llvm/Support/AllocatorBase.h new file mode 100644 index 0000000000000..e5549d111622e --- /dev/null +++ b/llvm/include/llvm/Support/AllocatorBase.h @@ -0,0 +1,103 @@ +//===- AllocatorBase.h - Simple memory allocation abstraction ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines MallocAllocator. MallocAllocator conforms to the LLVM +/// "Allocator" concept which consists of an Allocate method accepting a size +/// and alignment, and a Deallocate accepting a pointer and size. Further, the +/// LLVM "Allocator" concept has overloads of Allocate and Deallocate for +/// setting size and alignment based on the final type. These overloads are +/// typically provided by a base class template \c AllocatorBase. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ALLOCATORBASE_H +#define LLVM_SUPPORT_ALLOCATORBASE_H + +#include "llvm/Support/Compiler.h" +#include "llvm/Support/MemAlloc.h" + +namespace llvm { + +/// 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 +/// LLVM-style allocators, and redirects all of the overloads to a single core +/// set of methods which the derived class must define. +template <typename DerivedT> class AllocatorBase { +public: + /// 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__ + static_assert(static_cast<void *(AllocatorBase::*)(size_t, size_t)>( + &AllocatorBase::Allocate) != + static_cast<void *(DerivedT::*)(size_t, size_t)>( + &DerivedT::Allocate), + "Class derives from AllocatorBase without implementing the " + "core Allocate(size_t, size_t) overload!"); +#endif + return static_cast<DerivedT *>(this)->Allocate(Size, Alignment); + } + + /// Deallocate \a Ptr to \a Size bytes of memory allocated by this + /// allocator. + void Deallocate(const void *Ptr, size_t Size, size_t Alignment) { +#ifdef __clang__ + static_assert( + static_cast<void (AllocatorBase::*)(const void *, size_t, size_t)>( + &AllocatorBase::Deallocate) != + static_cast<void (DerivedT::*)(const void *, size_t, size_t)>( + &DerivedT::Deallocate), + "Class derives from AllocatorBase without implementing the " + "core Deallocate(void *) overload!"); +#endif + return static_cast<DerivedT *>(this)->Deallocate(Ptr, Size, Alignment); + } + + // The rest of these methods are helpers that redirect to one of the above + // core methods. + + /// 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))); + } + + /// Deallocate space for a sequence of objects without constructing them. + template <typename T> + std::enable_if_t<!std::is_same<std::remove_cv_t<T>, void>::value, void> + Deallocate(T *Ptr, size_t Num = 1) { + Deallocate(static_cast<const void *>(Ptr), Num * sizeof(T), alignof(T)); + } +}; + +class MallocAllocator : public AllocatorBase<MallocAllocator> { +public: + void Reset() {} + + LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t Size, size_t Alignment) { + return allocate_buffer(Size, Alignment); + } + + // Pull in base class overloads. + using AllocatorBase<MallocAllocator>::Allocate; + + void Deallocate(const void *Ptr, size_t Size, size_t Alignment) { + deallocate_buffer(const_cast<void *>(Ptr), Size, Alignment); + } + + // Pull in base class overloads. + using AllocatorBase<MallocAllocator>::Deallocate; + + void PrintStats() const {} +}; + +} // namespace llvm + +#endif // LLVM_SUPPORT_ALLOCATORBASE_H diff --git a/llvm/include/llvm/Support/AtomicOrdering.h b/llvm/include/llvm/Support/AtomicOrdering.h index 763bc3ea7b282..a8d89955fa2b5 100644 --- a/llvm/include/llvm/Support/AtomicOrdering.h +++ b/llvm/include/llvm/Support/AtomicOrdering.h @@ -53,7 +53,7 @@ template <typename Int> inline bool isValidAtomicOrderingCABI(Int I) { /// /// not_atomic-->unordered-->relaxed-->release--------------->acq_rel-->seq_cst /// \-->consume-->acquire--/ -enum class AtomicOrdering { +enum class AtomicOrdering : unsigned { NotAtomic = 0, Unordered = 1, Monotonic = 2, // Equivalent to C++'s relaxed. @@ -61,7 +61,8 @@ enum class AtomicOrdering { Acquire = 4, Release = 5, AcquireRelease = 6, - SequentiallyConsistent = 7 + SequentiallyConsistent = 7, + LAST = SequentiallyConsistent }; bool operator<(AtomicOrdering, AtomicOrdering) = delete; diff --git a/llvm/include/llvm/Support/Base64.h b/llvm/include/llvm/Support/Base64.h new file mode 100644 index 0000000000000..62064a35aa344 --- /dev/null +++ b/llvm/include/llvm/Support/Base64.h @@ -0,0 +1,56 @@ +//===--- Base64.h - Base64 Encoder/Decoder ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides generic base64 encoder/decoder. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_BASE64_H +#define LLVM_SUPPORT_BASE64_H + +#include <string> + +namespace llvm { + +template <class InputBytes> std::string encodeBase64(InputBytes const &Bytes) { + static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + std::string Buffer; + Buffer.resize(((Bytes.size() + 2) / 3) * 4); + + size_t i = 0, j = 0; + for (size_t n = Bytes.size() / 3 * 3; i < n; i += 3, j += 4) { + uint32_t x = ((unsigned char)Bytes[i] << 16) | + ((unsigned char)Bytes[i + 1] << 8) | + (unsigned char)Bytes[i + 2]; + Buffer[j + 0] = Table[(x >> 18) & 63]; + Buffer[j + 1] = Table[(x >> 12) & 63]; + Buffer[j + 2] = Table[(x >> 6) & 63]; + Buffer[j + 3] = Table[x & 63]; + } + if (i + 1 == Bytes.size()) { + uint32_t x = ((unsigned char)Bytes[i] << 16); + Buffer[j + 0] = Table[(x >> 18) & 63]; + Buffer[j + 1] = Table[(x >> 12) & 63]; + Buffer[j + 2] = '='; + Buffer[j + 3] = '='; + } else if (i + 2 == Bytes.size()) { + uint32_t x = + ((unsigned char)Bytes[i] << 16) | ((unsigned char)Bytes[i + 1] << 8); + Buffer[j + 0] = Table[(x >> 18) & 63]; + Buffer[j + 1] = Table[(x >> 12) & 63]; + Buffer[j + 2] = Table[(x >> 6) & 63]; + Buffer[j + 3] = '='; + } + return Buffer; +} + +} // end namespace llvm + +#endif diff --git a/llvm/include/llvm/Support/BinaryStreamArray.h b/llvm/include/llvm/Support/BinaryStreamArray.h index 1634983d26ce0..3ba65c07cfe20 100644 --- a/llvm/include/llvm/Support/BinaryStreamArray.h +++ b/llvm/include/llvm/Support/BinaryStreamArray.h @@ -11,6 +11,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/iterator.h" +#include "llvm/Support/Alignment.h" #include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Error.h" #include <cassert> diff --git a/llvm/include/llvm/Support/BinaryStreamReader.h b/llvm/include/llvm/Support/BinaryStreamReader.h index b7d61c02667b3..b611707807c0a 100644 --- a/llvm/include/llvm/Support/BinaryStreamReader.h +++ b/llvm/include/llvm/Support/BinaryStreamReader.h @@ -11,6 +11,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Alignment.h" #include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/ConvertUTF.h" @@ -89,7 +90,7 @@ public: template <typename T> Error readEnum(T &Dest) { static_assert(std::is_enum<T>::value, "Cannot call readEnum with non-enum value!"); - typename std::underlying_type<T>::type N; + std::underlying_type_t<T> N; if (auto EC = readInteger(N)) return EC; Dest = static_cast<T>(N); diff --git a/llvm/include/llvm/Support/BinaryStreamWriter.h b/llvm/include/llvm/Support/BinaryStreamWriter.h index 86d2389d91820..ceba792e6b266 100644 --- a/llvm/include/llvm/Support/BinaryStreamWriter.h +++ b/llvm/include/llvm/Support/BinaryStreamWriter.h @@ -75,7 +75,7 @@ public: static_assert(std::is_enum<T>::value, "Cannot call writeEnum with non-Enum type"); - using U = typename std::underlying_type<T>::type; + using U = std::underlying_type_t<T>; return writeInteger<U>(static_cast<U>(Num)); } diff --git a/llvm/include/llvm/Support/BranchProbability.h b/llvm/include/llvm/Support/BranchProbability.h index cd9d369b4f4e6..6c7ad1fe2a52c 100644 --- a/llvm/include/llvm/Support/BranchProbability.h +++ b/llvm/include/llvm/Support/BranchProbability.h @@ -32,8 +32,8 @@ class BranchProbability { uint32_t N; // Denominator, which is a constant value. - static const uint32_t D = 1u << 31; - static const uint32_t UnknownN = UINT32_MAX; + static constexpr uint32_t D = 1u << 31; + static constexpr uint32_t UnknownN = UINT32_MAX; // Construct a BranchProbability with only numerator assuming the denominator // is 1<<31. For internal use only. diff --git a/llvm/include/llvm/Support/CFGDiff.h b/llvm/include/llvm/Support/CFGDiff.h new file mode 100644 index 0000000000000..94734ce70e02c --- /dev/null +++ b/llvm/include/llvm/Support/CFGDiff.h @@ -0,0 +1,250 @@ +//===- CFGDiff.h - Define a CFG snapshot. -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines specializations of GraphTraits that allows generic +// algorithms to see a different snapshot of a CFG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_CFGDIFF_H +#define LLVM_SUPPORT_CFGDIFF_H + +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/CFGUpdate.h" +#include "llvm/Support/type_traits.h" +#include <cassert> +#include <cstddef> +#include <iterator> + +// Two booleans are used to define orders in graphs: +// InverseGraph defines when we need to reverse the whole graph and is as such +// also equivalent to applying updates in reverse. +// InverseEdge defines whether we want to change the edges direction. E.g., for +// a non-inversed graph, the children are naturally the successors when +// InverseEdge is false and the predecessors when InverseEdge is true. + +// We define two base clases that call into GraphDiff, one for successors +// (CFGSuccessors), where InverseEdge is false, and one for predecessors +// (CFGPredecessors), where InverseEdge is true. +// FIXME: Further refactoring may merge the two base classes into a single one +// templated / parametrized on using succ_iterator/pred_iterator and false/true +// for the InverseEdge. + +// CFGViewChildren and CFGViewPredecessors, both can be parametrized to +// consider the graph inverted or not (i.e. InverseGraph). Successors +// implicitly has InverseEdge = false and Predecessors implicitly has +// InverseEdge = true (see calls to GraphDiff methods in there). The GraphTraits +// instantiations that follow define the value of InverseGraph. + +// GraphTraits instantiations: +// - GraphDiff<BasicBlock *> is equivalent to InverseGraph = false +// - GraphDiff<Inverse<BasicBlock *>> is equivalent to InverseGraph = true +// - second pair item is BasicBlock *, then InverseEdge = false (so it inherits +// from CFGViewChildren). +// - second pair item is Inverse<BasicBlock *>, then InverseEdge = true (so it +// inherits from CFGViewPredecessors). + +// The 4 GraphTraits are as follows: +// 1. std::pair<const GraphDiff<BasicBlock *> *, BasicBlock *>> : +// CFGViewChildren<false> +// Regular CFG, children means successors, InverseGraph = false, +// InverseEdge = false. +// 2. std::pair<const GraphDiff<Inverse<BasicBlock *>> *, BasicBlock *>> : +// CFGViewChildren<true> +// Reverse the graph, get successors but reverse-apply updates, +// InverseGraph = true, InverseEdge = false. +// 3. std::pair<const GraphDiff<BasicBlock *> *, Inverse<BasicBlock *>>> : +// CFGViewPredecessors<false> +// Regular CFG, reverse edges, so children mean predecessors, +// InverseGraph = false, InverseEdge = true. +// 4. std::pair<const GraphDiff<Inverse<BasicBlock *>> *, Inverse<BasicBlock *>> +// : CFGViewPredecessors<true> +// Reverse the graph and the edges, InverseGraph = true, InverseEdge = true. + +namespace llvm { + +// GraphDiff defines a CFG snapshot: given a set of Update<NodePtr>, provide +// utilities to skip edges marked as deleted and return a set of edges marked as +// newly inserted. The current diff treats the CFG as a graph rather than a +// multigraph. Added edges are pruned to be unique, and deleted edges will +// remove all existing edges between two blocks. +template <typename NodePtr, bool InverseGraph = false> class GraphDiff { + using UpdateMapType = SmallDenseMap<NodePtr, SmallVector<NodePtr, 2>>; + struct EdgesInsertedDeleted { + UpdateMapType Succ; + UpdateMapType Pred; + }; + // Store Deleted edges on position 0, and Inserted edges on position 1. + EdgesInsertedDeleted Edges[2]; + // By default, it is assumed that, given a CFG and a set of updates, we wish + // to apply these updates as given. If UpdatedAreReverseApplied is set, the + // updates will be applied in reverse: deleted edges are considered re-added + // and inserted edges are considered deleted when returning children. + bool UpdatedAreReverseApplied; + // Using a singleton empty vector for all node requests with no + // children. + SmallVector<NodePtr, 0> Empty; + + // Keep the list of legalized updates for a deterministic order of updates + // when using a GraphDiff for incremental updates in the DominatorTree. + // The list is kept in reverse to allow popping from end. + SmallVector<cfg::Update<NodePtr>, 4> LegalizedUpdates; + + void printMap(raw_ostream &OS, const UpdateMapType &M) const { + for (auto Pair : M) + for (auto Child : Pair.second) { + OS << "("; + Pair.first->printAsOperand(OS, false); + OS << ", "; + Child->printAsOperand(OS, false); + OS << ") "; + } + OS << "\n"; + } + +public: + GraphDiff() : UpdatedAreReverseApplied(false) {} + GraphDiff(ArrayRef<cfg::Update<NodePtr>> Updates, + bool ReverseApplyUpdates = false) { + cfg::LegalizeUpdates<NodePtr>(Updates, LegalizedUpdates, InverseGraph, + /*ReverseResultOrder=*/true); + // The legalized updates are stored in reverse so we can pop_back when doing + // incremental updates. + for (auto U : LegalizedUpdates) { + unsigned IsInsert = + (U.getKind() == cfg::UpdateKind::Insert) == !ReverseApplyUpdates; + Edges[IsInsert].Succ[U.getFrom()].push_back(U.getTo()); + Edges[IsInsert].Pred[U.getTo()].push_back(U.getFrom()); + } + UpdatedAreReverseApplied = ReverseApplyUpdates; + } + + auto getLegalizedUpdates() const { + return make_range(LegalizedUpdates.begin(), LegalizedUpdates.end()); + } + + unsigned getNumLegalizedUpdates() const { return LegalizedUpdates.size(); } + + cfg::Update<NodePtr> popUpdateForIncrementalUpdates() { + assert(!LegalizedUpdates.empty() && "No updates to apply!"); + auto U = LegalizedUpdates.pop_back_val(); + unsigned IsInsert = + (U.getKind() == cfg::UpdateKind::Insert) == !UpdatedAreReverseApplied; + auto &SuccList = Edges[IsInsert].Succ[U.getFrom()]; + assert(SuccList.back() == U.getTo()); + SuccList.pop_back(); + if (SuccList.empty()) + Edges[IsInsert].Succ.erase(U.getFrom()); + + auto &PredList = Edges[IsInsert].Pred[U.getTo()]; + assert(PredList.back() == U.getFrom()); + PredList.pop_back(); + if (PredList.empty()) + Edges[IsInsert].Pred.erase(U.getTo()); + return U; + } + + bool ignoreChild(const NodePtr BB, NodePtr EdgeEnd, bool InverseEdge) const { + // Used to filter nullptr in clang. + if (EdgeEnd == nullptr) + return true; + auto &DeleteChildren = + (InverseEdge != InverseGraph) ? Edges[0].Pred : Edges[0].Succ; + auto It = DeleteChildren.find(BB); + if (It == DeleteChildren.end()) + return false; + auto &EdgesForBB = It->second; + return llvm::find(EdgesForBB, EdgeEnd) != EdgesForBB.end(); + } + + iterator_range<typename SmallVectorImpl<NodePtr>::const_iterator> + getAddedChildren(const NodePtr BB, bool InverseEdge) const { + auto &InsertChildren = + (InverseEdge != InverseGraph) ? Edges[1].Pred : Edges[1].Succ; + auto It = InsertChildren.find(BB); + if (It == InsertChildren.end()) + return make_range(Empty.begin(), Empty.end()); + return make_range(It->second.begin(), It->second.end()); + } + + void print(raw_ostream &OS) const { + OS << "===== GraphDiff: CFG edge changes to create a CFG snapshot. \n" + "===== (Note: notion of children/inverse_children depends on " + "the direction of edges and the graph.)\n"; + OS << "Children to insert:\n\t"; + printMap(OS, Edges[1].Succ); + OS << "Children to delete:\n\t"; + printMap(OS, Edges[0].Succ); + OS << "Inverse_children to insert:\n\t"; + printMap(OS, Edges[1].Pred); + OS << "Inverse_children to delete:\n\t"; + printMap(OS, Edges[0].Pred); + OS << "\n"; + } + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + LLVM_DUMP_METHOD void dump() const { print(dbgs()); } +#endif +}; + +template <typename GraphT, bool InverseGraph = false, bool InverseEdge = false, + typename GT = GraphTraits<GraphT>> +struct CFGViewChildren { + using DataRef = const GraphDiff<typename GT::NodeRef, InverseGraph> *; + using NodeRef = std::pair<DataRef, typename GT::NodeRef>; + + template<typename Range> + static auto makeChildRange(Range &&R, DataRef DR) { + using Iter = WrappedPairNodeDataIterator<decltype(std::forward<Range>(R).begin()), NodeRef, DataRef>; + return make_range(Iter(R.begin(), DR), Iter(R.end(), DR)); + } + + static auto children(NodeRef N) { + + // filter iterator init: + auto R = make_range(GT::child_begin(N.second), GT::child_end(N.second)); + // This lambda is copied into the iterators and persists to callers, ensure + // captures are by value or otherwise have sufficient lifetime. + auto First = make_filter_range(makeChildRange(R, N.first), [N](NodeRef C) { + return !C.first->ignoreChild(N.second, C.second, InverseEdge); + }); + + // new inserts iterator init: + auto InsertVec = N.first->getAddedChildren(N.second, InverseEdge); + auto Second = makeChildRange(InsertVec, N.first); + + auto CR = concat<NodeRef>(First, Second); + + // concat_range contains references to other ranges, returning it would + // leave those references dangling - the iterators contain + // other iterators by value so they're safe to return. + return make_range(CR.begin(), CR.end()); + } + + static auto child_begin(NodeRef N) { + return children(N).begin(); + } + + static auto child_end(NodeRef N) { + return children(N).end(); + } + + using ChildIteratorType = decltype(child_end(std::declval<NodeRef>())); +}; + +template <typename T, bool B> +struct GraphTraits<std::pair<const GraphDiff<T, B> *, T>> + : CFGViewChildren<T, B> {}; +template <typename T, bool B> +struct GraphTraits<std::pair<const GraphDiff<T, B> *, Inverse<T>>> + : CFGViewChildren<Inverse<T>, B, true> {}; +} // end namespace llvm + +#endif // LLVM_SUPPORT_CFGDIFF_H diff --git a/llvm/include/llvm/Support/CFGUpdate.h b/llvm/include/llvm/Support/CFGUpdate.h index eeaf5d0a21acd..af4cd6ed1f1df 100644 --- a/llvm/include/llvm/Support/CFGUpdate.h +++ b/llvm/include/llvm/Support/CFGUpdate.h @@ -62,7 +62,7 @@ public: template <typename NodePtr> void LegalizeUpdates(ArrayRef<Update<NodePtr>> AllUpdates, SmallVectorImpl<Update<NodePtr>> &Result, - bool InverseGraph) { + bool InverseGraph, bool ReverseResultOrder = false) { // 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 @@ -104,11 +104,11 @@ void LegalizeUpdates(ArrayRef<Update<NodePtr>> AllUpdates, Operations[{U.getTo(), U.getFrom()}] = int(i); } - llvm::sort(Result, - [&Operations](const Update<NodePtr> &A, const Update<NodePtr> &B) { - return Operations[{A.getFrom(), A.getTo()}] > - Operations[{B.getFrom(), B.getTo()}]; - }); + llvm::sort(Result, [&](const Update<NodePtr> &A, const Update<NodePtr> &B) { + const auto &OpA = Operations[{A.getFrom(), A.getTo()}]; + const auto &OpB = Operations[{B.getFrom(), B.getTo()}]; + return ReverseResultOrder ? OpA < OpB : OpA > OpB; + }); } } // end namespace cfg diff --git a/llvm/include/llvm/Support/CachePruning.h b/llvm/include/llvm/Support/CachePruning.h index a72a86439f6a5..10d6372f9163c 100644 --- a/llvm/include/llvm/Support/CachePruning.h +++ b/llvm/include/llvm/Support/CachePruning.h @@ -14,12 +14,13 @@ #ifndef LLVM_SUPPORT_CACHE_PRUNING_H #define LLVM_SUPPORT_CACHE_PRUNING_H -#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Optional.h" #include <chrono> namespace llvm { template <typename T> class Expected; +class StringRef; /// Policy for the pruneCache() function. A default constructed /// CachePruningPolicy provides a reasonable default policy. diff --git a/llvm/include/llvm/Support/Casting.h b/llvm/include/llvm/Support/Casting.h index 46bdedb04cfe6..d6f7793d5df01 100644 --- a/llvm/include/llvm/Support/Casting.h +++ b/llvm/include/llvm/Support/Casting.h @@ -61,8 +61,7 @@ struct isa_impl { /// 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> { +struct isa_impl<To, From, std::enable_if_t<std::is_base_of<To, From>::value>> { static inline bool doit(const From &) { return true; } }; @@ -133,24 +132,30 @@ struct isa_impl_wrap<To, FromTy, FromTy> { } }; -// isa<X> - Return true if the parameter to the template is an instance of the -// template type argument. Used like this: +// isa<X> - Return true if the parameter to the template is an instance of one +// of the template type arguments. Used like this: // // if (isa<Type>(myVal)) { ... } +// if (isa<Type0, Type1, Type2>(myVal)) { ... } // template <class X, class Y> LLVM_NODISCARD inline bool isa(const Y &Val) { return isa_impl_wrap<X, const Y, typename simplify_type<const Y>::SimpleType>::doit(Val); } +template <typename First, typename Second, typename... Rest, typename Y> +LLVM_NODISCARD inline bool isa(const Y &Val) { + return isa<First>(Val) || isa<Second, Rest...>(Val); +} + // isa_and_nonnull<X> - Functionally identical to isa, except that a null value // is accepted. // -template <class X, class Y> +template <typename... X, class Y> LLVM_NODISCARD inline bool isa_and_nonnull(const Y &Val) { if (!Val) return false; - return isa<X>(Val); + return isa<X...>(Val); } //===----------------------------------------------------------------------===// @@ -184,7 +189,7 @@ template <class To, class From> struct cast_retty_impl<To, std::unique_ptr<From>> { private: using PointerType = typename cast_retty_impl<To, From *>::ret_type; - using ResultType = typename std::remove_pointer<PointerType>::type; + using ResultType = std::remove_pointer_t<PointerType>; public: using ret_type = std::unique_ptr<ResultType>; @@ -244,8 +249,8 @@ template <class X> struct is_simple_type { // cast<Instruction>(myVal)->getParent() // template <class X, class Y> -inline typename std::enable_if<!is_simple_type<Y>::value, - typename cast_retty<X, const Y>::ret_type>::type +inline std::enable_if_t<!is_simple_type<Y>::value, + typename cast_retty<X, const Y>::ret_type> cast(const Y &Val) { assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!"); return cast_convert_val< @@ -280,10 +285,9 @@ cast(std::unique_ptr<Y> &&Val) { // accepted. // template <class X, class Y> -LLVM_NODISCARD inline - typename std::enable_if<!is_simple_type<Y>::value, - typename cast_retty<X, const Y>::ret_type>::type - cast_or_null(const Y &Val) { +LLVM_NODISCARD inline std::enable_if_t< + !is_simple_type<Y>::value, typename cast_retty<X, const Y>::ret_type> +cast_or_null(const Y &Val) { if (!Val) return nullptr; assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!"); @@ -291,10 +295,9 @@ LLVM_NODISCARD inline } template <class X, class Y> -LLVM_NODISCARD inline - typename std::enable_if<!is_simple_type<Y>::value, - typename cast_retty<X, Y>::ret_type>::type - cast_or_null(Y &Val) { +LLVM_NODISCARD inline std::enable_if_t<!is_simple_type<Y>::value, + typename cast_retty<X, Y>::ret_type> +cast_or_null(Y &Val) { if (!Val) return nullptr; assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!"); @@ -326,10 +329,9 @@ cast_or_null(std::unique_ptr<Y> &&Val) { // template <class X, class Y> -LLVM_NODISCARD inline - typename std::enable_if<!is_simple_type<Y>::value, - typename cast_retty<X, const Y>::ret_type>::type - dyn_cast(const Y &Val) { +LLVM_NODISCARD inline std::enable_if_t< + !is_simple_type<Y>::value, typename cast_retty<X, const Y>::ret_type> +dyn_cast(const Y &Val) { return isa<X>(Val) ? cast<X>(Val) : nullptr; } @@ -347,18 +349,16 @@ LLVM_NODISCARD inline typename cast_retty<X, Y *>::ret_type dyn_cast(Y *Val) { // value is accepted. // template <class X, class Y> -LLVM_NODISCARD inline - typename std::enable_if<!is_simple_type<Y>::value, - typename cast_retty<X, const Y>::ret_type>::type - dyn_cast_or_null(const Y &Val) { +LLVM_NODISCARD inline std::enable_if_t< + !is_simple_type<Y>::value, typename cast_retty<X, const Y>::ret_type> +dyn_cast_or_null(const Y &Val) { return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr; } template <class X, class Y> -LLVM_NODISCARD inline - typename std::enable_if<!is_simple_type<Y>::value, - typename cast_retty<X, Y>::ret_type>::type - dyn_cast_or_null(Y &Val) { +LLVM_NODISCARD inline std::enable_if_t<!is_simple_type<Y>::value, + typename cast_retty<X, Y>::ret_type> +dyn_cast_or_null(Y &Val) { return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr; } @@ -382,8 +382,7 @@ LLVM_NODISCARD inline auto unique_dyn_cast(std::unique_ptr<Y> &Val) } template <class X, class Y> -LLVM_NODISCARD inline auto unique_dyn_cast(std::unique_ptr<Y> &&Val) - -> decltype(cast<X>(Val)) { +LLVM_NODISCARD inline auto unique_dyn_cast(std::unique_ptr<Y> &&Val) { return unique_dyn_cast<X, Y>(Val); } @@ -398,8 +397,7 @@ LLVM_NODISCARD inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &Val) } template <class X, class Y> -LLVM_NODISCARD inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &&Val) - -> decltype(cast<X>(Val)) { +LLVM_NODISCARD inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &&Val) { return unique_dyn_cast_or_null<X, Y>(Val); } diff --git a/llvm/include/llvm/Support/CheckedArithmetic.h b/llvm/include/llvm/Support/CheckedArithmetic.h index 8a50e3d5ddf6f..035e4533322cb 100644 --- a/llvm/include/llvm/Support/CheckedArithmetic.h +++ b/llvm/include/llvm/Support/CheckedArithmetic.h @@ -25,8 +25,8 @@ namespace { /// \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 +std::enable_if_t<std::is_integral<T>::value && sizeof(T) * 8 <= 64, + llvm::Optional<T>> 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); @@ -44,7 +44,7 @@ namespace llvm { /// \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 +std::enable_if_t<std::is_signed<T>::value, llvm::Optional<T>> checkedAdd(T LHS, T RHS) { return checkedOp(LHS, RHS, &llvm::APInt::sadd_ov); } @@ -53,7 +53,7 @@ checkedAdd(T LHS, T 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 +std::enable_if_t<std::is_signed<T>::value, llvm::Optional<T>> checkedSub(T LHS, T RHS) { return checkedOp(LHS, RHS, &llvm::APInt::ssub_ov); } @@ -62,7 +62,7 @@ checkedSub(T LHS, T 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 +std::enable_if_t<std::is_signed<T>::value, llvm::Optional<T>> checkedMul(T LHS, T RHS) { return checkedOp(LHS, RHS, &llvm::APInt::smul_ov); } @@ -71,7 +71,7 @@ checkedMul(T LHS, T RHS) { /// \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 +std::enable_if_t<std::is_signed<T>::value, llvm::Optional<T>> checkedMulAdd(T A, T B, T C) { if (auto Product = checkedMul(A, B)) return checkedAdd(*Product, C); @@ -82,7 +82,7 @@ checkedMulAdd(T A, T B, T C) { /// \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 +std::enable_if_t<std::is_unsigned<T>::value, llvm::Optional<T>> checkedAddUnsigned(T LHS, T RHS) { return checkedOp(LHS, RHS, &llvm::APInt::uadd_ov, /*Signed=*/false); } @@ -91,7 +91,7 @@ checkedAddUnsigned(T LHS, T 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 +std::enable_if_t<std::is_unsigned<T>::value, llvm::Optional<T>> checkedMulUnsigned(T LHS, T RHS) { return checkedOp(LHS, RHS, &llvm::APInt::umul_ov, /*Signed=*/false); } @@ -100,7 +100,7 @@ checkedMulUnsigned(T LHS, T RHS) { /// \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 +std::enable_if_t<std::is_unsigned<T>::value, llvm::Optional<T>> checkedMulAddUnsigned(T A, T B, T C) { if (auto Product = checkedMulUnsigned(A, B)) return checkedAddUnsigned(*Product, C); diff --git a/llvm/include/llvm/Support/Chrono.h b/llvm/include/llvm/Support/Chrono.h index 334ab60835a44..098512dce783b 100644 --- a/llvm/include/llvm/Support/Chrono.h +++ b/llvm/include/llvm/Support/Chrono.h @@ -112,8 +112,8 @@ template <typename Rep, typename Period> struct format_provider<std::chrono::duration<Rep, Period>> { private: typedef std::chrono::duration<Rep, Period> Dur; - typedef typename std::conditional< - std::chrono::treat_as_floating_point<Rep>::value, double, intmax_t>::type + typedef std::conditional_t<std::chrono::treat_as_floating_point<Rep>::value, + double, intmax_t> InternalRep; template <typename AsPeriod> static InternalRep getAs(const Dur &D) { diff --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h index 05374e34aa7d4..466945e40a9ce 100644 --- a/llvm/include/llvm/Support/CommandLine.h +++ b/llvm/include/llvm/Support/CommandLine.h @@ -45,7 +45,6 @@ namespace llvm { class StringSaver; -class raw_ostream; /// cl Namespace - This namespace contains all of the command line option /// processing machinery. It is intentionally a short name to make qualified @@ -488,14 +487,13 @@ struct callback_traits : public callback_traits<decltype(&F::operator())> {}; template <typename R, typename C, typename... Args> struct callback_traits<R (C::*)(Args...) const> { using result_type = R; - using arg_type = typename std::tuple_element<0, std::tuple<Args...>>::type; + using arg_type = std::tuple_element_t<0, std::tuple<Args...>>; static_assert(sizeof...(Args) == 1, "callback function must have one and only one parameter"); static_assert(std::is_same<result_type, void>::value, "callback return type must be void"); - static_assert( - std::is_lvalue_reference<arg_type>::value && - std::is_const<typename std::remove_reference<arg_type>::type>::value, - "callback arg_type must be a const lvalue reference"); + static_assert(std::is_lvalue_reference<arg_type>::value && + std::is_const<std::remove_reference_t<arg_type>>::value, + "callback arg_type must be a const lvalue reference"); }; } // namespace detail @@ -1453,16 +1451,16 @@ class opt : public Option, } } - template <class T, class = typename std::enable_if< - std::is_assignable<T&, T>::value>::type> + template <class T, + class = std::enable_if_t<std::is_assignable<T &, T>::value>> void setDefaultImpl() { const OptionValue<DataType> &V = this->getDefault(); if (V.hasValue()) this->setValue(V.getValue()); } - template <class T, class = typename std::enable_if< - !std::is_assignable<T&, T>::value>::type> + template <class T, + class = std::enable_if_t<!std::is_assignable<T &, T>::value>> void setDefaultImpl(...) {} void setDefault() override { setDefaultImpl<DataType>(); } @@ -1607,8 +1605,8 @@ public: reference front() { return Storage.front(); } const_reference front() const { return Storage.front(); } - operator std::vector<DataType>&() { return Storage; } - operator ArrayRef<DataType>() { return Storage; } + operator std::vector<DataType> &() { return Storage; } + operator ArrayRef<DataType>() const { return Storage; } std::vector<DataType> *operator&() { return &Storage; } const std::vector<DataType> *operator&() const { return &Storage; } @@ -2028,6 +2026,13 @@ void TokenizeWindowsCommandLine(StringRef Source, StringSaver &Saver, SmallVectorImpl<const char *> &NewArgv, bool MarkEOLs = false); +/// Tokenizes a Windows command line while attempting to avoid copies. If no +/// quoting or escaping was used, this produces substrings of the original +/// string. If a token requires unquoting, it will be allocated with the +/// StringSaver. +void TokenizeWindowsCommandLineNoCopy(StringRef Source, StringSaver &Saver, + SmallVectorImpl<StringRef> &NewArgv); + /// String tokenization function type. Should be compatible with either /// Windows or Unix command line tokenizers. using TokenizerCallback = void (*)(StringRef Source, StringSaver &Saver, diff --git a/llvm/include/llvm/Support/Compiler.h b/llvm/include/llvm/Support/Compiler.h index 6f6f65cad6f5b..80ea76240d6cf 100644 --- a/llvm/include/llvm/Support/Compiler.h +++ b/llvm/include/llvm/Support/Compiler.h @@ -95,7 +95,8 @@ /// 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. +/// and MSVC implemented this later than everything else. This appears to be +/// corrected in MSVC 2019 but not MSVC 2017. #if __has_feature(cxx_rvalue_references) || LLVM_GNUC_PREREQ(4, 8, 1) #define LLVM_HAS_RVALUE_REFERENCE_THIS 1 #else @@ -288,6 +289,22 @@ #define LLVM_REQUIRE_CONSTANT_INITIALIZATION #endif +/// LLVM_GSL_OWNER - Apply this to owning classes like SmallVector to enable +/// lifetime warnings. +#if LLVM_HAS_CPP_ATTRIBUTE(gsl::Owner) +#define LLVM_GSL_OWNER [[gsl::Owner]] +#else +#define LLVM_GSL_OWNER +#endif + +/// LLVM_GSL_POINTER - Apply this to non-owning classes like +/// StringRef to enable lifetime warnings. +#if LLVM_HAS_CPP_ATTRIBUTE(gsl::Pointer) +#define LLVM_GSL_POINTER [[gsl::Pointer]] +#else +#define LLVM_GSL_POINTER +#endif + /// LLVM_EXTENSION - Support compilers where we have a keyword to suppress /// pedantic diagnostics. #ifdef __GNUC__ @@ -356,7 +373,6 @@ #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) -// As of today, clang does not support __builtin_assume_aligned. # define LLVM_ASSUME_ALIGNED(p, a) \ (((uintptr_t(p) % (a)) == 0) ? (p) : (LLVM_BUILTIN_UNREACHABLE, (p))) #else @@ -542,48 +558,4 @@ void AnnotateIgnoreWritesEnd(const char *file, int line); #define LLVM_ENABLE_EXCEPTIONS 1 #endif -#ifdef __cplusplus -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 -#ifdef __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 -#ifdef __cpp_sized_deallocation - , - Size -#endif -#ifdef __cpp_aligned_new - , - std::align_val_t(Alignment) -#endif - ); -} - -} // End namespace llvm - -#endif // __cplusplus #endif diff --git a/llvm/include/llvm/Support/CrashRecoveryContext.h b/llvm/include/llvm/Support/CrashRecoveryContext.h index 9522c4742244e..61a1bd405a4d4 100644 --- a/llvm/include/llvm/Support/CrashRecoveryContext.h +++ b/llvm/include/llvm/Support/CrashRecoveryContext.h @@ -99,7 +99,8 @@ public: /// Explicitly trigger a crash recovery in the current process, and /// return failure from RunSafely(). This function does not return. - void HandleCrash(); + LLVM_ATTRIBUTE_NORETURN + void HandleExit(int RetCode); /// In case of a crash, this is the crash identifier. int RetCode = 0; diff --git a/llvm/include/llvm/Support/DataExtractor.h b/llvm/include/llvm/Support/DataExtractor.h index 0be478811b22f..f9335c161563c 100644 --- a/llvm/include/llvm/Support/DataExtractor.h +++ b/llvm/include/llvm/Support/DataExtractor.h @@ -105,19 +105,32 @@ public: /// updated with the offset of the byte that follows the NULL /// terminator byte. /// - /// @param[in,out] offset_ptr + /// @param[in,out] OffsetPtr /// A pointer to an offset within the data that will be advanced /// by the appropriate number of bytes if the value is extracted /// correctly. If the offset is out of bounds or there are not /// enough bytes to extract this value, the offset will be left /// unmodified. /// + /// @param[in,out] Err + /// A pointer to an Error object. Upon return the Error object is set to + /// indicate the result (success/failure) of the function. If the Error + /// object is already set when calling this function, no extraction is + /// performed. + /// /// @return /// A pointer to the C string value in the data. If the offset /// pointed to by \a offset_ptr is out of bounds, or if the /// offset plus the length of the C string is out of bounds, /// NULL will be returned. - const char *getCStr(uint64_t *offset_ptr) const; + const char *getCStr(uint64_t *OffsetPtr, Error *Err = nullptr) const { + return getCStrRef(OffsetPtr, Err).data(); + } + + /// Extract a C string from the location given by the cursor. In case of an + /// extraction error, or if the cursor is already in an error state, a + /// nullptr is returned. + const char *getCStr(Cursor &C) const { return getCStrRef(C).data(); } /// Extract a C string from \a *offset_ptr. /// @@ -127,19 +140,102 @@ public: /// updated with the offset of the byte that follows the NULL /// terminator byte. /// - /// \param[in,out] offset_ptr + /// \param[in,out] OffsetPtr /// A pointer to an offset within the data that will be advanced /// by the appropriate number of bytes if the value is extracted /// correctly. If the offset is out of bounds or there are not /// enough bytes to extract this value, the offset will be left /// unmodified. /// + /// @param[in,out] Err + /// A pointer to an Error object. Upon return the Error object is set to + /// indicate the result (success/failure) of the function. If the Error + /// object is already set when calling this function, no extraction is + /// performed. + /// /// \return /// A StringRef for the C string value in the data. If the offset /// pointed to by \a offset_ptr is out of bounds, or if the /// offset plus the length of the C string is out of bounds, /// a default-initialized StringRef will be returned. - StringRef getCStrRef(uint64_t *offset_ptr) const; + StringRef getCStrRef(uint64_t *OffsetPtr, Error *Err = nullptr) const; + + /// Extract a C string (as a StringRef) from the location given by the cursor. + /// In case of an extraction error, or if the cursor is already in an error + /// state, a default-initialized StringRef is returned. + StringRef getCStrRef(Cursor &C) const { + return getCStrRef(&C.Offset, &C.Err); + } + + /// Extract a fixed length string from \a *OffsetPtr and consume \a Length + /// bytes. + /// + /// Returns a StringRef for the string from the data at the offset + /// pointed to by \a OffsetPtr. A fixed length C string will be extracted + /// and the \a OffsetPtr will be advanced by \a Length bytes. + /// + /// \param[in,out] OffsetPtr + /// A pointer to an offset within the data that will be advanced + /// by the appropriate number of bytes if the value is extracted + /// correctly. If the offset is out of bounds or there are not + /// enough bytes to extract this value, the offset will be left + /// unmodified. + /// + /// \param[in] Length + /// The length of the fixed length string to extract. If there are not + /// enough bytes in the data to extract the full string, the offset will + /// be left unmodified. + /// + /// \param[in] TrimChars + /// A set of characters to trim from the end of the string. Fixed length + /// strings are commonly either NULL terminated by one or more zero + /// bytes. Some clients have one or more spaces at the end of the string, + /// but a good default is to trim the NULL characters. + /// + /// \return + /// A StringRef for the C string value in the data. If the offset + /// pointed to by \a OffsetPtr is out of bounds, or if the + /// offset plus the length of the C string is out of bounds, + /// a default-initialized StringRef will be returned. + StringRef getFixedLengthString(uint64_t *OffsetPtr, + uint64_t Length, StringRef TrimChars = {"\0", 1}) const; + + /// Extract a fixed number of bytes from the specified offset. + /// + /// Returns a StringRef for the bytes from the data at the offset + /// pointed to by \a OffsetPtr. A fixed length C string will be extracted + /// and the \a OffsetPtr will be advanced by \a Length bytes. + /// + /// \param[in,out] OffsetPtr + /// A pointer to an offset within the data that will be advanced + /// by the appropriate number of bytes if the value is extracted + /// correctly. If the offset is out of bounds or there are not + /// enough bytes to extract this value, the offset will be left + /// unmodified. + /// + /// \param[in] Length + /// The number of bytes to extract. If there are not enough bytes in the + /// data to extract all of the bytes, the offset will be left unmodified. + /// + /// @param[in,out] Err + /// A pointer to an Error object. Upon return the Error object is set to + /// indicate the result (success/failure) of the function. If the Error + /// object is already set when calling this function, no extraction is + /// performed. + /// + /// \return + /// A StringRef for the extracted bytes. If the offset pointed to by + /// \a OffsetPtr is out of bounds, or if the offset plus the length + /// is out of bounds, a default-initialized StringRef will be returned. + StringRef getBytes(uint64_t *OffsetPtr, uint64_t Length, + Error *Err = nullptr) const; + + /// Extract a fixed number of bytes from the location given by the cursor. In + /// case of an extraction error, or if the cursor is already in an error + /// state, a default-initialized StringRef is returned. + StringRef getBytes(Cursor &C, uint64_t Length) { + return getBytes(&C.Offset, Length, &C.Err); + } /// Extract an unsigned integer of size \a byte_size from \a /// *offset_ptr. @@ -365,15 +461,26 @@ public: /// \a offset_ptr, construct a uint32_t from them and update the offset /// on success. /// - /// @param[in,out] offset_ptr + /// @param[in,out] OffsetPtr /// A pointer to an offset within the data that will be advanced /// by the 3 bytes if the value is extracted correctly. If the offset /// is out of bounds or there are not enough bytes to extract this value, /// the offset will be left unmodified. /// + /// @param[in,out] Err + /// A pointer to an Error object. Upon return the Error object is set to + /// indicate the result (success/failure) of the function. If the Error + /// object is already set when calling this function, no extraction is + /// performed. + /// /// @return /// The extracted 24-bit value represented in a uint32_t. - uint32_t getU24(uint64_t *offset_ptr) const; + uint32_t getU24(uint64_t *OffsetPtr, Error *Err = nullptr) const; + + /// Extract a single 24-bit unsigned value from the location given by the + /// cursor. In case of an extraction error, or if the cursor is already in an + /// error state, zero is returned. + uint32_t getU24(Cursor &C) const { return getU24(&C.Offset, &C.Err); } /// Extract a uint32_t value from \a *offset_ptr. /// @@ -486,16 +593,27 @@ public: /// pointed to by \a offset_ptr will be updated with the offset of /// the byte following the last extracted byte. /// - /// @param[in,out] offset_ptr + /// @param[in,out] OffsetPtr /// A pointer to an offset within the data that will be advanced /// by the appropriate number of bytes if the value is extracted /// correctly. If the offset is out of bounds or there are not /// enough bytes to extract this value, the offset will be left /// unmodified. /// + /// @param[in,out] Err + /// A pointer to an Error object. Upon return the Error object is set to + /// indicate the result (success/failure) of the function. If the Error + /// object is already set when calling this function, no extraction is + /// performed. + /// /// @return /// The extracted signed integer value. - int64_t getSLEB128(uint64_t *offset_ptr) const; + int64_t getSLEB128(uint64_t *OffsetPtr, Error *Err = nullptr) const; + + /// Extract an signed LEB128 value from the location given by the cursor. + /// In case of an extraction error, or if the cursor is already in an error + /// state, zero is returned. + int64_t getSLEB128(Cursor &C) const { return getSLEB128(&C.Offset, &C.Err); } /// Extract a unsigned LEB128 value from \a *offset_ptr. /// @@ -521,7 +639,7 @@ public: /// The extracted unsigned integer value. uint64_t getULEB128(uint64_t *offset_ptr, llvm::Error *Err = nullptr) const; - /// Extract an unsigned ULEB128 value from the location given by the cursor. + /// Extract an unsigned LEB128 value from the location given by the cursor. /// In case of an extraction error, or if the cursor is already in an error /// state, zero is returned. uint64_t getULEB128(Cursor &C) const { return getULEB128(&C.Offset, &C.Err); } @@ -571,6 +689,16 @@ protected: // public. static uint64_t &getOffset(Cursor &C) { return C.Offset; } static Error &getError(Cursor &C) { return C.Err; } + +private: + /// If it is possible to read \a Size bytes at offset \a Offset, returns \b + /// true. Otherwise, returns \b false. If \a E is not nullptr, also sets the + /// error object to indicate an error. + bool prepareRead(uint64_t Offset, uint64_t Size, Error *E) const; + + template <typename T> T getU(uint64_t *OffsetPtr, Error *Err) const; + template <typename T> + T *getUs(uint64_t *OffsetPtr, T *Dst, uint32_t Count, Error *Err) const; }; } // namespace llvm diff --git a/llvm/include/llvm/Support/DebugCounter.h b/llvm/include/llvm/Support/DebugCounter.h index e7d1fa68f21ae..cd9474a4d9184 100644 --- a/llvm/include/llvm/Support/DebugCounter.h +++ b/llvm/include/llvm/Support/DebugCounter.h @@ -44,14 +44,15 @@ #define LLVM_SUPPORT_DEBUGCOUNTER_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/UniqueVector.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" #include <string> namespace llvm { +class raw_ostream; + class DebugCounter { public: ~DebugCounter(); @@ -68,7 +69,7 @@ public: // line option parsing. The main reason to register counters is to produce a // nice list of them on the command line, but i'm not sure this is worth it. static unsigned registerCounter(StringRef Name, StringRef Desc) { - return instance().addCounter(Name, Desc); + return instance().addCounter(std::string(Name), std::string(Desc)); } inline static bool shouldExecute(unsigned CounterName) { if (!isCountingEnabled()) diff --git a/llvm/include/llvm/Support/ELFAttributeParser.h b/llvm/include/llvm/Support/ELFAttributeParser.h new file mode 100644 index 0000000000000..8bf87b2d84f05 --- /dev/null +++ b/llvm/include/llvm/Support/ELFAttributeParser.h @@ -0,0 +1,72 @@ +//===- ELF AttributeParser.h - ELF Attribute Parser -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ELFATTRIBUTEPARSER_H +#define LLVM_SUPPORT_ELFATTRIBUTEPARSER_H + +#include "ELFAttributes.h" +#include "ScopedPrinter.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Error.h" + +#include <unordered_map> + +namespace llvm { +class StringRef; + +class ELFAttributeParser { + StringRef vendor; + std::unordered_map<unsigned, unsigned> attributes; + std::unordered_map<unsigned, StringRef> attributesStr; + + virtual Error handler(uint64_t tag, bool &handled) = 0; + +protected: + ScopedPrinter *sw; + TagNameMap tagToStringMap; + DataExtractor de{ArrayRef<uint8_t>{}, true, 0}; + DataExtractor::Cursor cursor{0}; + + void printAttribute(unsigned tag, unsigned value, StringRef valueDesc); + + Error parseStringAttribute(const char *name, unsigned tag, + ArrayRef<const char *> strings); + Error parseAttributeList(uint32_t length); + void parseIndexList(SmallVectorImpl<uint8_t> &indexList); + Error parseSubsection(uint32_t length); + +public: + virtual ~ELFAttributeParser() { static_cast<void>(!cursor.takeError()); } + Error integerAttribute(unsigned tag); + Error stringAttribute(unsigned tag); + + ELFAttributeParser(ScopedPrinter *sw, TagNameMap tagNameMap, StringRef vendor) + : vendor(vendor), sw(sw), tagToStringMap(tagNameMap) {} + + ELFAttributeParser(TagNameMap tagNameMap, StringRef vendor) + : vendor(vendor), sw(nullptr), tagToStringMap(tagNameMap) {} + + Error parse(ArrayRef<uint8_t> section, support::endianness endian); + + Optional<unsigned> getAttributeValue(unsigned tag) const { + auto I = attributes.find(tag); + if (I == attributes.end()) + return None; + return I->second; + } + Optional<StringRef> getAttributeString(unsigned tag) const { + auto I = attributesStr.find(tag); + if (I == attributesStr.end()) + return None; + return I->second; + } +}; + +} // namespace llvm +#endif diff --git a/llvm/include/llvm/Support/ELFAttributes.h b/llvm/include/llvm/Support/ELFAttributes.h new file mode 100644 index 0000000000000..c8a7ae142b9af --- /dev/null +++ b/llvm/include/llvm/Support/ELFAttributes.h @@ -0,0 +1,37 @@ +//===-- ELFAttributes.h - ELF Attributes ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ELFATTRIBUTES_H +#define LLVM_SUPPORT_ELFATTRIBUTES_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" + +namespace llvm { + +struct TagNameItem { + unsigned attr; + StringRef tagName; +}; + +using TagNameMap = ArrayRef<TagNameItem>; + +namespace ELFAttrs { + +enum AttrType : unsigned { File = 1, Section = 2, Symbol = 3 }; + +StringRef attrTypeAsString(unsigned attr, TagNameMap tagNameMap, + bool hasTagPrefix = true); +Optional<unsigned> attrTypeFromString(StringRef tag, TagNameMap tagNameMap); + +// Magic numbers for ELF attributes. +enum AttrMagic { Format_Version = 0x41 }; + +} // namespace ELFAttrs +} // namespace llvm +#endif diff --git a/llvm/include/llvm/Support/Endian.h b/llvm/include/llvm/Support/Endian.h index 87aecedd3a4b4..5e7c1e961b9d1 100644 --- a/llvm/include/llvm/Support/Endian.h +++ b/llvm/include/llvm/Support/Endian.h @@ -13,9 +13,7 @@ #ifndef LLVM_SUPPORT_ENDIAN_H #define LLVM_SUPPORT_ENDIAN_H -#include "llvm/Support/AlignOf.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/Host.h" #include "llvm/Support/SwapByteOrder.h" #include <cassert> #include <cstddef> @@ -111,7 +109,7 @@ inline void write(void *memory, value_type value) { } template <typename value_type> -using make_unsigned_t = typename std::make_unsigned<value_type>::type; +using make_unsigned_t = std::make_unsigned_t<value_type>; /// Read a value of a particular endianness from memory, for a location /// that starts at the given bit offset within the first byte. diff --git a/llvm/include/llvm/Support/Errno.h b/llvm/include/llvm/Support/Errno.h index aedb5fb292b84..dc3b3322ed982 100644 --- a/llvm/include/llvm/Support/Errno.h +++ b/llvm/include/llvm/Support/Errno.h @@ -30,8 +30,8 @@ std::string StrError(); std::string StrError(int errnum); template <typename FailT, typename Fun, typename... Args> -inline auto RetryAfterSignal(const FailT &Fail, const Fun &F, - const Args &... As) -> decltype(F(As...)) { +inline decltype(auto) RetryAfterSignal(const FailT &Fail, const Fun &F, + const Args &... As) { decltype(F(As...)) Res; do { errno = 0; diff --git a/llvm/include/llvm/Support/Error.h b/llvm/include/llvm/Support/Error.h index 44676338808b4..9dd1bb7cb96de 100644 --- a/llvm/include/llvm/Support/Error.h +++ b/llvm/include/llvm/Support/Error.h @@ -269,9 +269,13 @@ private: } ErrorInfoBase *getPtr() const { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS return reinterpret_cast<ErrorInfoBase*>( reinterpret_cast<uintptr_t>(Payload) & ~static_cast<uintptr_t>(0x1)); +#else + return Payload; +#endif } void setPtr(ErrorInfoBase *EI) { @@ -294,10 +298,12 @@ private: } void setChecked(bool V) { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS Payload = reinterpret_cast<ErrorInfoBase*>( (reinterpret_cast<uintptr_t>(Payload) & ~static_cast<uintptr_t>(0x1)) | (V ? 0 : 1)); +#endif } std::unique_ptr<ErrorInfoBase> takePayload() { @@ -434,21 +440,21 @@ template <class T> class LLVM_NODISCARD Expected { template <class T1> friend class ExpectedAsOutParameter; template <class OtherT> friend class Expected; - static const bool isRef = std::is_reference<T>::value; + static constexpr bool isRef = std::is_reference<T>::value; - using wrap = std::reference_wrapper<typename std::remove_reference<T>::type>; + using wrap = std::reference_wrapper<std::remove_reference_t<T>>; using error_type = std::unique_ptr<ErrorInfoBase>; public: - using storage_type = typename std::conditional<isRef, wrap, T>::type; + using storage_type = std::conditional_t<isRef, wrap, T>; using value_type = T; private: - using reference = typename std::remove_reference<T>::type &; - using const_reference = const typename std::remove_reference<T>::type &; - using pointer = typename std::remove_reference<T>::type *; - using const_pointer = const typename std::remove_reference<T>::type *; + using reference = std::remove_reference_t<T> &; + using const_reference = const std::remove_reference_t<T> &; + using pointer = std::remove_reference_t<T> *; + using const_pointer = const std::remove_reference_t<T> *; public: /// Create an Expected<T> error value from the given Error. @@ -472,12 +478,12 @@ public: /// must be convertible to T. template <typename OtherT> Expected(OtherT &&Val, - typename std::enable_if<std::is_convertible<OtherT, T>::value>::type - * = nullptr) + std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr) : HasError(false) #if LLVM_ENABLE_ABI_BREAKING_CHECKS // Expected is unchecked upon construction in Debug builds. - , Unchecked(true) + , + Unchecked(true) #endif { new (getStorage()) storage_type(std::forward<OtherT>(Val)); @@ -489,9 +495,9 @@ public: /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT /// must be convertible to T. template <class OtherT> - Expected(Expected<OtherT> &&Other, - typename std::enable_if<std::is_convertible<OtherT, T>::value>::type - * = nullptr) { + Expected( + Expected<OtherT> &&Other, + std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr) { moveConstruct(std::move(Other)); } @@ -500,8 +506,7 @@ public: template <class OtherT> explicit Expected( Expected<OtherT> &&Other, - typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * = - nullptr) { + std::enable_if_t<!std::is_convertible<OtherT, T>::value> * = nullptr) { moveConstruct(std::move(Other)); } diff --git a/llvm/include/llvm/Support/ErrorHandling.h b/llvm/include/llvm/Support/ErrorHandling.h index f75c2984a9ff7..7cbc668b3a0e8 100644 --- a/llvm/include/llvm/Support/ErrorHandling.h +++ b/llvm/include/llvm/Support/ErrorHandling.h @@ -66,7 +66,7 @@ class StringRef; /// /// If no error handler is installed the default is to print the message to /// standard error, followed by a newline. -/// After the error handler is called this function will call exit(1), it +/// After the error handler is called this function will call abort(), it /// does not return. LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const char *reason, bool gen_crash_diag = true); @@ -103,8 +103,8 @@ 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 -/// defined error handler throws an exception. +/// functions, this function might not terminate, e.g. the user +/// defined error handler throws an exception, but it won't return. /// /// Note: When throwing an exception in the bad alloc handler, make sure that /// the following unwind succeeds, e.g. do not trigger additional allocations @@ -113,7 +113,8 @@ void install_out_of_memory_new_handler(); /// 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 called. -void report_bad_alloc_error(const char *Reason, bool GenCrashDiag = true); +LLVM_ATTRIBUTE_NORETURN void report_bad_alloc_error(const char *Reason, + bool GenCrashDiag = true); /// This function calls abort(), and prints the optional message to stderr. /// Use the llvm_unreachable macro (that adds location info), instead of @@ -127,7 +128,7 @@ llvm_unreachable_internal(const char *msg = nullptr, const char *file = nullptr, /// In !NDEBUG builds, prints the message and location info to stderr. /// In NDEBUG builds, becomes an optimizer hint that the current location /// is not supposed to be reachable. On compilers that don't support -/// such hints, prints a reduced message instead. +/// such hints, prints a reduced message instead and aborts the program. /// /// Use this instead of assert(0). It conveys intent more clearly and /// allows compilers to omit some unnecessary code. diff --git a/llvm/include/llvm/Support/ErrorOr.h b/llvm/include/llvm/Support/ErrorOr.h index 8211f4d8a098b..1fbccc1d1e263 100644 --- a/llvm/include/llvm/Support/ErrorOr.h +++ b/llvm/include/llvm/Support/ErrorOr.h @@ -56,25 +56,25 @@ template<class T> class ErrorOr { template <class OtherT> friend class ErrorOr; - static const bool isRef = std::is_reference<T>::value; + static constexpr bool isRef = std::is_reference<T>::value; - using wrap = std::reference_wrapper<typename std::remove_reference<T>::type>; + using wrap = std::reference_wrapper<std::remove_reference_t<T>>; public: - using storage_type = typename std::conditional<isRef, wrap, T>::type; + using storage_type = std::conditional_t<isRef, wrap, T>; private: - using reference = typename std::remove_reference<T>::type &; - using const_reference = const typename std::remove_reference<T>::type &; - using pointer = typename std::remove_reference<T>::type *; - using const_pointer = const typename std::remove_reference<T>::type *; + using reference = std::remove_reference_t<T> &; + using const_reference = const std::remove_reference_t<T> &; + using pointer = std::remove_reference_t<T> *; + using const_pointer = const std::remove_reference_t<T> *; public: template <class E> ErrorOr(E ErrorCode, - typename std::enable_if<std::is_error_code_enum<E>::value || - std::is_error_condition_enum<E>::value, - void *>::type = nullptr) + std::enable_if_t<std::is_error_code_enum<E>::value || + std::is_error_condition_enum<E>::value, + void *> = nullptr) : HasError(true) { new (getErrorStorage()) std::error_code(make_error_code(ErrorCode)); } @@ -85,8 +85,7 @@ public: template <class OtherT> ErrorOr(OtherT &&Val, - typename std::enable_if<std::is_convertible<OtherT, T>::value>::type - * = nullptr) + std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr) : HasError(false) { new (getStorage()) storage_type(std::forward<OtherT>(Val)); } @@ -96,18 +95,16 @@ public: } template <class OtherT> - ErrorOr( - const ErrorOr<OtherT> &Other, - typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * = - nullptr) { + ErrorOr(const ErrorOr<OtherT> &Other, + std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr) { copyConstruct(Other); } template <class OtherT> explicit ErrorOr( const ErrorOr<OtherT> &Other, - typename std::enable_if< - !std::is_convertible<OtherT, const T &>::value>::type * = nullptr) { + std::enable_if_t<!std::is_convertible<OtherT, const T &>::value> * = + nullptr) { copyConstruct(Other); } @@ -116,10 +113,8 @@ public: } template <class OtherT> - ErrorOr( - ErrorOr<OtherT> &&Other, - typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * = - nullptr) { + ErrorOr(ErrorOr<OtherT> &&Other, + std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr) { moveConstruct(std::move(Other)); } @@ -128,8 +123,7 @@ public: template <class OtherT> explicit ErrorOr( ErrorOr<OtherT> &&Other, - typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * = - nullptr) { + std::enable_if_t<!std::is_convertible<OtherT, T>::value> * = nullptr) { moveConstruct(std::move(Other)); } @@ -266,9 +260,9 @@ private: }; template <class T, class E> -typename std::enable_if<std::is_error_code_enum<E>::value || - std::is_error_condition_enum<E>::value, - bool>::type +std::enable_if_t<std::is_error_code_enum<E>::value || + std::is_error_condition_enum<E>::value, + bool> operator==(const ErrorOr<T> &Err, E Code) { return Err.getError() == Code; } diff --git a/llvm/include/llvm/Support/ExtensibleRTTI.h b/llvm/include/llvm/Support/ExtensibleRTTI.h new file mode 100644 index 0000000000000..6b8510ce759f9 --- /dev/null +++ b/llvm/include/llvm/Support/ExtensibleRTTI.h @@ -0,0 +1,135 @@ +//===-- llvm/Support/ExtensibleRTTI.h - ExtensibleRTTI support --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// \file +// +// Defines an extensible RTTI mechanism designed to work with Casting.h. +// +// Extensible RTTI differs from LLVM's primary RTTI mechanism (see +// llvm.org/docs/HowToSetUpLLVMStyleRTTI.html) by supporting open type +// hierarchies, where new types can be added from outside libraries without +// needing to change existing code. LLVM's primary RTTI mechanism should be +// preferred where possible, but where open hierarchies are needed this system +// can be used. +// +// The RTTIRoot class defines methods for comparing type ids. Implementations +// of these methods can be injected into new classes using the RTTIExtends +// class template. +// +// E.g. +// +// @code{.cpp} +// class MyBaseClass : public RTTIExtends<MyBaseClass, RTTIRoot> { +// public: +// static char ID; +// virtual void foo() = 0; +// }; +// +// class MyDerivedClass1 : public RTTIExtends<MyDerivedClass1, MyBaseClass> { +// public: +// static char ID; +// void foo() override {} +// }; +// +// class MyDerivedClass2 : public RTTIExtends<MyDerivedClass2, MyBaseClass> { +// public: +// static char ID; +// void foo() override {} +// }; +// +// char MyBaseClass::ID = 0; +// char MyDerivedClass1::ID = 0; +// char MyDerivedClass2:: ID = 0; +// +// void fn() { +// std::unique_ptr<MyBaseClass> B = llvm::make_unique<MyDerivedClass1>(); +// llvm::outs() << isa<MyBaseClass>(B) << "\n"; // Outputs "1". +// llvm::outs() << isa<MyDerivedClass1>(B) << "\n"; // Outputs "1". +// llvm::outs() << isa<MyDerivedClass2>(B) << "\n"; // Outputs "0'. +// } +// +// @endcode +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_EXTENSIBLERTTI_H +#define LLVM_SUPPORT_EXTENSIBLERTTI_H + +namespace llvm { + +template <typename ThisT, typename ParentT> class RTTIExtends; + +/// Base class for the extensible RTTI hierarchy. +/// +/// This class defines virtual methods, dynamicClassID and isA, that enable +/// type comparisons. +class RTTIRoot { +public: + virtual ~RTTIRoot() = default; + + /// Returns the class ID for this type. + static const void *classID() { return &ID; } + + /// Returns the class ID for the dynamic type of this RTTIRoot instance. + virtual const void *dynamicClassID() const = 0; + + /// Returns true if this class's ID matches the given class ID. + virtual bool isA(const void *const ClassID) const { + return ClassID == classID(); + } + + /// Check whether this instance is a subclass of QueryT. + template <typename QueryT> + bool isA() const { return isA(QueryT::classID()); } + +private: + virtual void anchor(); + + static char ID; +}; + +/// Inheritance utility for extensible RTTI. +/// +/// Supports single inheritance only: A class can only have one +/// ExtensibleRTTI-parent (i.e. a parent for which the isa<> test will work), +/// though it can have many non-ExtensibleRTTI parents. +/// +/// RTTIExtents uses CRTP so the first template argument to RTTIExtends is the +/// newly introduced type, and the *second* argument is the parent class. +/// +/// class MyType : public RTTIExtends<MyType, RTTIRoot> { +/// public: +/// static char ID; +/// }; +/// +/// class MyDerivedType : public RTTIExtends<MyDerivedType, MyType> { +/// public: +/// static char ID; +/// }; +/// +template <typename ThisT, typename ParentT> +class RTTIExtends : public ParentT { +public: + // Inherit constructors from ParentT. + using ParentT::ParentT; + + static const void *classID() { return &ThisT::ID; } + + const void *dynamicClassID() const override { return &ThisT::ID; } + + bool isA(const void *const ClassID) const override { + return ClassID == classID() || ParentT::isA(ClassID); + } + + static bool classof(const RTTIRoot *R) { return R->isA<ThisT>(); } +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_EXTENSIBLERTTI_H diff --git a/llvm/include/llvm/Support/FileCheck.h b/llvm/include/llvm/Support/FileCheck.h index 429e36cfcbb5f..2f0e641394d57 100644 --- a/llvm/include/llvm/Support/FileCheck.h +++ b/llvm/include/llvm/Support/FileCheck.h @@ -24,13 +24,15 @@ namespace llvm { /// Contains info about various FileCheck options. struct FileCheckRequest { - std::vector<std::string> CheckPrefixes; + std::vector<StringRef> CheckPrefixes; + std::vector<StringRef> CommentPrefixes; bool NoCanonicalizeWhiteSpace = false; - std::vector<std::string> ImplicitCheckNot; - std::vector<std::string> GlobalDefines; + std::vector<StringRef> ImplicitCheckNot; + std::vector<StringRef> GlobalDefines; bool AllowEmptyInput = false; bool MatchFullLines = false; bool IgnoreCase = false; + bool IsDefaultCheckPrefix = false; bool EnableVarScope = false; bool AllowDeprecatedDagOverlap = false; bool Verbose = false; @@ -52,6 +54,7 @@ enum FileCheckKind { CheckDAG, CheckLabel, CheckEmpty, + CheckComment, /// Indicates the pattern only matches the end of file. This is used for /// trailing CHECK-NOTs. @@ -87,7 +90,7 @@ struct FileCheckDiag { /// What is the FileCheck directive for this diagnostic? Check::FileCheckType CheckTy; /// Where is the FileCheck directive for this diagnostic? - unsigned CheckLine, CheckCol; + SMLoc CheckLoc; /// What type of match result does this diagnostic describe? /// /// A directive's supplied pattern is said to be either expected or excluded @@ -159,7 +162,13 @@ public: /// /// Only expected strings whose prefix is one of those listed in \p PrefixRE /// are recorded. \returns true in case of an error, false otherwise. - bool readCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE); + /// + /// If \p ImpPatBufferIDRange, then the range (inclusive start, exclusive end) + /// of IDs for source buffers added to \p SM for implicit patterns are + /// recorded in it. The range is empty if there are none. + bool + readCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE, + std::pair<unsigned, unsigned> *ImpPatBufferIDRange = nullptr); bool ValidateCheckPrefixes(); diff --git a/llvm/include/llvm/Support/FileCollector.h b/llvm/include/llvm/Support/FileCollector.h index 079fe3efab9d3..2b5e9c669b680 100644 --- a/llvm/include/llvm/Support/FileCollector.h +++ b/llvm/include/llvm/Support/FileCollector.h @@ -12,23 +12,44 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSet.h" -#include "llvm/ADT/Twine.h" #include "llvm/Support/VirtualFileSystem.h" - #include <mutex> +#include <string> namespace llvm { - -/// Collects files into a directory and generates a mapping that can be used by -/// the VFS. +class FileCollectorFileSystem; +class Twine; + +/// Captures file system interaction and generates data to be later replayed +/// with the RedirectingFileSystem. +/// +/// For any file that gets accessed we eventually create: +/// - a copy of the file inside Root +/// - a record in RedirectingFileSystem mapping that maps: +/// current real path -> path to the copy in Root +/// +/// That intent is that later when the mapping is used by RedirectingFileSystem +/// it simulates the state of FS that we collected. +/// +/// We generate file copies and mapping lazily - see writeMapping and copyFiles. +/// We don't try to capture the state of the file at the exact time when it's +/// accessed. Files might get changed, deleted ... we record only the "final" +/// state. +/// +/// In order to preserve the relative topology of files we use their real paths +/// as relative paths inside of the Root. class FileCollector { public: + /// \p Root is the directory where collected files are will be stored. + /// \p OverlayRoot is VFS mapping root. + /// \p Root directory gets created in copyFiles unless it already exists. FileCollector(std::string Root, std::string OverlayRoot); void addFile(const Twine &file); + void addDirectory(const Twine &Dir); /// Write the yaml mapping (for the VFS) to the given file. - std::error_code writeMapping(StringRef mapping_file); + std::error_code writeMapping(StringRef MappingFile); /// Copy the files into the root directory. /// @@ -37,14 +58,14 @@ public: /// removed after it was added to the mapping. std::error_code copyFiles(bool StopOnError = true); - /// Create a VFS that collects all the paths that might be looked at by the - /// file system accesses. + /// Create a VFS that uses \p Collector to collect files accessed via \p + /// BaseFS. static IntrusiveRefCntPtr<vfs::FileSystem> createCollectorVFS(IntrusiveRefCntPtr<vfs::FileSystem> BaseFS, std::shared_ptr<FileCollector> Collector); private: - void addFileImpl(StringRef SrcPath); + friend FileCollectorFileSystem; bool markAsSeen(StringRef Path) { if (Path.empty()) @@ -55,18 +76,27 @@ private: bool getRealPath(StringRef SrcPath, SmallVectorImpl<char> &Result); void addFileToMapping(StringRef VirtualPath, StringRef RealPath) { - VFSWriter.addFileMapping(VirtualPath, RealPath); + if (sys::fs::is_directory(VirtualPath)) + VFSWriter.addDirectoryMapping(VirtualPath, RealPath); + else + VFSWriter.addFileMapping(VirtualPath, RealPath); } protected: - /// Synchronizes adding files. + void addFileImpl(StringRef SrcPath); + + llvm::vfs::directory_iterator + addDirectoryImpl(const llvm::Twine &Dir, + IntrusiveRefCntPtr<vfs::FileSystem> FS, std::error_code &EC); + + /// Synchronizes access to Seen, VFSWriter and SymlinkMap. std::mutex Mutex; - /// The root directory where files are copied. - std::string Root; + /// The directory where collected files are copied to in copyFiles(). + const std::string Root; /// The root directory where the VFS overlay lives. - std::string OverlayRoot; + const std::string OverlayRoot; /// Tracks already seen files so they can be skipped. StringSet<> Seen; diff --git a/llvm/include/llvm/Support/FileOutputBuffer.h b/llvm/include/llvm/Support/FileOutputBuffer.h index bdc1425d43617..8eb36d0034ad4 100644 --- a/llvm/include/llvm/Support/FileOutputBuffer.h +++ b/llvm/include/llvm/Support/FileOutputBuffer.h @@ -13,11 +13,9 @@ #ifndef LLVM_SUPPORT_FILEOUTPUTBUFFER_H #define LLVM_SUPPORT_FILEOUTPUTBUFFER_H -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Error.h" -#include "llvm/Support/FileSystem.h" namespace llvm { /// FileOutputBuffer - This interface provides simple way to create an in-memory diff --git a/llvm/include/llvm/Support/FormatAdapters.h b/llvm/include/llvm/Support/FormatAdapters.h index a0e8cc4391912..495205d11748b 100644 --- a/llvm/include/llvm/Support/FormatAdapters.h +++ b/llvm/include/llvm/Support/FormatAdapters.h @@ -9,7 +9,6 @@ #ifndef LLVM_SUPPORT_FORMATADAPTERS_H #define LLVM_SUPPORT_FORMATADAPTERS_H -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/FormatCommon.h" @@ -35,7 +34,7 @@ public: : FormatAdapter<T>(std::forward<T>(Item)), Where(Where), Amount(Amount), Fill(Fill) {} - void format(llvm::raw_ostream &Stream, StringRef Style) { + void format(llvm::raw_ostream &Stream, StringRef Style) override { auto Adapter = detail::build_format_adapter(std::forward<T>(this->Item)); FmtAlign(Adapter, Where, Amount, Fill).format(Stream, Style); } @@ -49,7 +48,7 @@ public: PadAdapter(T &&Item, size_t Left, size_t Right) : FormatAdapter<T>(std::forward<T>(Item)), Left(Left), Right(Right) {} - void format(llvm::raw_ostream &Stream, StringRef Style) { + void format(llvm::raw_ostream &Stream, StringRef Style) override { auto Adapter = detail::build_format_adapter(std::forward<T>(this->Item)); Stream.indent(Left); Adapter.format(Stream, Style); @@ -64,7 +63,7 @@ public: RepeatAdapter(T &&Item, size_t Count) : FormatAdapter<T>(std::forward<T>(Item)), Count(Count) {} - void format(llvm::raw_ostream &Stream, StringRef Style) { + void format(llvm::raw_ostream &Stream, StringRef Style) override { auto Adapter = detail::build_format_adapter(std::forward<T>(this->Item)); for (size_t I = 0; I < Count; ++I) { Adapter.format(Stream, Style); @@ -77,7 +76,9 @@ 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; } + void format(llvm::raw_ostream &Stream, StringRef Style) override { + Stream << Item; + } }; } diff --git a/llvm/include/llvm/Support/FormatProviders.h b/llvm/include/llvm/Support/FormatProviders.h index 629a4845716a4..c31481a292595 100644 --- a/llvm/include/llvm/Support/FormatProviders.h +++ b/llvm/include/llvm/Support/FormatProviders.h @@ -124,7 +124,7 @@ protected: template <typename T> struct format_provider< - T, typename std::enable_if<detail::use_integral_formatter<T>::value>::type> + T, std::enable_if_t<detail::use_integral_formatter<T>::value>> : public detail::HelperFunctions { private: public: @@ -173,7 +173,7 @@ public: /// cases indicates the minimum number of nibbles to print. template <typename T> struct format_provider< - T, typename std::enable_if<detail::use_pointer_formatter<T>::value>::type> + T, std::enable_if_t<detail::use_pointer_formatter<T>::value>> : public detail::HelperFunctions { private: public: @@ -198,7 +198,7 @@ public: template <typename T> struct format_provider< - T, typename std::enable_if<detail::use_string_formatter<T>::value>::type> { + T, std::enable_if_t<detail::use_string_formatter<T>::value>> { static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) { size_t N = StringRef::npos; if (!Style.empty() && Style.getAsInteger(10, N)) { @@ -230,8 +230,8 @@ template <> struct format_provider<Twine> { /// character. Otherwise, it is treated as an integer options string. /// template <typename T> -struct format_provider< - T, typename std::enable_if<detail::use_char_formatter<T>::value>::type> { +struct format_provider<T, + std::enable_if_t<detail::use_char_formatter<T>::value>> { static void format(const char &V, llvm::raw_ostream &Stream, StringRef Style) { if (Style.empty()) @@ -296,8 +296,8 @@ template <> struct format_provider<bool> { /// else. template <typename T> -struct format_provider< - T, typename std::enable_if<detail::use_double_formatter<T>::value>::type> +struct format_provider<T, + std::enable_if_t<detail::use_double_formatter<T>::value>> : public detail::HelperFunctions { static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) { FloatStyle S; diff --git a/llvm/include/llvm/Support/FormatVariadic.h b/llvm/include/llvm/Support/FormatVariadic.h index 86a9d30cc138d..dfafc3ccb44e4 100644 --- a/llvm/include/llvm/Support/FormatVariadic.h +++ b/llvm/include/llvm/Support/FormatVariadic.h @@ -25,6 +25,7 @@ #ifndef LLVM_SUPPORT_FORMATVARIADIC_H #define LLVM_SUPPORT_FORMATVARIADIC_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" @@ -63,23 +64,8 @@ struct ReplacementItem { class formatv_object_base { protected: - // The parameters are stored in a std::tuple, which does not provide runtime - // indexing capabilities. In order to enable runtime indexing, we use this - // structure to put the parameters into a std::vector. Since the parameters - // are not all the same type, we use some type-erasure by wrapping the - // parameters in a template class that derives from a non-template superclass. - // Essentially, we are converting a std::tuple<Derived<Ts...>> to a - // std::vector<Base*>. - struct create_adapters { - template <typename... Ts> - std::vector<detail::format_adapter *> operator()(Ts &... Items) { - return std::vector<detail::format_adapter *>{&Items...}; - } - }; - StringRef Fmt; - std::vector<detail::format_adapter *> Adapters; - std::vector<ReplacementItem> Replacements; + ArrayRef<detail::format_adapter *> Adapters; static bool consumeFieldLayout(StringRef &Spec, AlignStyle &Where, size_t &Align, char &Pad); @@ -87,23 +73,16 @@ protected: static std::pair<ReplacementItem, StringRef> splitLiteralAndReplacement(StringRef Fmt); -public: - formatv_object_base(StringRef Fmt, std::size_t ParamCount) - : Fmt(Fmt), Replacements(parseFormatString(Fmt)) { - Adapters.reserve(ParamCount); - } + formatv_object_base(StringRef Fmt, + ArrayRef<detail::format_adapter *> Adapters) + : Fmt(Fmt), Adapters(Adapters) {} formatv_object_base(formatv_object_base const &rhs) = delete; + formatv_object_base(formatv_object_base &&rhs) = default; - formatv_object_base(formatv_object_base &&rhs) - : Fmt(std::move(rhs.Fmt)), - Adapters(), // Adapters are initialized by formatv_object - Replacements(std::move(rhs.Replacements)) { - Adapters.reserve(rhs.Adapters.size()); - }; - +public: void format(raw_ostream &S) const { - for (auto &R : Replacements) { + for (auto &R : parseFormatString(Fmt)) { if (R.Type == ReplacementType::Empty) continue; if (R.Type == ReplacementType::Literal) { @@ -121,7 +100,7 @@ public: Align.format(S, R.Options); } } - static std::vector<ReplacementItem> parseFormatString(StringRef Fmt); + static SmallVector<ReplacementItem, 2> parseFormatString(StringRef Fmt); static Optional<ReplacementItem> parseReplacementItem(StringRef Spec); @@ -150,12 +129,29 @@ template <typename Tuple> class formatv_object : public formatv_object_base { // of the parameters, we have to own the storage for the parameters here, and // have the base class store type-erased pointers into this tuple. Tuple Parameters; + std::array<detail::format_adapter *, std::tuple_size<Tuple>::value> + ParameterPointers; + + // The parameters are stored in a std::tuple, which does not provide runtime + // indexing capabilities. In order to enable runtime indexing, we use this + // structure to put the parameters into a std::array. Since the parameters + // are not all the same type, we use some type-erasure by wrapping the + // parameters in a template class that derives from a non-template superclass. + // Essentially, we are converting a std::tuple<Derived<Ts...>> to a + // std::array<Base*>. + struct create_adapters { + template <typename... Ts> + std::array<detail::format_adapter *, std::tuple_size<Tuple>::value> + operator()(Ts &... Items) { + return {{&Items...}}; + } + }; public: formatv_object(StringRef Fmt, Tuple &&Params) - : formatv_object_base(Fmt, std::tuple_size<Tuple>::value), + : formatv_object_base(Fmt, ParameterPointers), Parameters(std::move(Params)) { - Adapters = apply_tuple(create_adapters(), Parameters); + ParameterPointers = apply_tuple(create_adapters(), Parameters); } formatv_object(formatv_object const &rhs) = delete; @@ -163,7 +159,8 @@ public: formatv_object(formatv_object &&rhs) : formatv_object_base(std::move(rhs)), Parameters(std::move(rhs.Parameters)) { - Adapters = apply_tuple(create_adapters(), Parameters); + ParameterPointers = apply_tuple(create_adapters(), Parameters); + Adapters = ParameterPointers; } }; diff --git a/llvm/include/llvm/Support/FormatVariadicDetails.h b/llvm/include/llvm/Support/FormatVariadicDetails.h index e3c185134daa4..d5e67b756a472 100644 --- a/llvm/include/llvm/Support/FormatVariadicDetails.h +++ b/llvm/include/llvm/Support/FormatVariadicDetails.h @@ -36,7 +36,7 @@ public: explicit provider_format_adapter(T &&Item) : Item(std::forward<T>(Item)) {} void format(llvm::raw_ostream &S, StringRef Options) override { - format_provider<typename std::decay<T>::type>::format(Item, S, Options); + format_provider<std::decay_t<T>>::format(Item, S, Options); } }; @@ -59,7 +59,7 @@ template <typename T> class missing_format_adapter; // template <class T> class has_FormatProvider { public: - using Decayed = typename std::decay<T>::type; + using Decayed = std::decay_t<T>; typedef void (*Signature_format)(const Decayed &, llvm::raw_ostream &, StringRef); @@ -75,14 +75,14 @@ public: // 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 &; + using ConstRefT = const std::decay_t<T> &; 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); + static char test( + std::enable_if_t<std::is_same<decltype(std::declval<llvm::raw_ostream &>() + << std::declval<U>()), + llvm::raw_ostream &>::value, + int *>); template <typename U> static double test(...); @@ -95,8 +95,8 @@ template <typename T> struct uses_format_member : public std::integral_constant< bool, - std::is_base_of<format_adapter, - typename std::remove_reference<T>::type>::value> {}; + std::is_base_of<format_adapter, std::remove_reference_t<T>>::value> { +}; // Simple template that decides whether a type T should use the format_provider // based format() invocation. The member function takes priority, so this test @@ -127,34 +127,32 @@ struct uses_missing_provider }; template <typename T> -typename std::enable_if<uses_format_member<T>::value, T>::type +std::enable_if_t<uses_format_member<T>::value, T> build_format_adapter(T &&Item) { return std::forward<T>(Item); } template <typename T> -typename std::enable_if<uses_format_provider<T>::value, - provider_format_adapter<T>>::type +std::enable_if_t<uses_format_provider<T>::value, provider_format_adapter<T>> build_format_adapter(T &&Item) { return provider_format_adapter<T>(std::forward<T>(Item)); } template <typename T> -typename std::enable_if<uses_stream_operator<T>::value, - stream_operator_format_adapter<T>>::type +std::enable_if_t<uses_stream_operator<T>::value, + stream_operator_format_adapter<T>> 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, + !std::is_same<llvm::Error, std::remove_cv_t<T>>::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 +std::enable_if_t<uses_missing_provider<T>::value, missing_format_adapter<T>> build_format_adapter(T &&Item) { return missing_format_adapter<T>(); } diff --git a/llvm/include/llvm/Support/FormattedStream.h b/llvm/include/llvm/Support/FormattedStream.h index b49c8d86531db..5f937cfa79840 100644 --- a/llvm/include/llvm/Support/FormattedStream.h +++ b/llvm/include/llvm/Support/FormattedStream.h @@ -14,6 +14,7 @@ #ifndef LLVM_SUPPORT_FORMATTEDSTREAM_H #define LLVM_SUPPORT_FORMATTEDSTREAM_H +#include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" #include <utility> @@ -21,8 +22,11 @@ namespace llvm { /// formatted_raw_ostream - A raw_ostream that wraps another one and keeps track /// of line and column position, allowing padding out to specific column -/// boundaries and querying the number of lines written to the stream. -/// +/// boundaries and querying the number of lines written to the stream. This +/// assumes that the contents of the stream is valid UTF-8 encoded text. This +/// doesn't attempt to handle everything Unicode can do (combining characters, +/// right-to-left markers, etc), but should cover the cases likely to appear in +/// source code or diagnostic messages. class formatted_raw_ostream : public raw_ostream { /// TheStream - The real stream we output to. We set it to be /// unbuffered, since we're already doing our own buffering. @@ -40,6 +44,14 @@ class formatted_raw_ostream : public raw_ostream { /// const char *Scanned; + /// PartialUTF8Char - Either empty or a prefix of a UTF-8 code unit sequence + /// for a Unicode scalar value which should be prepended to the buffer for the + /// next call to ComputePosition. This is needed when the buffer is flushed + /// when it ends part-way through the UTF-8 encoding of a Unicode scalar + /// value, so that we can compute the display width of the character once we + /// have the rest of it. + SmallString<4> PartialUTF8Char; + void write_impl(const char *Ptr, size_t Size) override; /// current_pos - Return the current position within the stream, @@ -52,10 +64,16 @@ class formatted_raw_ostream : public raw_ostream { } /// ComputePosition - Examine the given output buffer and figure out the new - /// position after output. - /// + /// position after output. This is safe to call multiple times on the same + /// buffer, as it records the most recently scanned character and resumes from + /// there when the buffer has not been flushed. void ComputePosition(const char *Ptr, size_t size); + /// UpdatePosition - scan the characters in [Ptr, Ptr+Size), and update the + /// line and column numbers. Unlike ComputePosition, this must be called + /// exactly once on each region of the buffer. + void UpdatePosition(const char *Ptr, size_t Size); + void setStream(raw_ostream &Stream) { releaseStream(); @@ -105,11 +123,17 @@ public: /// \param NewCol - The column to move to. formatted_raw_ostream &PadToColumn(unsigned NewCol); - /// getColumn - Return the column number - unsigned getColumn() { return Position.first; } + unsigned getColumn() { + // Calculate current position, taking buffer contents into account. + ComputePosition(getBufferStart(), GetNumBytesInBuffer()); + return Position.first; + } - /// getLine - Return the line number - unsigned getLine() { return Position.second; } + unsigned getLine() { + // Calculate current position, taking buffer contents into account. + ComputePosition(getBufferStart(), GetNumBytesInBuffer()); + return Position.second; + } raw_ostream &resetColor() override { TheStream->resetColor(); diff --git a/llvm/include/llvm/Support/GenericDomTree.h b/llvm/include/llvm/Support/GenericDomTree.h index 2545a075062a1..10e591a69d369 100644 --- a/llvm/include/llvm/Support/GenericDomTree.h +++ b/llvm/include/llvm/Support/GenericDomTree.h @@ -25,7 +25,6 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/GraphTraits.h" -#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" @@ -78,18 +77,25 @@ template <class NodeT> class DomTreeNodeBase { const_iterator begin() const { return Children.begin(); } const_iterator end() const { return Children.end(); } + DomTreeNodeBase *const &back() const { return Children.back(); } + DomTreeNodeBase *&back() { return Children.back(); } + + iterator_range<iterator> children() { return make_range(begin(), end()); } + iterator_range<const_iterator> children() const { + return make_range(begin(), end()); + } + NodeT *getBlock() const { return TheBB; } DomTreeNodeBase *getIDom() const { return IDom; } unsigned getLevel() const { return Level; } - const std::vector<DomTreeNodeBase *> &getChildren() const { return Children; } - std::unique_ptr<DomTreeNodeBase> addChild( std::unique_ptr<DomTreeNodeBase> C) { Children.push_back(C.get()); return C; } + bool isLeaf() const { return Children.empty(); } size_t getNumChildren() const { return Children.size(); } void clearAllChildren() { Children.clear(); } @@ -225,7 +231,7 @@ class DominatorTreeBase { using ParentPtr = decltype(std::declval<NodeT *>()->getParent()); static_assert(std::is_pointer<ParentPtr>::value, "Currently NodeT's parent must be a pointer type"); - using ParentType = typename std::remove_pointer<ParentPtr>::type; + using ParentType = std::remove_pointer_t<ParentPtr>; static constexpr bool IsPostDominator = IsPostDom; using UpdateType = cfg::Update<NodePtr>; @@ -277,11 +283,27 @@ protected: DominatorTreeBase(const DominatorTreeBase &) = delete; DominatorTreeBase &operator=(const DominatorTreeBase &) = delete; - /// getRoots - Return the root blocks of the current CFG. This may include - /// multiple blocks if we are computing post dominators. For forward - /// dominators, this will always be a single block (the entry node). + /// Iteration over roots. /// - const SmallVectorImpl<NodeT *> &getRoots() const { return Roots; } + /// This may include multiple blocks if we are computing post dominators. + /// For forward dominators, this will always be a single block (the entry + /// block). + using root_iterator = typename SmallVectorImpl<NodeT *>::iterator; + using const_root_iterator = typename SmallVectorImpl<NodeT *>::const_iterator; + + root_iterator root_begin() { return Roots.begin(); } + const_root_iterator root_begin() const { return Roots.begin(); } + root_iterator root_end() { return Roots.end(); } + const_root_iterator root_end() const { return Roots.end(); } + + size_t root_size() const { return Roots.size(); } + + iterator_range<root_iterator> roots() { + return make_range(root_begin(), root_end()); + } + iterator_range<const_root_iterator> roots() const { + return make_range(root_begin(), root_end()); + } /// isPostDominator - Returns true if analysis based of postdoms /// @@ -319,8 +341,6 @@ protected: return false; } - void releaseMemory() { reset(); } - /// getNode - return the (Post)DominatorTree node for the specified basic /// 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) @@ -570,8 +590,7 @@ protected: DomTreeNodeBase<NodeT> *IDomNode = getNode(DomBB); assert(IDomNode && "Not immediate dominator specified for block!"); DFSInfoValid = false; - return (DomTreeNodes[BB] = IDomNode->addChild( - std::make_unique<DomTreeNodeBase<NodeT>>(BB, IDomNode))).get(); + return createChild(BB, IDomNode); } /// Add a new node to the forward dominator tree and make it a new root. @@ -584,8 +603,7 @@ protected: assert(!this->isPostDominator() && "Cannot change root of post-dominator tree"); DFSInfoValid = false; - DomTreeNodeBase<NodeT> *NewNode = (DomTreeNodes[BB] = - std::make_unique<DomTreeNodeBase<NodeT>>(BB, nullptr)).get(); + DomTreeNodeBase<NodeT> *NewNode = createNode(BB); if (Roots.empty()) { addRoot(BB); } else { @@ -620,7 +638,7 @@ protected: void eraseNode(NodeT *BB) { DomTreeNodeBase<NodeT> *Node = getNode(BB); assert(Node && "Removing node that isn't in dominator tree."); - assert(Node->getChildren().empty() && "Node is not a leaf node."); + assert(Node->isLeaf() && "Node is not a leaf node."); DFSInfoValid = false; @@ -754,9 +772,6 @@ public: return DomTreeBuilder::Verify(*this, VL); } -protected: - void addRoot(NodeT *BB) { this->Roots.push_back(BB); } - void reset() { DomTreeNodes.clear(); Roots.clear(); @@ -766,6 +781,21 @@ protected: SlowQueries = 0; } +protected: + void addRoot(NodeT *BB) { this->Roots.push_back(BB); } + + DomTreeNodeBase<NodeT> *createChild(NodeT *BB, DomTreeNodeBase<NodeT> *IDom) { + return (DomTreeNodes[BB] = IDom->addChild( + std::make_unique<DomTreeNodeBase<NodeT>>(BB, IDom))) + .get(); + } + + DomTreeNodeBase<NodeT> *createNode(NodeT *BB) { + return (DomTreeNodes[BB] = + std::make_unique<DomTreeNodeBase<NodeT>>(BB, nullptr)) + .get(); + } + // NewBB is split and now it has one successor. Update dominator tree to // reflect this change. template <class N> diff --git a/llvm/include/llvm/Support/GenericDomTreeConstruction.h b/llvm/include/llvm/Support/GenericDomTreeConstruction.h index 7c0278e8770ee..464de4e2b3ba1 100644 --- a/llvm/include/llvm/Support/GenericDomTreeConstruction.h +++ b/llvm/include/llvm/Support/GenericDomTreeConstruction.h @@ -7,11 +7,11 @@ //===----------------------------------------------------------------------===// /// \file /// -/// Generic dominator tree construction - This file provides routines to +/// Generic dominator tree construction - this file provides routines to /// construct immediate dominator information for a flow-graph based on the /// Semi-NCA algorithm described in this dissertation: /// -/// Linear-Time Algorithms for Dominators and Related Problems +/// [1] Linear-Time Algorithms for Dominators and Related Problems /// Loukas Georgiadis, Princeton University, November 2005, pp. 21-23: /// ftp://ftp.cs.princeton.edu/reports/2005/737.pdf /// @@ -20,13 +20,15 @@ /// /// O(n^2) worst cases happen when the computation of nearest common ancestors /// requires O(n) average time, which is very unlikely in real world. If this -/// ever turns out to be an issue, consider implementing a hybrid algorithm. +/// ever turns out to be an issue, consider implementing a hybrid algorithm +/// that uses SLT to perform full constructions and SemiNCA for incremental +/// updates. /// /// The file uses the Depth Based Search algorithm to perform incremental /// updates (insertion and deletions). The implemented algorithm is based on /// this publication: /// -/// An Experimental Study of Dynamic Dominators +/// [2] An Experimental Study of Dynamic Dominators /// Loukas Georgiadis, et al., April 12 2016, pp. 5-7, 9-10: /// https://arxiv.org/pdf/1604.02711.pdf /// @@ -35,7 +37,6 @@ #ifndef LLVM_SUPPORT_GENERICDOMTREECONSTRUCTION_H #define LLVM_SUPPORT_GENERICDOMTREECONSTRUCTION_H -#include <queue> #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/DepthFirstIterator.h" @@ -43,6 +44,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/Debug.h" #include "llvm/Support/GenericDomTree.h" +#include <queue> #define DEBUG_TYPE "dom-tree-builder" @@ -185,9 +187,7 @@ struct SemiNCAInfo { // Add a new tree node for this NodeT, and link it as a child of // IDomNode - return (DT.DomTreeNodes[BB] = IDomNode->addChild( - std::make_unique<DomTreeNodeBase<NodeT>>(BB, IDomNode))) - .get(); + return DT.createChild(BB, IDomNode); } static bool AlwaysDescend(NodePtr, NodePtr) { return true; } @@ -585,9 +585,7 @@ struct SemiNCAInfo { // all real exits (including multiple exit blocks, infinite loops). NodePtr Root = IsPostDom ? nullptr : DT.Roots[0]; - DT.RootNode = (DT.DomTreeNodes[Root] = - std::make_unique<DomTreeNodeBase<NodeT>>(Root, nullptr)) - .get(); + DT.RootNode = DT.createNode(Root); SNCA.attachNewSubtree(DT, DT.RootNode); } @@ -597,8 +595,6 @@ 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]; - 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? @@ -610,8 +606,7 @@ struct SemiNCAInfo { // Add a new tree node for this BasicBlock, and link it as a child of // IDomNode. - DT.DomTreeNodes[W] = IDomNode->addChild( - std::make_unique<DomTreeNodeBase<NodeT>>(W, IDomNode)); + DT.createChild(W, IDomNode); } } @@ -661,10 +656,7 @@ struct SemiNCAInfo { // The unreachable node becomes a new root -- a tree node for it. TreeNodePtr VirtualRoot = DT.getNode(nullptr); - FromTN = - (DT.DomTreeNodes[From] = VirtualRoot->addChild( - std::make_unique<DomTreeNodeBase<NodeT>>(From, VirtualRoot))) - .get(); + FromTN = DT.createChild(From, VirtualRoot); DT.Roots.push_back(From); } @@ -732,7 +724,7 @@ struct SemiNCAInfo { 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. + // we do not know yet how to do it, and it happens rarely in practice. CalculateFromScratch(DT, BUI); } } @@ -757,13 +749,13 @@ struct SemiNCAInfo { LLVM_DEBUG(dbgs() << "\t\tNCA == " << BlockNamePrinter(NCD) << "\n"); const unsigned NCDLevel = NCD->getLevel(); - // Based on Lemma 2.5 from the second paper, after insertion of (From,To), v - // is affected iff depth(NCD)+1 < depth(v) && a path P from To to v exists - // where every w on P s.t. depth(v) <= depth(w) + // Based on Lemma 2.5 from [2], after insertion of (From,To), v is affected + // iff depth(NCD)+1 < depth(v) && a path P from To to v exists where every + // w on P s.t. depth(v) <= depth(w) // // This reduces to a widest path problem (maximizing the depth of the // minimum vertex in the path) which can be solved by a modified version of - // Dijkstra with a bucket queue (named depth-based search in the paper). + // Dijkstra with a bucket queue (named depth-based search in [2]). // To is in the path, so depth(NCD)+1 < depth(v) <= depth(To). Nothing // affected if this does not hold. @@ -957,7 +949,7 @@ struct SemiNCAInfo { << BlockNamePrinter(ToIDom) << "\n"); // To remains reachable after deletion. - // (Based on the caption under Figure 4. from the second paper.) + // (Based on the caption under Figure 4. from [2].) if (FromTN != ToIDom || HasProperSupport(DT, BUI, ToTN)) DeleteReachable(DT, BUI, FromTN, ToTN); else @@ -976,7 +968,7 @@ struct SemiNCAInfo { 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.) + // (Based on the lemma 2.6 from [2].) const NodePtr ToIDom = DT.findNearestCommonDominator(FromTN->getBlock(), ToTN->getBlock()); assert(ToIDom || DT.isPostDominator()); @@ -1008,7 +1000,7 @@ struct SemiNCAInfo { } // Checks if a node has proper support, as defined on the page 3 and later - // explained on the page 7 of the second paper. + // explained on the page 7 of [2]. static bool HasProperSupport(DomTreeT &DT, const BatchUpdatePtr BUI, const TreeNodePtr TN) { LLVM_DEBUG(dbgs() << "IsReachableFromIDom " << BlockNamePrinter(TN) @@ -1033,7 +1025,7 @@ struct SemiNCAInfo { } // Handle deletions that make destination node unreachable. - // (Based on the lemma 2.7 from the second paper.) + // (Based on the lemma 2.7 from the [2].) static void DeleteUnreachable(DomTreeT &DT, const BatchUpdatePtr BUI, const TreeNodePtr ToTN) { LLVM_DEBUG(dbgs() << "Deleting unreachable subtree " @@ -1372,7 +1364,7 @@ struct SemiNCAInfo { if (!DT.DFSInfoValid || !DT.Parent) return true; - const NodePtr RootBB = IsPostDom ? nullptr : DT.getRoots()[0]; + const NodePtr RootBB = IsPostDom ? nullptr : *DT.root_begin(); const TreeNodePtr Root = DT.getNode(RootBB); auto PrintNodeAndDFSNums = [](const TreeNodePtr TN) { @@ -1396,7 +1388,7 @@ struct SemiNCAInfo { const TreeNodePtr Node = NodeToTN.second.get(); // Handle tree leaves. - if (Node->getChildren().empty()) { + if (Node->isLeaf()) { if (Node->getDFSNumIn() + 1 != Node->getDFSNumOut()) { errs() << "Tree leaf should have DFSOut = DFSIn + 1:\n\t"; PrintNodeAndDFSNums(Node); @@ -1493,9 +1485,9 @@ struct SemiNCAInfo { // LEFT, and thus, LEFT is really an ancestor (in the dominator tree) of // RIGHT, not a sibling. - // It is possible to verify the parent and sibling properties in - // 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. + // It is possible to verify the parent and sibling properties in 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 @@ -1508,7 +1500,8 @@ struct SemiNCAInfo { for (auto &NodeToTN : DT.DomTreeNodes) { const TreeNodePtr TN = NodeToTN.second.get(); const NodePtr BB = TN->getBlock(); - if (!BB || TN->getChildren().empty()) continue; + if (!BB || TN->isLeaf()) + continue; LLVM_DEBUG(dbgs() << "Verifying parent property of node " << BlockNamePrinter(TN) << "\n"); @@ -1517,7 +1510,7 @@ struct SemiNCAInfo { return From != BB && To != BB; }); - for (TreeNodePtr Child : TN->getChildren()) + for (TreeNodePtr Child : TN->children()) if (NodeToInfo.count(Child->getBlock()) != 0) { errs() << "Child " << BlockNamePrinter(Child) << " reachable after its parent " << BlockNamePrinter(BB) @@ -1541,17 +1534,17 @@ struct SemiNCAInfo { for (auto &NodeToTN : DT.DomTreeNodes) { const TreeNodePtr TN = NodeToTN.second.get(); const NodePtr BB = TN->getBlock(); - if (!BB || TN->getChildren().empty()) continue; + if (!BB || TN->isLeaf()) + continue; - const auto &Siblings = TN->getChildren(); - for (const TreeNodePtr N : Siblings) { + for (const TreeNodePtr N : TN->children()) { clear(); NodePtr BBN = N->getBlock(); doFullDFSWalk(DT, [BBN](NodePtr From, NodePtr To) { return From != BBN && To != BBN; }); - for (const TreeNodePtr S : Siblings) { + for (const TreeNodePtr S : TN->children()) { if (S == N) continue; if (NodeToInfo.count(S->getBlock()) == 0) { @@ -1571,7 +1564,7 @@ struct SemiNCAInfo { // 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). + // Running time: O(N^2), but faster in practice (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) @@ -1648,12 +1641,12 @@ bool Verify(const DomTreeT &DT, typename DomTreeT::VerificationLevel VL) { if (!SNCA.IsSameAsFreshTree(DT)) return false; - // Common checks to verify the properties of the tree. O(N log N) at worst + // 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) + // Extra checks depending on VerificationLevel. Up to O(N^3). if (VL == DomTreeT::VerificationLevel::Basic || VL == DomTreeT::VerificationLevel::Full) if (!SNCA.verifyParentProperty(DT)) diff --git a/llvm/include/llvm/Support/GenericIteratedDominanceFrontier.h b/llvm/include/llvm/Support/GenericIteratedDominanceFrontier.h index 25eb7cd7b6d57..a8fca70159f5f 100644 --- a/llvm/include/llvm/Support/GenericIteratedDominanceFrontier.h +++ b/llvm/include/llvm/Support/GenericIteratedDominanceFrontier.h @@ -57,7 +57,7 @@ template <class NodeTy, bool IsPostDom> struct ChildrenGetterTy { template <class NodeTy, bool IsPostDom> class IDFCalculatorBase { public: using OrderedNodeTy = - typename std::conditional<IsPostDom, Inverse<NodeTy *>, NodeTy *>::type; + std::conditional_t<IsPostDom, Inverse<NodeTy *>, NodeTy *>; using ChildrenGetterTy = IDFCalculatorDetail::ChildrenGetterTy<NodeTy, IsPostDom>; @@ -129,7 +129,7 @@ ChildrenGetterTy<NodeTy, IsPostDom>::get(const NodeRef &N) { template <class NodeTy, bool IsPostDom> void IDFCalculatorBase<NodeTy, IsPostDom>::calculate( - SmallVectorImpl<NodeTy *> &PHIBlocks) { + SmallVectorImpl<NodeTy *> &IDFBlocks) { // Use a priority queue keyed on dominator tree level so that inserted nodes // are handled from the bottom of the dominator tree upwards. We also augment // the level with a DFS number to ensure that the blocks are ordered in a @@ -144,15 +144,16 @@ void IDFCalculatorBase<NodeTy, IsPostDom>::calculate( DT.updateDFSNumbers(); - for (NodeTy *BB : *DefBlocks) { - if (DomTreeNodeBase<NodeTy> *Node = DT.getNode(BB)) - PQ.push({Node, std::make_pair(Node->getLevel(), Node->getDFSNumIn())}); - } - SmallVector<DomTreeNodeBase<NodeTy> *, 32> Worklist; SmallPtrSet<DomTreeNodeBase<NodeTy> *, 32> VisitedPQ; SmallPtrSet<DomTreeNodeBase<NodeTy> *, 32> VisitedWorklist; + for (NodeTy *BB : *DefBlocks) + if (DomTreeNodeBase<NodeTy> *Node = DT.getNode(BB)) { + PQ.push({Node, std::make_pair(Node->getLevel(), Node->getDFSNumIn())}); + VisitedWorklist.insert(Node); + } + while (!PQ.empty()) { DomTreeNodePair RootPair = PQ.top(); PQ.pop(); @@ -164,9 +165,8 @@ void IDFCalculatorBase<NodeTy, IsPostDom>::calculate( // most Root's level are added to the iterated dominance frontier of the // definition set. - Worklist.clear(); + assert(Worklist.empty()); Worklist.push_back(Root); - VisitedWorklist.insert(Root); while (!Worklist.empty()) { DomTreeNodeBase<NodeTy> *Node = Worklist.pop_back_val(); @@ -187,7 +187,7 @@ void IDFCalculatorBase<NodeTy, IsPostDom>::calculate( if (useLiveIn && !LiveInBlocks->count(SuccBB)) return; - PHIBlocks.emplace_back(SuccBB); + IDFBlocks.emplace_back(SuccBB); if (!DefBlocks->count(SuccBB)) PQ.push(std::make_pair( SuccNode, std::make_pair(SuccLevel, SuccNode->getDFSNumIn()))); diff --git a/llvm/include/llvm/Support/GlobPattern.h b/llvm/include/llvm/Support/GlobPattern.h index 0098ac65fd308..3e5989d025007 100644 --- a/llvm/include/llvm/Support/GlobPattern.h +++ b/llvm/include/llvm/Support/GlobPattern.h @@ -16,15 +16,15 @@ #include "llvm/ADT/BitVector.h" #include "llvm/ADT/Optional.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include <vector> // This class represents a glob pattern. Supported metacharacters // are "*", "?", "\", "[<chars>]", "[^<chars>]", and "[!<chars>]". namespace llvm { -class BitVector; + template <typename T> class ArrayRef; +class StringRef; class GlobPattern { public: diff --git a/llvm/include/llvm/Support/GraphWriter.h b/llvm/include/llvm/Support/GraphWriter.h index 466a0449e2579..f9241b1e8081b 100644 --- a/llvm/include/llvm/Support/GraphWriter.h +++ b/llvm/include/llvm/Support/GraphWriter.h @@ -126,7 +126,7 @@ public: } void writeHeader(const std::string &Title) { - std::string GraphName = DTraits.getGraphName(G); + std::string GraphName(DTraits.getGraphName(G)); if (!Title.empty()) O << "digraph \"" << DOT::EscapeString(Title) << "\" {\n"; @@ -330,11 +330,8 @@ std::string WriteGraph(const GraphType &G, const Twine &Name, const Twine &Title = "", std::string Filename = "") { int FD; - // Windows can't always handle long paths, so limit the length of the name. - std::string N = Name.str(); - N = N.substr(0, std::min<std::size_t>(N.size(), 140)); if (Filename.empty()) { - Filename = createGraphFilename(N, FD); + Filename = createGraphFilename(Name.str(), FD); } else { std::error_code EC = sys::fs::openFileForWrite(Filename, FD); @@ -344,6 +341,8 @@ std::string WriteGraph(const GraphType &G, const Twine &Name, } else if (EC) { errs() << "error writing into file" << "\n"; return ""; + } else { + errs() << "writing to the newly created file " << Filename << "\n"; } } raw_fd_ostream O(FD, /*shouldClose=*/ true); @@ -359,6 +358,17 @@ std::string WriteGraph(const GraphType &G, const Twine &Name, return Filename; } +/// DumpDotGraph - Just dump a dot graph to the user-provided file name. +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +template <typename GraphType> +LLVM_DUMP_METHOD void +dumpDotGraphToFile(const GraphType &G, const Twine &FileName, + const Twine &Title, bool ShortNames = false, + const Twine &Name = "") { + llvm::WriteGraph(G, Name, ShortNames, Title, FileName.str()); +} +#endif + /// ViewGraph - Emit a dot graph, run 'dot', run gv on the postscript file, /// then cleanup. For use from the debugger. /// diff --git a/llvm/include/llvm/Support/Host.h b/llvm/include/llvm/Support/Host.h index 44f543c363db5..d4ef389450cc8 100644 --- a/llvm/include/llvm/Support/Host.h +++ b/llvm/include/llvm/Support/Host.h @@ -13,11 +13,13 @@ #ifndef LLVM_SUPPORT_HOST_H #define LLVM_SUPPORT_HOST_H -#include "llvm/ADT/StringMap.h" - #include <string> namespace llvm { +class MallocAllocator; +class StringRef; +template <typename ValueTy, typename AllocatorTy> class StringMap; + namespace sys { /// getDefaultTargetTriple() - Return the default target triple the compiler @@ -50,7 +52,7 @@ namespace sys { /// all valid LLVM feature names. /// /// \return - True on success. - bool getHostCPUFeatures(StringMap<bool> &Features); + bool getHostCPUFeatures(StringMap<bool, MallocAllocator> &Features); /// Get the number of physical cores (as opposed to logical cores returned /// from thread::hardware_concurrency(), which includes hyperthreads). diff --git a/llvm/include/llvm/Support/ItaniumManglingCanonicalizer.h b/llvm/include/llvm/Support/ItaniumManglingCanonicalizer.h index 6920000340d4f..8e1b3d631983d 100644 --- a/llvm/include/llvm/Support/ItaniumManglingCanonicalizer.h +++ b/llvm/include/llvm/Support/ItaniumManglingCanonicalizer.h @@ -14,11 +14,13 @@ #ifndef LLVM_SUPPORT_ITANIUMMANGLINGCANONICALIZER_H #define LLVM_SUPPORT_ITANIUMMANGLINGCANONICALIZER_H -#include "llvm/ADT/StringRef.h" - #include <cstddef> +#include <cstdint> namespace llvm { + +class StringRef; + /// Canonicalizer for mangled names. /// /// This class allows specifying a list of "equivalent" manglings. For example, diff --git a/llvm/include/llvm/Support/JSON.h b/llvm/include/llvm/Support/JSON.h index 2c63468c401a1..8b1c66234fe87 100644 --- a/llvm/include/llvm/Support/JSON.h +++ b/llvm/include/llvm/Support/JSON.h @@ -329,32 +329,28 @@ public: 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> + template <typename T, + typename = std::enable_if_t<std::is_same<T, bool>::value>, + 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> + template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>, + typename = std::enable_if_t<!std::is_same<T, bool>::value>> 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, + typename = std::enable_if_t<std::is_floating_point<T>::value>, 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< + typename = std::enable_if_t<std::is_same< Value, decltype(toJSON(*(const T *)nullptr))>::value>, Value * = nullptr> Value(const T &V) : Value(toJSON(V)) {} @@ -565,7 +561,7 @@ inline bool Object::erase(StringRef K) { // See comments on Value. inline bool fromJSON(const Value &E, std::string &Out) { if (auto S = E.getAsString()) { - Out = *S; + Out = std::string(*S); return true; } return false; @@ -598,6 +594,13 @@ inline bool fromJSON(const Value &E, bool &Out) { } return false; } +inline bool fromJSON(const Value &E, std::nullptr_t &Out) { + if (auto S = E.getAsNull()) { + Out = *S; + return true; + } + return false; +} template <typename T> bool fromJSON(const Value &E, llvm::Optional<T> &Out) { if (E.getAsNull()) { Out = llvm::None; @@ -625,7 +628,7 @@ 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)])) + if (!fromJSON(KV.second, Out[std::string(llvm::StringRef(KV.first))])) return false; return true; } diff --git a/llvm/include/llvm/Support/KnownBits.h b/llvm/include/llvm/Support/KnownBits.h index ff25b6fc572ce..69040cd23f039 100644 --- a/llvm/include/llvm/Support/KnownBits.h +++ b/llvm/include/llvm/Support/KnownBits.h @@ -122,39 +122,55 @@ public: return ~Zero; } - /// Truncate the underlying known Zero and One bits. This is equivalent - /// to truncating the value we're tracking. + /// Return known bits for a truncation of the value we're tracking. KnownBits trunc(unsigned BitWidth) const { return KnownBits(Zero.trunc(BitWidth), One.trunc(BitWidth)); } - /// Extends the underlying known Zero and One bits. - /// By setting ExtendedBitsAreKnownZero=true this will be equivalent to - /// zero extending the value we're tracking. - /// With ExtendedBitsAreKnownZero=false the extended bits are set to unknown. - KnownBits zext(unsigned BitWidth, bool ExtendedBitsAreKnownZero) const { + /// Return known bits for an "any" extension of the value we're tracking, + /// where we don't know anything about the extended bits. + KnownBits anyext(unsigned BitWidth) const { + return KnownBits(Zero.zext(BitWidth), One.zext(BitWidth)); + } + + /// Return known bits for a zero extension of the value we're tracking. + KnownBits zext(unsigned BitWidth) const { unsigned OldBitWidth = getBitWidth(); APInt NewZero = Zero.zext(BitWidth); - if (ExtendedBitsAreKnownZero) - NewZero.setBitsFrom(OldBitWidth); + NewZero.setBitsFrom(OldBitWidth); return KnownBits(NewZero, One.zext(BitWidth)); } - /// Sign extends the underlying known Zero and One bits. This is equivalent - /// to sign extending the value we're tracking. + /// Return known bits for a sign extension of the value we're tracking. KnownBits sext(unsigned BitWidth) const { return KnownBits(Zero.sext(BitWidth), One.sext(BitWidth)); } - /// Extends or truncates the underlying known Zero and One bits. When - /// extending the extended bits can either be set as known zero (if - /// ExtendedBitsAreKnownZero=true) or as unknown (if - /// ExtendedBitsAreKnownZero=false). - KnownBits zextOrTrunc(unsigned BitWidth, - bool ExtendedBitsAreKnownZero) const { + /// Return known bits for an "any" extension or truncation of the value we're + /// tracking. + KnownBits anyextOrTrunc(unsigned BitWidth) const { + if (BitWidth > getBitWidth()) + return anyext(BitWidth); + if (BitWidth < getBitWidth()) + return trunc(BitWidth); + return *this; + } + + /// Return known bits for a zero extension or truncation of the value we're + /// tracking. + KnownBits zextOrTrunc(unsigned BitWidth) const { if (BitWidth > getBitWidth()) - return zext(BitWidth, ExtendedBitsAreKnownZero); - return KnownBits(Zero.zextOrTrunc(BitWidth), One.zextOrTrunc(BitWidth)); + return zext(BitWidth); + if (BitWidth < getBitWidth()) + return trunc(BitWidth); + return *this; + } + + /// Return a KnownBits with the extracted bits + /// [bitPosition,bitPosition+numBits). + KnownBits extractBits(unsigned NumBits, unsigned BitPosition) const { + return KnownBits(Zero.extractBits(NumBits, BitPosition), + One.extractBits(NumBits, BitPosition)); } /// Returns the minimum number of trailing zero bits. @@ -224,8 +240,47 @@ public: /// Compute known bits resulting from adding LHS and RHS. static KnownBits computeForAddSub(bool Add, bool NSW, const KnownBits &LHS, KnownBits RHS); + + /// Update known bits based on ANDing with RHS. + KnownBits &operator&=(const KnownBits &RHS); + + /// Update known bits based on ORing with RHS. + KnownBits &operator|=(const KnownBits &RHS); + + /// Update known bits based on XORing with RHS. + KnownBits &operator^=(const KnownBits &RHS); }; +inline KnownBits operator&(KnownBits LHS, const KnownBits &RHS) { + LHS &= RHS; + return LHS; +} + +inline KnownBits operator&(const KnownBits &LHS, KnownBits &&RHS) { + RHS &= LHS; + return std::move(RHS); +} + +inline KnownBits operator|(KnownBits LHS, const KnownBits &RHS) { + LHS |= RHS; + return LHS; +} + +inline KnownBits operator|(const KnownBits &LHS, KnownBits &&RHS) { + RHS |= LHS; + return std::move(RHS); +} + +inline KnownBits operator^(KnownBits LHS, const KnownBits &RHS) { + LHS ^= RHS; + return LHS; +} + +inline KnownBits operator^(const KnownBits &LHS, KnownBits &&RHS) { + RHS ^= LHS; + return std::move(RHS); +} + } // end namespace llvm #endif diff --git a/llvm/include/llvm/Support/LEB128.h b/llvm/include/llvm/Support/LEB128.h index a02b83ca95975..8ab35431354d5 100644 --- a/llvm/include/llvm/Support/LEB128.h +++ b/llvm/include/llvm/Support/LEB128.h @@ -134,7 +134,7 @@ inline uint64_t decodeULEB128(const uint8_t *p, unsigned *n = nullptr, if (error) *error = nullptr; do { - if (end && p == end) { + if (p == end) { if (error) *error = "malformed uleb128, extends past end"; if (n) @@ -168,7 +168,7 @@ inline int64_t decodeSLEB128(const uint8_t *p, unsigned *n = nullptr, if (error) *error = nullptr; do { - if (end && p == end) { + if (p == end) { if (error) *error = "malformed sleb128, extends past end"; if (n) diff --git a/llvm/include/llvm/Support/LockFileManager.h b/llvm/include/llvm/Support/LockFileManager.h index 2efeca3b62001..ab66621e67566 100644 --- a/llvm/include/llvm/Support/LockFileManager.h +++ b/llvm/include/llvm/Support/LockFileManager.h @@ -78,8 +78,8 @@ public: /// For a shared lock, wait until the owner releases the lock. /// Total timeout for the file to appear is ~1.5 minutes. - /// \param MaxSeconds the maximum wait time per iteration in seconds. - WaitForUnlockResult waitForUnlock(const unsigned MaxSeconds = 40); + /// \param MaxSeconds the maximum total wait time in seconds. + WaitForUnlockResult waitForUnlock(const unsigned MaxSeconds = 90); /// Remove the lock file. This may delete a different lock file than /// the one previously read if there is a race. diff --git a/llvm/include/llvm/Support/LowLevelTypeImpl.h b/llvm/include/llvm/Support/LowLevelTypeImpl.h index 6ef7c298bc28f..c1d516f2fe587 100644 --- a/llvm/include/llvm/Support/LowLevelTypeImpl.h +++ b/llvm/include/llvm/Support/LowLevelTypeImpl.h @@ -27,6 +27,7 @@ #define LLVM_SUPPORT_LOWLEVELTYPEIMPL_H #include "llvm/ADT/DenseMapInfo.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/MachineValueType.h" #include <cassert> @@ -137,6 +138,26 @@ public: : LLT::scalar(NewEltSize); } + /// Return a vector or scalar with the same element type and the new number of + /// elements. + LLT changeNumElements(unsigned NewNumElts) const { + return LLT::scalarOrVector(NewNumElts, getScalarType()); + } + + /// Return a type that is \p Factor times smaller. Reduces the number of + /// elements if this is a vector, or the bitwidth for scalar/pointers. Does + /// not attempt to handle cases that aren't evenly divisible. + LLT divide(int Factor) const { + assert(Factor != 1); + if (isVector()) { + assert(getNumElements() % Factor == 0); + return scalarOrVector(getNumElements() / Factor, getElementType()); + } + + assert(getSizeInBits() % Factor == 0); + return scalar(getSizeInBits() / Factor); + } + bool isByteSized() const { return (getSizeInBits() & 7) == 0; } unsigned getScalarSizeInBits() const { @@ -174,6 +195,13 @@ public: void print(raw_ostream &OS) const; +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + LLVM_DUMP_METHOD void dump() const { + print(dbgs()); + dbgs() << '\n'; + } +#endif + bool operator==(const LLT &RHS) const { return IsPointer == RHS.IsPointer && IsVector == RHS.IsVector && RHS.RawData == RawData; diff --git a/llvm/include/llvm/Support/MD5.h b/llvm/include/llvm/Support/MD5.h index bb2bdbf1bed22..3b2d5b974d0bf 100644 --- a/llvm/include/llvm/Support/MD5.h +++ b/llvm/include/llvm/Support/MD5.h @@ -28,7 +28,6 @@ #ifndef LLVM_SUPPORT_MD5_H #define LLVM_SUPPORT_MD5_H -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Endian.h" #include <array> @@ -36,6 +35,7 @@ namespace llvm { +template <unsigned N> class SmallString; template <typename T> class ArrayRef; class MD5 { diff --git a/llvm/include/llvm/Support/MSVCErrorWorkarounds.h b/llvm/include/llvm/Support/MSVCErrorWorkarounds.h index 30e8febae20b9..bf983dc1e406b 100644 --- a/llvm/include/llvm/Support/MSVCErrorWorkarounds.h +++ b/llvm/include/llvm/Support/MSVCErrorWorkarounds.h @@ -59,22 +59,19 @@ public: template <typename OtherT> MSVCPExpected( OtherT &&Val, - typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * = - nullptr) + std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr) : Expected<T>(std::move(Val)) {} template <class OtherT> MSVCPExpected( Expected<OtherT> &&Other, - typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * = - nullptr) + std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr) : Expected<T>(std::move(Other)) {} template <class OtherT> explicit MSVCPExpected( Expected<OtherT> &&Other, - typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * = - nullptr) + std::enable_if_t<!std::is_convertible<OtherT, T>::value> * = nullptr) : Expected<T>(std::move(Other)) {} }; diff --git a/llvm/include/llvm/Support/MachineValueType.h b/llvm/include/llvm/Support/MachineValueType.h index 26b45a602763a..3bb8220e72e5d 100644 --- a/llvm/include/llvm/Support/MachineValueType.h +++ b/llvm/include/llvm/Support/MachineValueType.h @@ -47,158 +47,179 @@ namespace llvm { 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, + bf16 = 8, // This is a 16 bit brain floating point value + f16 = 9, // This is a 16 bit floating point value + f32 = 10, // This is a 32 bit floating point value + f64 = 11, // This is a 64 bit floating point value + f80 = 12, // This is a 80 bit floating point value + f128 = 13, // This is a 128 bit floating point value + ppcf128 = 14, // This is a PPC 128-bit floating point value + + FIRST_FP_VALUETYPE = bf16, 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 - v256i1 = 22, // 256 x i1 - v512i1 = 23, // 512 x i1 - v1024i1 = 24, // 1024 x i1 - - v1i8 = 25, // 1 x i8 - v2i8 = 26, // 2 x i8 - v4i8 = 27, // 4 x i8 - v8i8 = 28, // 8 x i8 - v16i8 = 29, // 16 x i8 - v32i8 = 30, // 32 x i8 - v64i8 = 31, // 64 x i8 - v128i8 = 32, //128 x i8 - v256i8 = 33, //256 x i8 - - v1i16 = 34, // 1 x i16 - v2i16 = 35, // 2 x i16 - v3i16 = 36, // 3 x i16 - v4i16 = 37, // 4 x i16 - v8i16 = 38, // 8 x i16 - v16i16 = 39, // 16 x i16 - v32i16 = 40, // 32 x i16 - v64i16 = 41, // 64 x i16 - v128i16 = 42, //128 x i16 - - v1i32 = 43, // 1 x i32 - v2i32 = 44, // 2 x i32 - v3i32 = 45, // 3 x i32 - v4i32 = 46, // 4 x i32 - v5i32 = 47, // 5 x i32 - v8i32 = 48, // 8 x i32 - v16i32 = 49, // 16 x i32 - v32i32 = 50, // 32 x i32 - v64i32 = 51, // 64 x i32 - v128i32 = 52, // 128 x i32 - v256i32 = 53, // 256 x i32 - v512i32 = 54, // 512 x i32 - v1024i32 = 55, // 1024 x i32 - v2048i32 = 56, // 2048 x i32 - - v1i64 = 57, // 1 x i64 - v2i64 = 58, // 2 x i64 - v4i64 = 59, // 4 x i64 - v8i64 = 60, // 8 x i64 - v16i64 = 61, // 16 x i64 - v32i64 = 62, // 32 x i64 - - v1i128 = 63, // 1 x i128 + v1i1 = 15, // 1 x i1 + v2i1 = 16, // 2 x i1 + v4i1 = 17, // 4 x i1 + v8i1 = 18, // 8 x i1 + v16i1 = 19, // 16 x i1 + v32i1 = 20, // 32 x i1 + v64i1 = 21, // 64 x i1 + v128i1 = 22, // 128 x i1 + v256i1 = 23, // 256 x i1 + v512i1 = 24, // 512 x i1 + v1024i1 = 25, // 1024 x i1 + + v1i8 = 26, // 1 x i8 + v2i8 = 27, // 2 x i8 + v4i8 = 28, // 4 x i8 + v8i8 = 29, // 8 x i8 + v16i8 = 30, // 16 x i8 + v32i8 = 31, // 32 x i8 + v64i8 = 32, // 64 x i8 + v128i8 = 33, //128 x i8 + v256i8 = 34, //256 x i8 + + v1i16 = 35, // 1 x i16 + v2i16 = 36, // 2 x i16 + v3i16 = 37, // 3 x i16 + v4i16 = 38, // 4 x i16 + v8i16 = 39, // 8 x i16 + v16i16 = 40, // 16 x i16 + v32i16 = 41, // 32 x i16 + v64i16 = 42, // 64 x i16 + v128i16 = 43, //128 x i16 + + v1i32 = 44, // 1 x i32 + v2i32 = 45, // 2 x i32 + v3i32 = 46, // 3 x i32 + v4i32 = 47, // 4 x i32 + v5i32 = 48, // 5 x i32 + v8i32 = 49, // 8 x i32 + v16i32 = 50, // 16 x i32 + v32i32 = 51, // 32 x i32 + v64i32 = 52, // 64 x i32 + v128i32 = 53, // 128 x i32 + v256i32 = 54, // 256 x i32 + v512i32 = 55, // 512 x i32 + v1024i32 = 56, // 1024 x i32 + v2048i32 = 57, // 2048 x i32 + + v1i64 = 58, // 1 x i64 + v2i64 = 59, // 2 x i64 + v4i64 = 60, // 4 x i64 + v8i64 = 61, // 8 x i64 + v16i64 = 62, // 16 x i64 + v32i64 = 63, // 32 x i64 + + v1i128 = 64, // 1 x i128 FIRST_INTEGER_FIXEDLEN_VECTOR_VALUETYPE = v1i1, LAST_INTEGER_FIXEDLEN_VECTOR_VALUETYPE = v1i128, - v2f16 = 64, // 2 x f16 - v3f16 = 65, // 3 x f16 - v4f16 = 66, // 4 x f16 - v8f16 = 67, // 8 x f16 - v16f16 = 68, // 16 x f16 - v32f16 = 69, // 32 x f16 - v1f32 = 70, // 1 x f32 - v2f32 = 71, // 2 x f32 - v3f32 = 72, // 3 x f32 - v4f32 = 73, // 4 x f32 - v5f32 = 74, // 5 x f32 - v8f32 = 75, // 8 x f32 - v16f32 = 76, // 16 x f32 - v32f32 = 77, // 32 x f32 - v64f32 = 78, // 64 x f32 - v128f32 = 79, // 128 x f32 - v256f32 = 80, // 256 x f32 - v512f32 = 81, // 512 x f32 - v1024f32 = 82, // 1024 x f32 - v2048f32 = 83, // 2048 x f32 - v1f64 = 84, // 1 x f64 - v2f64 = 85, // 2 x f64 - v4f64 = 86, // 4 x f64 - v8f64 = 87, // 8 x f64 + v2f16 = 65, // 2 x f16 + v3f16 = 66, // 3 x f16 + v4f16 = 67, // 4 x f16 + v8f16 = 68, // 8 x f16 + v16f16 = 69, // 16 x f16 + v32f16 = 70, // 32 x f16 + v64f16 = 71, // 64 x f16 + v128f16 = 72, // 128 x f16 + v2bf16 = 73, // 2 x bf16 + v3bf16 = 74, // 3 x bf16 + v4bf16 = 75, // 4 x bf16 + v8bf16 = 76, // 8 x bf16 + v16bf16 = 77, // 16 x bf16 + v32bf16 = 78, // 32 x bf16 + v64bf16 = 79, // 64 x bf16 + v128bf16 = 80, // 128 x bf16 + v1f32 = 81, // 1 x f32 + v2f32 = 82, // 2 x f32 + v3f32 = 83, // 3 x f32 + v4f32 = 84, // 4 x f32 + v5f32 = 85, // 5 x f32 + v8f32 = 86, // 8 x f32 + v16f32 = 87, // 16 x f32 + v32f32 = 88, // 32 x f32 + v64f32 = 89, // 64 x f32 + v128f32 = 90, // 128 x f32 + v256f32 = 91, // 256 x f32 + v512f32 = 92, // 512 x f32 + v1024f32 = 93, // 1024 x f32 + v2048f32 = 94, // 2048 x f32 + v1f64 = 95, // 1 x f64 + v2f64 = 96, // 2 x f64 + v4f64 = 97, // 4 x f64 + v8f64 = 98, // 8 x f64 + v16f64 = 99, // 16 x f64 + v32f64 = 100, // 32 x f64 FIRST_FP_FIXEDLEN_VECTOR_VALUETYPE = v2f16, - LAST_FP_FIXEDLEN_VECTOR_VALUETYPE = v8f64, + LAST_FP_FIXEDLEN_VECTOR_VALUETYPE = v32f64, FIRST_FIXEDLEN_VECTOR_VALUETYPE = v1i1, - LAST_FIXEDLEN_VECTOR_VALUETYPE = v8f64, - - nxv1i1 = 88, // n x 1 x i1 - nxv2i1 = 89, // n x 2 x i1 - nxv4i1 = 90, // n x 4 x i1 - nxv8i1 = 91, // n x 8 x i1 - nxv16i1 = 92, // n x 16 x i1 - nxv32i1 = 93, // n x 32 x i1 - - nxv1i8 = 94, // n x 1 x i8 - nxv2i8 = 95, // n x 2 x i8 - nxv4i8 = 96, // n x 4 x i8 - nxv8i8 = 97, // n x 8 x i8 - nxv16i8 = 98, // n x 16 x i8 - nxv32i8 = 99, // n x 32 x i8 - - nxv1i16 = 100, // n x 1 x i16 - nxv2i16 = 101, // n x 2 x i16 - nxv4i16 = 102, // n x 4 x i16 - nxv8i16 = 103, // n x 8 x i16 - nxv16i16 = 104, // n x 16 x i16 - nxv32i16 = 105, // n x 32 x i16 - - nxv1i32 = 106, // n x 1 x i32 - nxv2i32 = 107, // n x 2 x i32 - nxv4i32 = 108, // n x 4 x i32 - nxv8i32 = 109, // n x 8 x i32 - nxv16i32 = 110, // n x 16 x i32 - nxv32i32 = 111, // n x 32 x i32 - - nxv1i64 = 112, // n x 1 x i64 - nxv2i64 = 113, // n x 2 x i64 - nxv4i64 = 114, // n x 4 x i64 - nxv8i64 = 115, // n x 8 x i64 - nxv16i64 = 116, // n x 16 x i64 - nxv32i64 = 117, // n x 32 x i64 + LAST_FIXEDLEN_VECTOR_VALUETYPE = v32f64, + + nxv1i1 = 101, // n x 1 x i1 + nxv2i1 = 102, // n x 2 x i1 + nxv4i1 = 103, // n x 4 x i1 + nxv8i1 = 104, // n x 8 x i1 + nxv16i1 = 105, // n x 16 x i1 + nxv32i1 = 106, // n x 32 x i1 + nxv64i1 = 107, // n x 64 x i1 + + nxv1i8 = 108, // n x 1 x i8 + nxv2i8 = 109, // n x 2 x i8 + nxv4i8 = 110, // n x 4 x i8 + nxv8i8 = 111, // n x 8 x i8 + nxv16i8 = 112, // n x 16 x i8 + nxv32i8 = 113, // n x 32 x i8 + nxv64i8 = 114, // n x 64 x i8 + + nxv1i16 = 115, // n x 1 x i16 + nxv2i16 = 116, // n x 2 x i16 + nxv4i16 = 117, // n x 4 x i16 + nxv8i16 = 118, // n x 8 x i16 + nxv16i16 = 119, // n x 16 x i16 + nxv32i16 = 120, // n x 32 x i16 + + nxv1i32 = 121, // n x 1 x i32 + nxv2i32 = 122, // n x 2 x i32 + nxv4i32 = 123, // n x 4 x i32 + nxv8i32 = 124, // n x 8 x i32 + nxv16i32 = 125, // n x 16 x i32 + nxv32i32 = 126, // n x 32 x i32 + + nxv1i64 = 127, // n x 1 x i64 + nxv2i64 = 128, // n x 2 x i64 + nxv4i64 = 129, // n x 4 x i64 + nxv8i64 = 130, // n x 8 x i64 + nxv16i64 = 131, // n x 16 x i64 + nxv32i64 = 132, // n x 32 x i64 FIRST_INTEGER_SCALABLE_VECTOR_VALUETYPE = nxv1i1, LAST_INTEGER_SCALABLE_VECTOR_VALUETYPE = nxv32i64, - nxv2f16 = 118, // n x 2 x f16 - nxv4f16 = 119, // n x 4 x f16 - nxv8f16 = 120, // n x 8 x f16 - nxv1f32 = 121, // n x 1 x f32 - nxv2f32 = 122, // n x 2 x f32 - nxv4f32 = 123, // n x 4 x f32 - nxv8f32 = 124, // n x 8 x f32 - nxv16f32 = 125, // n x 16 x f32 - nxv1f64 = 126, // n x 1 x f64 - nxv2f64 = 127, // n x 2 x f64 - nxv4f64 = 128, // n x 4 x f64 - nxv8f64 = 129, // n x 8 x f64 - - FIRST_FP_SCALABLE_VECTOR_VALUETYPE = nxv2f16, + nxv1f16 = 133, // n x 1 x f16 + nxv2f16 = 134, // n x 2 x f16 + nxv4f16 = 135, // n x 4 x f16 + nxv8f16 = 136, // n x 8 x f16 + nxv16f16 = 137, // n x 16 x f16 + nxv32f16 = 138, // n x 32 x f16 + nxv2bf16 = 139, // n x 2 x bf16 + nxv4bf16 = 140, // n x 4 x bf16 + nxv8bf16 = 141, // n x 8 x bf16 + nxv1f32 = 142, // n x 1 x f32 + nxv2f32 = 143, // n x 2 x f32 + nxv4f32 = 144, // n x 4 x f32 + nxv8f32 = 145, // n x 8 x f32 + nxv16f32 = 146, // n x 16 x f32 + nxv1f64 = 147, // n x 1 x f64 + nxv2f64 = 148, // n x 2 x f64 + nxv4f64 = 149, // n x 4 x f64 + nxv8f64 = 150, // n x 8 x f64 + + FIRST_FP_SCALABLE_VECTOR_VALUETYPE = nxv1f16, LAST_FP_SCALABLE_VECTOR_VALUETYPE = nxv8f64, FIRST_SCALABLE_VECTOR_VALUETYPE = nxv1i1, @@ -207,20 +228,20 @@ namespace llvm { FIRST_VECTOR_VALUETYPE = v1i1, LAST_VECTOR_VALUETYPE = nxv8f64, - x86mmx = 130, // This is an X86 MMX value + x86mmx = 151, // This is an X86 MMX value - Glue = 131, // This glues nodes together during pre-RA sched + Glue = 152, // This glues nodes together during pre-RA sched - isVoid = 132, // This has no value + isVoid = 153, // This has no value - Untyped = 133, // This value takes a register, but has - // unspecified type. The register class - // will be determined by the opcode. + Untyped = 154, // This value takes a register, but has + // unspecified type. The register class + // will be determined by the opcode. - exnref = 134, // WebAssembly's exnref type + exnref = 155, // WebAssembly's exnref type - FIRST_VALUETYPE = 1, // This is always the beginning of the list. - LAST_VALUETYPE = 135, // This always remains at the end of the list. + FIRST_VALUETYPE = 1, // This is always the beginning of the list. + LAST_VALUETYPE = 156, // 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 @@ -332,17 +353,19 @@ namespace llvm { /// 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 (SimpleTy == MVT::v32i1 || SimpleTy == MVT::v4i8 || + SimpleTy == MVT::v2i16 || SimpleTy == MVT::v1i32 || + SimpleTy == MVT::v2f16 || SimpleTy == MVT::v2bf16 || + 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 (SimpleTy == MVT::v64i1 || SimpleTy == MVT::v8i8 || + SimpleTy == MVT::v4i16 || SimpleTy == MVT::v2i32 || + SimpleTy == MVT::v1i64 || SimpleTy == MVT::v4f16 || + SimpleTy == MVT::v4bf16 ||SimpleTy == MVT::v2f32 || + SimpleTy == MVT::v1f64); } /// Return true if this is a 128-bit vector type. @@ -350,44 +373,50 @@ namespace llvm { 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); + SimpleTy == MVT::v8f16 || SimpleTy == MVT::v8bf16 || + SimpleTy == MVT::v4f32 || SimpleTy == MVT::v2f64); } /// Return true if this is a 256-bit vector type. bool is256BitVector() const { - return (SimpleTy == MVT::v16f16 || SimpleTy == MVT::v8f32 || - SimpleTy == MVT::v4f64 || SimpleTy == MVT::v32i8 || - SimpleTy == MVT::v16i16 || SimpleTy == MVT::v8i32 || - SimpleTy == MVT::v4i64 || SimpleTy == MVT::v256i1); + return (SimpleTy == MVT::v16f16 || SimpleTy == MVT::v16bf16 || + SimpleTy == MVT::v8f32 || SimpleTy == MVT::v4f64 || + SimpleTy == MVT::v32i8 || SimpleTy == MVT::v16i16 || + SimpleTy == MVT::v8i32 || SimpleTy == MVT::v4i64 || + SimpleTy == MVT::v256i1); } /// Return true if this is a 512-bit vector type. bool is512BitVector() const { - return (SimpleTy == MVT::v32f16 || SimpleTy == MVT::v16f32 || - SimpleTy == MVT::v8f64 || SimpleTy == MVT::v512i1 || - SimpleTy == MVT::v64i8 || SimpleTy == MVT::v32i16 || - SimpleTy == MVT::v16i32 || SimpleTy == MVT::v8i64); + return (SimpleTy == MVT::v32f16 || SimpleTy == MVT::v32bf16 || + 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); + SimpleTy == MVT::v16i64 || SimpleTy == MVT::v64f16 || + SimpleTy == MVT::v32f32 || SimpleTy == MVT::v16f64 || + SimpleTy == MVT::v64bf16); } /// 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 (SimpleTy == MVT::v256i8 || SimpleTy == MVT::v128i16 || + SimpleTy == MVT::v64i32 || SimpleTy == MVT::v32i64 || + SimpleTy == MVT::v128f16 || SimpleTy == MVT::v64f32 || + SimpleTy == MVT::v32f64 || SimpleTy == MVT::v128bf16); } /// 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); + return (SimpleTy == MVT::Any || SimpleTy == MVT::iAny || + SimpleTy == MVT::fAny || SimpleTy == MVT::vAny || + SimpleTy == MVT::iPTRAny); } /// Return a VT for a vector type with the same element type but @@ -441,7 +470,8 @@ namespace llvm { case nxv4i1: case nxv8i1: case nxv16i1: - case nxv32i1: return i1; + case nxv32i1: + case nxv64i1: return i1; case v1i8: case v2i8: case v4i8: @@ -456,7 +486,8 @@ namespace llvm { case nxv4i8: case nxv8i8: case nxv16i8: - case nxv32i8: return i8; + case nxv32i8: + case nxv64i8: return i8; case v1i16: case v2i16: case v3i16: @@ -511,9 +542,25 @@ namespace llvm { case v8f16: case v16f16: case v32f16: + case v64f16: + case v128f16: + case nxv1f16: case nxv2f16: case nxv4f16: - case nxv8f16: return f16; + case nxv8f16: + case nxv16f16: + case nxv32f16: return f16; + case v2bf16: + case v3bf16: + case v4bf16: + case v8bf16: + case v16bf16: + case v32bf16: + case v64bf16: + case v128bf16: + case nxv2bf16: + case nxv4bf16: + case nxv8bf16: return bf16; case v1f32: case v2f32: case v3f32: @@ -537,6 +584,8 @@ namespace llvm { case v2f64: case v4f64: case v8f64: + case v16f64: + case v32f64: case nxv1f64: case nxv2f64: case nxv4f64: @@ -564,36 +613,48 @@ namespace llvm { case v128i8: case v128i16: case v128i32: + case v128f16: + case v128bf16: case v128f32: return 128; case v64i1: case v64i8: case v64i16: case v64i32: - case v64f32: return 64; + case v64f16: + case v64bf16: + case v64f32: + case nxv64i1: + case nxv64i8: return 64; case v32i1: case v32i8: case v32i16: case v32i32: case v32i64: case v32f16: + case v32bf16: case v32f32: + case v32f64: case nxv32i1: case nxv32i8: case nxv32i16: case nxv32i32: - case nxv32i64: return 32; + case nxv32i64: + case nxv32f16: return 32; case v16i1: case v16i8: case v16i16: case v16i32: case v16i64: case v16f16: + case v16bf16: case v16f32: + case v16f64: case nxv16i1: case nxv16i8: case nxv16i16: case nxv16i32: case nxv16i64: + case nxv16f16: case nxv16f32: return 16; case v8i1: case v8i8: @@ -601,6 +662,7 @@ namespace llvm { case v8i32: case v8i64: case v8f16: + case v8bf16: case v8f32: case v8f64: case nxv8i1: @@ -609,6 +671,7 @@ namespace llvm { case nxv8i32: case nxv8i64: case nxv8f16: + case nxv8bf16: case nxv8f32: case nxv8f64: return 8; case v5i32: @@ -619,6 +682,7 @@ namespace llvm { case v4i32: case v4i64: case v4f16: + case v4bf16: case v4f32: case v4f64: case nxv4i1: @@ -627,11 +691,13 @@ namespace llvm { case nxv4i32: case nxv4i64: case nxv4f16: + case nxv4bf16: case nxv4f32: case nxv4f64: return 4; case v3i16: case v3i32: case v3f16: + case v3bf16: case v3f32: return 3; case v2i1: case v2i8: @@ -639,6 +705,7 @@ namespace llvm { case v2i32: case v2i64: case v2f16: + case v2bf16: case v2f32: case v2f64: case nxv2i1: @@ -647,6 +714,7 @@ namespace llvm { case nxv2i32: case nxv2i64: case nxv2f16: + case nxv2bf16: case nxv2f32: case nxv2f64: return 2; case v1i1: @@ -662,6 +730,7 @@ namespace llvm { case nxv1i16: case nxv1i32: case nxv1i64: + case nxv1f16: case nxv1f32: case nxv1f64: return 1; } @@ -671,6 +740,11 @@ namespace llvm { return { getVectorNumElements(), isScalableVector() }; } + /// Given a vector type, return the minimum number of elements it contains. + unsigned getVectorMinNumElements() const { + return getVectorElementCount().Min; + } + /// Returns the size of the specified MVT in bits. /// /// If the value type is a scalable vector type, the scalable property will @@ -709,18 +783,21 @@ namespace llvm { case nxv8i1: return TypeSize::Scalable(8); case i16 : case f16: + case bf16: case v16i1: case v2i8: case v1i16: return TypeSize::Fixed(16); case nxv16i1: case nxv2i8: - case nxv1i16: return TypeSize::Scalable(16); + case nxv1i16: + case nxv1f16: return TypeSize::Scalable(16); case f32 : case i32 : case v32i1: case v4i8: case v2i16: case v2f16: + case v2bf16: case v1f32: case v1i32: return TypeSize::Fixed(32); case nxv32i1: @@ -728,9 +805,11 @@ namespace llvm { case nxv2i16: case nxv1i32: case nxv2f16: + case nxv2bf16: case nxv1f32: return TypeSize::Scalable(32); case v3i16: - case v3f16: return TypeSize::Fixed(48); + case v3f16: + case v3bf16: return TypeSize::Fixed(48); case x86mmx: case f64 : case i64 : @@ -740,13 +819,16 @@ namespace llvm { case v2i32: case v1i64: case v4f16: + case v4bf16: case v2f32: case v1f64: return TypeSize::Fixed(64); + case nxv64i1: case nxv8i8: case nxv4i16: case nxv2i32: case nxv1i64: case nxv4f16: + case nxv4bf16: case nxv2f32: case nxv1f64: return TypeSize::Scalable(64); case f80 : return TypeSize::Fixed(80); @@ -762,6 +844,7 @@ namespace llvm { case v2i64: case v1i128: case v8f16: + case v8bf16: case v4f32: case v2f64: return TypeSize::Fixed(128); case nxv16i8: @@ -769,6 +852,7 @@ namespace llvm { case nxv4i32: case nxv2i64: case nxv8f16: + case nxv8bf16: case nxv4f32: case nxv2f64: return TypeSize::Scalable(128); case v5i32: @@ -779,12 +863,14 @@ namespace llvm { case v8i32: case v4i64: case v16f16: + case v16bf16: case v8f32: case v4f64: return TypeSize::Fixed(256); case nxv32i8: case nxv16i16: case nxv8i32: case nxv4i64: + case nxv16f16: case nxv8f32: case nxv4f64: return TypeSize::Scalable(256); case v512i1: @@ -793,11 +879,14 @@ namespace llvm { case v16i32: case v8i64: case v32f16: + case v32bf16: case v16f32: case v8f64: return TypeSize::Fixed(512); + case nxv64i8: case nxv32i16: case nxv16i32: case nxv8i64: + case nxv32f16: case nxv16f32: case nxv8f64: return TypeSize::Scalable(512); case v1024i1: @@ -805,14 +894,20 @@ namespace llvm { case v64i16: case v32i32: case v16i64: - case v32f32: return TypeSize::Fixed(1024); + case v64f16: + case v64bf16: + case v32f32: + case v16f64: return TypeSize::Fixed(1024); case nxv32i32: case nxv16i64: return TypeSize::Scalable(1024); case v256i8: case v128i16: case v64i32: case v32i64: - case v64f32: return TypeSize::Fixed(2048); + case v128f16: + case v128bf16: + case v64f32: + case v32f64: return TypeSize::Fixed(2048); case nxv32i64: return TypeSize::Scalable(2048); case v128i32: case v128f32: return TypeSize::Fixed(4096); @@ -982,12 +1077,24 @@ namespace llvm { if (NumElements == 1) return MVT::v1i128; break; case MVT::f16: - if (NumElements == 2) return MVT::v2f16; - if (NumElements == 3) return MVT::v3f16; - if (NumElements == 4) return MVT::v4f16; - if (NumElements == 8) return MVT::v8f16; - if (NumElements == 16) return MVT::v16f16; - if (NumElements == 32) return MVT::v32f16; + if (NumElements == 2) return MVT::v2f16; + if (NumElements == 3) return MVT::v3f16; + if (NumElements == 4) return MVT::v4f16; + if (NumElements == 8) return MVT::v8f16; + if (NumElements == 16) return MVT::v16f16; + if (NumElements == 32) return MVT::v32f16; + if (NumElements == 64) return MVT::v64f16; + if (NumElements == 128) return MVT::v128f16; + break; + case MVT::bf16: + if (NumElements == 2) return MVT::v2bf16; + if (NumElements == 3) return MVT::v3bf16; + if (NumElements == 4) return MVT::v4bf16; + if (NumElements == 8) return MVT::v8bf16; + if (NumElements == 16) return MVT::v16bf16; + if (NumElements == 32) return MVT::v32bf16; + if (NumElements == 64) return MVT::v64bf16; + if (NumElements == 128) return MVT::v128bf16; break; case MVT::f32: if (NumElements == 1) return MVT::v1f32; @@ -1010,6 +1117,8 @@ namespace llvm { if (NumElements == 2) return MVT::v2f64; if (NumElements == 4) return MVT::v4f64; if (NumElements == 8) return MVT::v8f64; + if (NumElements == 16) return MVT::v16f64; + if (NumElements == 32) return MVT::v32f64; break; } return (MVT::SimpleValueType)(MVT::INVALID_SIMPLE_VALUE_TYPE); @@ -1026,6 +1135,7 @@ namespace llvm { if (NumElements == 8) return MVT::nxv8i1; if (NumElements == 16) return MVT::nxv16i1; if (NumElements == 32) return MVT::nxv32i1; + if (NumElements == 64) return MVT::nxv64i1; break; case MVT::i8: if (NumElements == 1) return MVT::nxv1i8; @@ -1034,6 +1144,7 @@ namespace llvm { if (NumElements == 8) return MVT::nxv8i8; if (NumElements == 16) return MVT::nxv16i8; if (NumElements == 32) return MVT::nxv32i8; + if (NumElements == 64) return MVT::nxv64i8; break; case MVT::i16: if (NumElements == 1) return MVT::nxv1i16; @@ -1060,9 +1171,17 @@ namespace llvm { if (NumElements == 32) return MVT::nxv32i64; break; case MVT::f16: + if (NumElements == 1) return MVT::nxv1f16; if (NumElements == 2) return MVT::nxv2f16; if (NumElements == 4) return MVT::nxv4f16; if (NumElements == 8) return MVT::nxv8f16; + if (NumElements == 16) return MVT::nxv16f16; + if (NumElements == 32) return MVT::nxv32f16; + break; + case MVT::bf16: + if (NumElements == 2) return MVT::nxv2bf16; + if (NumElements == 4) return MVT::nxv4bf16; + if (NumElements == 8) return MVT::nxv8bf16; break; case MVT::f32: if (NumElements == 1) return MVT::nxv1f32; diff --git a/llvm/include/llvm/Support/ManagedStatic.h b/llvm/include/llvm/Support/ManagedStatic.h index e65bb051f1818..f2b41422f1315 100644 --- a/llvm/include/llvm/Support/ManagedStatic.h +++ b/llvm/include/llvm/Support/ManagedStatic.h @@ -40,8 +40,8 @@ template <typename T, size_t N> struct object_deleter<T[N]> { // constexpr, a dynamic initializer may be emitted depending on optimization // settings. For the affected versions of MSVC, use the old linker // initialization pattern of not providing a constructor and leaving the fields -// uninitialized. -#if !defined(_MSC_VER) || defined(__clang__) +// uninitialized. See http://llvm.org/PR41367 for details. +#if !defined(_MSC_VER) || (_MSC_VER >= 1925) || defined(__clang__) #define LLVM_USE_CONSTEXPR_CTOR #endif @@ -102,6 +102,12 @@ public: } const C *operator->() const { return &**this; } + + // Extract the instance, leaving the ManagedStatic uninitialized. The + // user is then responsible for the lifetime of the returned instance. + C *claim() { + return static_cast<C *>(Ptr.exchange(nullptr)); + } }; /// llvm_shutdown - Deallocate and destroy all ManagedStatic variables. diff --git a/llvm/include/llvm/Support/MathExtras.h b/llvm/include/llvm/Support/MathExtras.h index 37b9669cbeed9..16da3046c8ced 100644 --- a/llvm/include/llvm/Support/MathExtras.h +++ b/llvm/include/llvm/Support/MathExtras.h @@ -14,10 +14,11 @@ #define LLVM_SUPPORT_MATHEXTRAS_H #include "llvm/Support/Compiler.h" -#include "llvm/Support/SwapByteOrder.h" #include <algorithm> #include <cassert> #include <climits> +#include <cmath> +#include <cstdint> #include <cstring> #include <limits> #include <type_traits> @@ -312,6 +313,34 @@ T reverseBits(T Val) { return Val; } +#if __has_builtin(__builtin_bitreverse8) +template<> +inline uint8_t reverseBits<uint8_t>(uint8_t Val) { + return __builtin_bitreverse8(Val); +} +#endif + +#if __has_builtin(__builtin_bitreverse16) +template<> +inline uint16_t reverseBits<uint16_t>(uint16_t Val) { + return __builtin_bitreverse16(Val); +} +#endif + +#if __has_builtin(__builtin_bitreverse32) +template<> +inline uint32_t reverseBits<uint32_t>(uint32_t Val) { + return __builtin_bitreverse32(Val); +} +#endif + +#if __has_builtin(__builtin_bitreverse64) +template<> +inline uint64_t reverseBits<uint64_t>(uint64_t Val) { + return __builtin_bitreverse64(Val); +} +#endif + // NOTE: The following support functions use the _32/_64 extensions instead of // type overloading so that signed and unsigned integers can be used without // ambiguity. @@ -364,14 +393,12 @@ constexpr inline bool isShiftedInt(int64_t x) { /// to keep MSVC from (incorrectly) warning on isUInt<64> that we're shifting /// left too many places. template <unsigned N> -constexpr inline typename std::enable_if<(N < 64), bool>::type -isUInt(uint64_t X) { +constexpr inline std::enable_if_t<(N < 64), bool> isUInt(uint64_t X) { static_assert(N > 0, "isUInt<0> doesn't make sense"); return X < (UINT64_C(1) << (N)); } template <unsigned N> -constexpr inline typename std::enable_if<N >= 64, bool>::type -isUInt(uint64_t X) { +constexpr inline std::enable_if_t<N >= 64, bool> isUInt(uint64_t X) { return true; } @@ -471,21 +498,6 @@ constexpr inline bool isPowerOf2_64(uint64_t Value) { return Value && !(Value & (Value - 1)); } -/// Return a byte-swapped representation of the 16-bit argument. -inline uint16_t ByteSwap_16(uint16_t Value) { - return sys::SwapByteOrder_16(Value); -} - -/// Return a byte-swapped representation of the 32-bit argument. -inline uint32_t ByteSwap_32(uint32_t Value) { - return sys::SwapByteOrder_32(Value); -} - -/// Return a byte-swapped representation of the 64-bit argument. -inline uint64_t ByteSwap_64(uint64_t Value) { - return sys::SwapByteOrder_64(Value); -} - /// Count the number of ones from the most significant bit to the first /// zero bit. /// @@ -780,8 +792,7 @@ inline int64_t SignExtend64(uint64_t X, unsigned B) { /// Subtract two unsigned integers, X and Y, of type T and return the absolute /// value of the result. template <typename T> -typename std::enable_if<std::is_unsigned<T>::value, T>::type -AbsoluteDifference(T X, T Y) { +std::enable_if_t<std::is_unsigned<T>::value, T> AbsoluteDifference(T X, T Y) { return std::max(X, Y) - std::min(X, Y); } @@ -789,7 +800,7 @@ AbsoluteDifference(T X, T Y) { /// maximum representable value of T on overflow. ResultOverflowed indicates if /// the result is larger than the maximum representable value of type T. template <typename T> -typename std::enable_if<std::is_unsigned<T>::value, T>::type +std::enable_if_t<std::is_unsigned<T>::value, T> SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) { bool Dummy; bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy; @@ -806,7 +817,7 @@ SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) { /// maximum representable value of T on overflow. ResultOverflowed indicates if /// the result is larger than the maximum representable value of type T. template <typename T> -typename std::enable_if<std::is_unsigned<T>::value, T>::type +std::enable_if_t<std::is_unsigned<T>::value, T> SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) { bool Dummy; bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy; @@ -852,7 +863,7 @@ SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) { /// overflow. ResultOverflowed indicates if the result is larger than the /// maximum representable value of type T. template <typename T> -typename std::enable_if<std::is_unsigned<T>::value, T>::type +std::enable_if_t<std::is_unsigned<T>::value, T> SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) { bool Dummy; bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy; @@ -871,13 +882,12 @@ extern const float huge_valf; /// Add two signed integers, computing the two's complement truncated result, /// returning true if overflow occured. template <typename T> -typename std::enable_if<std::is_signed<T>::value, T>::type -AddOverflow(T X, T Y, T &Result) { +std::enable_if_t<std::is_signed<T>::value, T> AddOverflow(T X, T Y, T &Result) { #if __has_builtin(__builtin_add_overflow) return __builtin_add_overflow(X, Y, &Result); #else // Perform the unsigned addition. - using U = typename std::make_unsigned<T>::type; + using U = std::make_unsigned_t<T>; const U UX = static_cast<U>(X); const U UY = static_cast<U>(Y); const U UResult = UX + UY; @@ -898,13 +908,12 @@ AddOverflow(T X, T Y, T &Result) { /// Subtract two signed integers, computing the two's complement truncated /// result, returning true if an overflow ocurred. template <typename T> -typename std::enable_if<std::is_signed<T>::value, T>::type -SubOverflow(T X, T Y, T &Result) { +std::enable_if_t<std::is_signed<T>::value, T> SubOverflow(T X, T Y, T &Result) { #if __has_builtin(__builtin_sub_overflow) return __builtin_sub_overflow(X, Y, &Result); #else // Perform the unsigned addition. - using U = typename std::make_unsigned<T>::type; + using U = std::make_unsigned_t<T>; const U UX = static_cast<U>(X); const U UY = static_cast<U>(Y); const U UResult = UX - UY; @@ -922,14 +931,12 @@ SubOverflow(T X, T Y, T &Result) { #endif } - /// Multiply two signed integers, computing the two's complement truncated /// result, returning true if an overflow ocurred. template <typename T> -typename std::enable_if<std::is_signed<T>::value, T>::type -MulOverflow(T X, T Y, T &Result) { +std::enable_if_t<std::is_signed<T>::value, T> MulOverflow(T X, T Y, T &Result) { // Perform the unsigned multiplication on absolute values. - using U = typename std::make_unsigned<T>::type; + using U = std::make_unsigned_t<T>; const U UX = X < 0 ? (0 - static_cast<U>(X)) : static_cast<U>(X); const U UY = Y < 0 ? (0 - static_cast<U>(Y)) : static_cast<U>(Y); const U UResult = UX * UY; diff --git a/llvm/include/llvm/Support/MemAlloc.h b/llvm/include/llvm/Support/MemAlloc.h index 0e5869141fd3d..d6012bd5a6985 100644 --- a/llvm/include/llvm/Support/MemAlloc.h +++ b/llvm/include/llvm/Support/MemAlloc.h @@ -62,5 +62,26 @@ LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_realloc(void *Ptr, size_t Sz) { return Result; } -} +/// 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. +LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void * +allocate_buffer(size_t Size, size_t Alignment); + +/// 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. +void deallocate_buffer(void *Ptr, size_t Size, size_t Alignment); + +} // namespace llvm #endif diff --git a/llvm/include/llvm/Support/MemoryBuffer.h b/llvm/include/llvm/Support/MemoryBuffer.h index b5196cd84cb47..f47a8d2d334be 100644 --- a/llvm/include/llvm/Support/MemoryBuffer.h +++ b/llvm/include/llvm/Support/MemoryBuffer.h @@ -19,7 +19,6 @@ #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> @@ -28,6 +27,18 @@ namespace llvm { class MemoryBufferRef; +namespace sys { +namespace fs { +// Duplicated from FileSystem.h to avoid a dependency. +#if defined(_WIN32) +// A Win32 HANDLE is a typedef of void* +using file_t = void *; +#else +using file_t = int; +#endif +} // namespace fs +} // namespace sys + /// This interface provides simple read-only access to a block of memory, and /// provides simple methods for reading files and standard input into a memory /// buffer. In addition to basic access to the characters in the file, this @@ -48,9 +59,6 @@ protected: void init(const char *BufStart, const char *BufEnd, bool RequiresNullTerminator); - static constexpr sys::fs::mapped_file_region::mapmode Mapmode = - sys::fs::mapped_file_region::readonly; - public: MemoryBuffer(const MemoryBuffer &) = delete; MemoryBuffer &operator=(const MemoryBuffer &) = delete; @@ -156,9 +164,6 @@ class WritableMemoryBuffer : public MemoryBuffer { protected: WritableMemoryBuffer() = default; - static constexpr sys::fs::mapped_file_region::mapmode Mapmode = - sys::fs::mapped_file_region::priv; - public: using MemoryBuffer::getBuffer; using MemoryBuffer::getBufferEnd; @@ -218,9 +223,6 @@ 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; diff --git a/llvm/include/llvm/Support/NativeFormatting.h b/llvm/include/llvm/Support/NativeFormatting.h index 825a44c77c001..e664d05f24dbd 100644 --- a/llvm/include/llvm/Support/NativeFormatting.h +++ b/llvm/include/llvm/Support/NativeFormatting.h @@ -10,11 +10,10 @@ #define LLVM_SUPPORT_NATIVE_FORMATTING_H #include "llvm/ADT/Optional.h" -#include "llvm/Support/raw_ostream.h" - #include <cstdint> namespace llvm { +class raw_ostream; enum class FloatStyle { Exponent, ExponentUpper, Fixed, Percent }; enum class IntegerStyle { Integer, diff --git a/llvm/include/llvm/Support/OptimizedStructLayout.h b/llvm/include/llvm/Support/OptimizedStructLayout.h new file mode 100644 index 0000000000000..773ddfeaf13a9 --- /dev/null +++ b/llvm/include/llvm/Support/OptimizedStructLayout.h @@ -0,0 +1,142 @@ +//===-- OptimizedStructLayout.h - Struct layout algorithm ---------*- C++ -*-=// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// This file provides an interface for laying out a sequence of fields +/// as a struct in a way that attempts to minimizes the total space +/// requirements of the struct while still satisfying the layout +/// requirements of the individual fields. The resulting layout may be +/// substantially more compact than simply laying out the fields in their +/// original order. +/// +/// Fields may be pre-assigned fixed offsets. They may also be given sizes +/// that are not multiples of their alignments. There is no currently no +/// way to describe that a field has interior padding that other fields may +/// be allocated into. +/// +/// This algorithm does not claim to be "optimal" for several reasons: +/// +/// - First, it does not guarantee that the result is minimal in size. +/// There is no known efficient algoorithm to achieve minimality for +/// unrestricted inputs. Nonetheless, this algorithm +/// +/// - Second, there are other ways that a struct layout could be optimized +/// besides space usage, such as locality. This layout may have a mixed +/// impact on locality: less overall memory may be used, but adjacent +/// fields in the original array may be moved further from one another. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_OPTIMIZEDSTRUCTLAYOUT_H +#define LLVM_SUPPORT_OPTIMIZEDSTRUCTLAYOUT_H + +#include "llvm/Support/Alignment.h" +#include "llvm/ADT/ArrayRef.h" +#include <utility> + +namespace llvm { + +/// A field in a structure. +struct OptimizedStructLayoutField { + /// A special value for Offset indicating that the field can be moved + /// anywhere. + static constexpr uint64_t FlexibleOffset = ~(uint64_t)0; + + OptimizedStructLayoutField(const void *Id, uint64_t Size, Align Alignment, + uint64_t FixedOffset = FlexibleOffset) + : Offset(FixedOffset), Size(Size), Id(Id), Alignment(Alignment) { + assert(Size > 0 && "adding an empty field to the layout"); + } + + /// The offset of this field in the final layout. If this is + /// initialized to FlexibleOffset, layout will overwrite it with + /// the assigned offset of the field. + uint64_t Offset; + + /// The required size of this field in bytes. Does not have to be + /// a multiple of Alignment. Must be non-zero. + uint64_t Size; + + /// A opaque value which uniquely identifies this field. + const void *Id; + + /// Private scratch space for the algorithm. The implementation + /// must treat this as uninitialized memory on entry. + void *Scratch; + + /// The required alignment of this field. + Align Alignment; + + /// Return true if this field has been assigned a fixed offset. + /// After layout, this will be true of all the fields. + bool hasFixedOffset() const { + return (Offset != FlexibleOffset); + } + + /// Given that this field has a fixed offset, return the offset + /// of the first byte following it. + uint64_t getEndOffset() const { + assert(hasFixedOffset()); + return Offset + Size; + } +}; + +/// Compute a layout for a struct containing the given fields, making a +/// best-effort attempt to minimize the amount of space required. +/// +/// Two features are supported which require a more careful solution +/// than the well-known "sort by decreasing alignment" solution: +/// +/// - Fields may be assigned a fixed offset in the layout. If there are +/// gaps among the fixed-offset fields, the algorithm may attempt +/// to allocate flexible-offset fields into those gaps. If that's +/// undesirable, the caller should "block out" those gaps by e.g. +/// just creating a single fixed-offset field that represents the +/// entire "header". +/// +/// - The size of a field is not required to be a multiple of, or even +/// greater than, the field's required alignment. The only constraint +/// on fields is that they must not be zero-sized. +/// +/// To simplify the implementation, any fixed-offset fields in the +/// layout must appear at the start of the field array, and they must +/// be ordered by increasing offset. +/// +/// The algorithm will produce a guaranteed-minimal layout with no +/// interior padding in the following "C-style" case: +/// +/// - every field's size is a multiple of its required alignment and +/// - either no fields have initially fixed offsets, or the fixed-offset +/// fields have no interior padding and end at an offset that is at +/// least as aligned as all the flexible-offset fields. +/// +/// Otherwise, while the algorithm will make a best-effort attempt to +/// avoid padding, it cannot guarantee a minimal layout, as there is +/// no known efficient algorithm for doing so. +/// +/// The layout produced by this algorithm may not be stable across LLVM +/// releases. Do not use this anywhere where ABI stability is required. +/// +/// Flexible-offset fields with the same size and alignment will be ordered +/// the same way they were in the initial array. Otherwise the current +/// algorithm makes no effort to preserve the initial order of +/// flexible-offset fields. +/// +/// On return, all fields will have been assigned a fixed offset, and the +/// array will be sorted in order of ascending offsets. Note that this +/// means that the fixed-offset fields may no longer form a strict prefix +/// if there's any padding before they end. +/// +/// The return value is the total size of the struct and its required +/// alignment. Note that the total size is not rounded up to a multiple +/// of the required alignment; clients which require this can do so easily. +std::pair<uint64_t, Align> performOptimizedStructLayout( + MutableArrayRef<OptimizedStructLayoutField> Fields); + +} // namespace llvm + +#endif diff --git a/llvm/include/llvm/Support/Parallel.h b/llvm/include/llvm/Support/Parallel.h index 3c0ed2c111275..2c0edfbb1db5b 100644 --- a/llvm/include/llvm/Support/Parallel.h +++ b/llvm/include/llvm/Support/Parallel.h @@ -12,6 +12,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Config/llvm-config.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/Threading.h" #include <algorithm> #include <condition_variable> @@ -21,17 +22,11 @@ namespace llvm { namespace parallel { -struct sequential_execution_policy {}; -struct parallel_execution_policy {}; -template <typename T> -struct is_execution_policy - : public std::integral_constant< - bool, llvm::is_one_of<T, sequential_execution_policy, - parallel_execution_policy>::value> {}; - -constexpr sequential_execution_policy seq{}; -constexpr parallel_execution_policy par{}; +// Strategy for the default executor used by the parallel routines provided by +// this file. It defaults to using all hardware threads and should be +// initialized before the first use of parallel routines. +extern ThreadPoolStrategy strategy; namespace detail { @@ -163,61 +158,58 @@ void parallel_for_each_n(IndexTy Begin, IndexTy End, FuncTy Fn) { #endif -template <typename Iter> -using DefComparator = - std::less<typename std::iterator_traits<Iter>::value_type>; - } // namespace detail +} // namespace parallel -// sequential algorithm implementations. -template <class Policy, class RandomAccessIterator, - class Comparator = detail::DefComparator<RandomAccessIterator>> -void sort(Policy policy, RandomAccessIterator Start, RandomAccessIterator End, - const Comparator &Comp = Comparator()) { - static_assert(is_execution_policy<Policy>::value, - "Invalid execution policy!"); +template <class RandomAccessIterator, + class Comparator = std::less< + typename std::iterator_traits<RandomAccessIterator>::value_type>> +void parallelSort(RandomAccessIterator Start, RandomAccessIterator End, + const Comparator &Comp = Comparator()) { +#if LLVM_ENABLE_THREADS + if (parallel::strategy.ThreadsRequested != 1) { + parallel::detail::parallel_sort(Start, End, Comp); + return; + } +#endif llvm::sort(Start, End, Comp); } -template <class Policy, class IterTy, class FuncTy> -void for_each(Policy policy, IterTy Begin, IterTy End, FuncTy Fn) { - static_assert(is_execution_policy<Policy>::value, - "Invalid execution policy!"); +template <class IterTy, class FuncTy> +void parallelForEach(IterTy Begin, IterTy End, FuncTy Fn) { +#if LLVM_ENABLE_THREADS + if (parallel::strategy.ThreadsRequested != 1) { + parallel::detail::parallel_for_each(Begin, End, Fn); + return; + } +#endif std::for_each(Begin, End, Fn); } -template <class Policy, class IndexTy, class FuncTy> -void for_each_n(Policy policy, IndexTy Begin, IndexTy End, FuncTy Fn) { - static_assert(is_execution_policy<Policy>::value, - "Invalid execution policy!"); - for (IndexTy I = Begin; I != End; ++I) - Fn(I); -} - -// Parallel algorithm implementations, only available when LLVM_ENABLE_THREADS -// is true. +template <class FuncTy> +void parallelForEachN(size_t Begin, size_t End, FuncTy Fn) { #if LLVM_ENABLE_THREADS -template <class RandomAccessIterator, - class Comparator = detail::DefComparator<RandomAccessIterator>> -void sort(parallel_execution_policy policy, RandomAccessIterator Start, - RandomAccessIterator End, const Comparator &Comp = Comparator()) { - detail::parallel_sort(Start, End, Comp); + if (parallel::strategy.ThreadsRequested != 1) { + parallel::detail::parallel_for_each_n(Begin, End, Fn); + return; + } +#endif + for (size_t I = Begin; I != End; ++I) + Fn(I); } -template <class IterTy, class FuncTy> -void for_each(parallel_execution_policy policy, IterTy Begin, IterTy End, - FuncTy Fn) { - detail::parallel_for_each(Begin, End, Fn); +// Range wrappers. +template <class RangeTy, + class Comparator = std::less<decltype(*std::begin(RangeTy()))>> +void parallelSort(RangeTy &&R, const Comparator &Comp = Comparator()) { + parallelSort(std::begin(R), std::end(R), Comp); } -template <class IndexTy, class FuncTy> -void for_each_n(parallel_execution_policy policy, IndexTy Begin, IndexTy End, - FuncTy Fn) { - detail::parallel_for_each_n(Begin, End, Fn); +template <class RangeTy, class FuncTy> +void parallelForEach(RangeTy &&R, FuncTy Fn) { + parallelForEach(std::begin(R), std::end(R), Fn); } -#endif -} // namespace parallel } // namespace llvm #endif // LLVM_SUPPORT_PARALLEL_H diff --git a/llvm/include/llvm/Support/Path.h b/llvm/include/llvm/Support/Path.h index 97955f882d51e..83bca5b70bc21 100644 --- a/llvm/include/llvm/Support/Path.h +++ b/llvm/include/llvm/Support/Path.h @@ -47,7 +47,7 @@ enum class Style { windows, posix, native }; /// foo/ => foo,. /// /foo/bar => /,foo,bar /// ../ => ..,. -/// C:\foo\bar => C:,/,foo,bar +/// C:\foo\bar => C:,\,foo,bar /// @endcode class const_iterator : public iterator_facade_base<const_iterator, std::input_iterator_tag, @@ -153,32 +153,26 @@ void replace_extension(SmallVectorImpl<char> &path, const Twine &extension, /// @code /// /foo, /old, /new => /foo /// /old, /old, /new => /new -/// /old, /old/, /new, false => /old -/// /old, /old/, /new, true => /new +/// /old, /old/, /new => /old /// /old/foo, /old, /new => /new/foo /// /old/foo, /old/, /new => /new/foo /// /old/foo, /old/, /new/ => /new/foo /// /oldfoo, /old, /new => /oldfoo /// /foo, <empty>, /new => /new/foo /// /foo, <empty>, new => new/foo -/// /old/foo, /old, <empty>, false => /foo -/// /old/foo, /old, <empty>, true => foo +/// /old/foo, /old, <empty> => /foo /// @endcode /// /// @param Path If \a Path starts with \a OldPrefix modify to instead /// start with \a NewPrefix. -/// @param OldPrefix The path prefix to strip from \a Path. Any trailing -/// path separator is ignored if strict is true. +/// @param OldPrefix The path prefix to strip from \a Path. /// @param NewPrefix The path prefix to replace \a NewPrefix with. -/// @param style The path separator style -/// @param strict If strict is true, a directory separator following -/// \a OldPrefix will also be stripped. Otherwise, directory -/// separators will only be matched and stripped when present -/// in \a OldPrefix. +/// @param style The style used to match the prefix. Exact match using +/// Posix style, case/separator insensitive match for Windows style. /// @result true if \a Path begins with OldPrefix -bool replace_path_prefix(SmallVectorImpl<char> &Path, - const StringRef &OldPrefix, const StringRef &NewPrefix, - Style style = Style::native, bool strict = false); +bool replace_path_prefix(SmallVectorImpl<char> &Path, StringRef OldPrefix, + StringRef NewPrefix, + Style style = Style::native); /// Append to path. /// @@ -377,6 +371,20 @@ void system_temp_directory(bool erasedOnReboot, SmallVectorImpl<char> &result); /// @result True if a home directory is set, false otherwise. bool home_directory(SmallVectorImpl<char> &result); +/// Get the directory where packages should read user-specific configurations. +/// e.g. $XDG_CONFIG_HOME. +/// +/// @param result Holds the resulting path name. +/// @result True if the appropriate path was determined, it need not exist. +bool user_config_directory(SmallVectorImpl<char> &result); + +/// Get the directory where installed packages should put their +/// machine-local cache, e.g. $XDG_CACHE_HOME. +/// +/// @param result Holds the resulting path name. +/// @result True if the appropriate path was determined, it need not exist. +bool cache_directory(SmallVectorImpl<char> &result); + /// Has root name? /// /// root_name != "" @@ -468,10 +476,6 @@ 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/llvm/include/llvm/Support/PointerLikeTypeTraits.h b/llvm/include/llvm/Support/PointerLikeTypeTraits.h index 1e7e5b53ca657..1b15f930bd87d 100644 --- a/llvm/include/llvm/Support/PointerLikeTypeTraits.h +++ b/llvm/include/llvm/Support/PointerLikeTypeTraits.h @@ -15,7 +15,7 @@ #define LLVM_SUPPORT_POINTERLIKETYPETRAITS_H #include "llvm/Support/DataTypes.h" -#include <assert.h> +#include <cassert> #include <type_traits> namespace llvm { @@ -37,8 +37,9 @@ template <typename T, typename U = void> struct HasPointerLikeTypeTraits { }; // sizeof(T) is valid only for a complete T. -template <typename T> struct HasPointerLikeTypeTraits< - T, decltype((sizeof(PointerLikeTypeTraits<T>) + sizeof(T)), void())> { +template <typename T> +struct HasPointerLikeTypeTraits< + T, decltype((sizeof(PointerLikeTypeTraits<T>) + sizeof(T)), void())> { static const bool value = true; }; @@ -56,7 +57,8 @@ template <typename T> struct PointerLikeTypeTraits<T *> { static inline void *getAsVoidPointer(T *P) { return P; } static inline T *getFromVoidPointer(void *P) { return static_cast<T *>(P); } - enum { NumLowBitsAvailable = detail::ConstantLog2<alignof(T)>::value }; + static constexpr int NumLowBitsAvailable = + detail::ConstantLog2<alignof(T)>::value; }; template <> struct PointerLikeTypeTraits<void *> { @@ -70,7 +72,7 @@ template <> struct PointerLikeTypeTraits<void *> { /// /// All clients should use assertions to do a run-time check to ensure that /// this is actually true. - enum { NumLowBitsAvailable = 2 }; + static constexpr int NumLowBitsAvailable = 2; }; // Provide PointerLikeTypeTraits for const things. @@ -83,7 +85,7 @@ template <typename T> struct PointerLikeTypeTraits<const T> { static inline const T getFromVoidPointer(const void *P) { return NonConst::getFromVoidPointer(const_cast<void *>(P)); } - enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable }; + static constexpr int NumLowBitsAvailable = NonConst::NumLowBitsAvailable; }; // Provide PointerLikeTypeTraits for const pointers. @@ -96,7 +98,7 @@ template <typename T> struct PointerLikeTypeTraits<const T *> { static inline const T *getFromVoidPointer(const void *P) { return NonConst::getFromVoidPointer(const_cast<void *>(P)); } - enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable }; + static constexpr int NumLowBitsAvailable = NonConst::NumLowBitsAvailable; }; // Provide PointerLikeTypeTraits for uintptr_t. @@ -108,7 +110,7 @@ template <> struct PointerLikeTypeTraits<uintptr_t> { return reinterpret_cast<uintptr_t>(P); } // No bits are available! - enum { NumLowBitsAvailable = 0 }; + static constexpr int NumLowBitsAvailable = 0; }; /// Provide suitable custom traits struct for function pointers. @@ -121,7 +123,8 @@ template <> struct PointerLikeTypeTraits<uintptr_t> { /// potentially use alignment attributes on functions to satisfy that. template <int Alignment, typename FunctionPointerT> struct FunctionPointerLikeTypeTraits { - enum { NumLowBitsAvailable = detail::ConstantLog2<Alignment>::value }; + static constexpr int NumLowBitsAvailable = + detail::ConstantLog2<Alignment>::value; static inline void *getAsVoidPointer(FunctionPointerT P) { assert((reinterpret_cast<uintptr_t>(P) & ~((uintptr_t)-1 << NumLowBitsAvailable)) == 0 && diff --git a/llvm/include/llvm/Support/PrettyStackTrace.h b/llvm/include/llvm/Support/PrettyStackTrace.h index 6eb070b2297ec..ac25cffde051c 100644 --- a/llvm/include/llvm/Support/PrettyStackTrace.h +++ b/llvm/include/llvm/Support/PrettyStackTrace.h @@ -37,6 +37,13 @@ namespace llvm { /// \see PrettyStackTraceEntry void EnablePrettyStackTraceOnSigInfoForThisThread(bool ShouldEnable = true); + /// Replaces the generic bug report message that is output upon + /// a crash. + void setBugReportMsg(const char *Msg); + + /// Get the bug report message that will be output upon a crash. + const char *getBugReportMsg(); + /// PrettyStackTraceEntry - This class is used to represent a frame of the /// "pretty" stack trace that is dumped when a program crashes. You can define /// subclasses of this and declare them on the program stack: when they are diff --git a/llvm/include/llvm/Support/Process.h b/llvm/include/llvm/Support/Process.h index 67e37912519bd..0ba6d58ba287a 100644 --- a/llvm/include/llvm/Support/Process.h +++ b/llvm/include/llvm/Support/Process.h @@ -25,7 +25,7 @@ #define LLVM_SUPPORT_PROCESS_H #include "llvm/ADT/Optional.h" -#include "llvm/Support/Allocator.h" +#include "llvm/Support/AllocatorBase.h" #include "llvm/Support/Chrono.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Error.h" @@ -42,6 +42,11 @@ namespace sys { /// current executing process. class Process { public: + using Pid = int32_t; + + /// Get the process's identifier. + static Pid getProcessId(); + /// Get the process's page size. /// This may fail if the underlying syscall returns an error. In most cases, /// page size information is used for optimization, and this error can be @@ -201,6 +206,12 @@ public: /// Get the result of a process wide random number generator. The /// generator will be automatically seeded in non-deterministic fashion. static unsigned GetRandomNumber(); + + /// Equivalent to ::exit(), except when running inside a CrashRecoveryContext. + /// In that case, the control flow will resume after RunSafely(), like for a + /// crash, rather than exiting the current process. + LLVM_ATTRIBUTE_NORETURN + static void Exit(int RetCode); }; } diff --git a/llvm/include/llvm/Support/Program.h b/llvm/include/llvm/Support/Program.h index 6b2315c5da8d0..dbda064cda058 100644 --- a/llvm/include/llvm/Support/Program.h +++ b/llvm/include/llvm/Support/Program.h @@ -18,6 +18,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Config/llvm-config.h" #include "llvm/Support/ErrorOr.h" +#include <chrono> #include <system_error> namespace llvm { @@ -52,6 +53,13 @@ namespace sys { ProcessInfo(); }; + /// This struct encapsulates information about a process execution. + struct ProcessStatistics { + std::chrono::microseconds TotalTime; + std::chrono::microseconds UserTime; + uint64_t PeakMemory = 0; ///< Maximum resident set size in KiB. + }; + /// Find the first executable file \p Name in \p Paths. /// /// This does not perform hashing as a shell would but instead stats each PATH @@ -116,10 +124,14 @@ namespace sys { ///< string instance in which error messages will be returned. If the ///< string is non-empty upon return an error occurred while invoking the ///< program. - bool *ExecutionFailed = nullptr); + bool *ExecutionFailed = nullptr, + Optional<ProcessStatistics> *ProcStat = nullptr ///< If non-zero, provides + /// a pointer to a structure in which process execution statistics will be + /// stored. + ); /// Similar to ExecuteAndWait, but returns immediately. - /// @returns The \see ProcessInfo of the newly launced process. + /// @returns The \see ProcessInfo of the newly launched process. /// \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. @@ -182,18 +194,24 @@ namespace sys { /// \note Users of this function should always check the ReturnCode member of /// the \see ProcessInfo returned from this function. ProcessInfo Wait( - const ProcessInfo &PI, ///< The child process that should be waited on. + const ProcessInfo &PI, ///< The child process that should be waited on. unsigned SecondsToWait, ///< If non-zero, this specifies the amount of ///< time to wait for the child process to exit. If the time expires, the ///< child is killed and this function returns. If zero, this function ///< will perform a non-blocking wait on the child process. bool WaitUntilTerminates, ///< If true, ignores \p SecondsToWait and waits ///< until child has terminated. - std::string *ErrMsg = nullptr ///< If non-zero, provides a pointer to a + std::string *ErrMsg = nullptr, ///< If non-zero, provides a pointer to a ///< string instance in which error messages will be returned. If the ///< string is non-empty upon return an error occurred while invoking the ///< program. - ); + Optional<ProcessStatistics> *ProcStat = nullptr ///< If non-zero, provides + /// a pointer to a structure in which process execution statistics will be + /// stored. + ); + + /// Print a command argument, and optionally quote it. + void printArg(llvm::raw_ostream &OS, StringRef Arg, bool Quote); #if defined(_WIN32) /// Given a list of command line arguments, quote and escape them as necessary diff --git a/llvm/include/llvm/Support/RISCVAttributeParser.h b/llvm/include/llvm/Support/RISCVAttributeParser.h new file mode 100644 index 0000000000000..3e629419a7e9b --- /dev/null +++ b/llvm/include/llvm/Support/RISCVAttributeParser.h @@ -0,0 +1,37 @@ +//===-- RISCVAttributeParser.h - RISCV Attribute Parser ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_RISCVATTRIBUTEPARSER_H +#define LLVM_SUPPORT_RISCVATTRIBUTEPARSER_H + +#include "llvm/Support/ELFAttributeParser.h" +#include "llvm/Support/RISCVAttributes.h" + +namespace llvm { +class RISCVAttributeParser : public ELFAttributeParser { + struct DisplayHandler { + RISCVAttrs::AttrType attribute; + Error (RISCVAttributeParser::*routine)(unsigned); + }; + static const DisplayHandler displayRoutines[]; + + Error handler(uint64_t tag, bool &handled) override; + + Error unalignedAccess(unsigned tag); + Error stackAlign(unsigned tag); + +public: + RISCVAttributeParser(ScopedPrinter *sw) + : ELFAttributeParser(sw, RISCVAttrs::RISCVAttributeTags, "riscv") {} + RISCVAttributeParser() + : ELFAttributeParser(RISCVAttrs::RISCVAttributeTags, "riscv") {} +}; + +} // namespace llvm + +#endif diff --git a/llvm/include/llvm/Support/RISCVAttributes.h b/llvm/include/llvm/Support/RISCVAttributes.h new file mode 100644 index 0000000000000..caded9519b668 --- /dev/null +++ b/llvm/include/llvm/Support/RISCVAttributes.h @@ -0,0 +1,44 @@ +//===-- RISCVAttributes.h - RISCV Attributes --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains enumerations for RISCV attributes as defined in RISC-V +// ELF psABI specification. +// +// RISC-V ELF psABI specification +// +// https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_SUPPORT_RISCVATTRIBUTES_H +#define LLVM_SUPPORT_RISCVATTRIBUTES_H + +#include "llvm/Support/ELFAttributes.h" + +namespace llvm { +namespace RISCVAttrs { + +extern const TagNameMap RISCVAttributeTags; + +enum AttrType : unsigned { + // Attribute types in ELF/.riscv.attributes. + STACK_ALIGN = 4, + ARCH = 5, + UNALIGNED_ACCESS = 6, + PRIV_SPEC = 8, + PRIV_SPEC_MINOR = 10, + PRIV_SPEC_REVISION = 12, +}; + +enum StackAlign { ALIGN_4 = 4, ALIGN_16 = 16 }; + +enum { NOT_ALLOWED = 0, ALLOWED = 1 }; + +} // namespace RISCVAttrs +} // namespace llvm + +#endif diff --git a/llvm/include/llvm/Support/Regex.h b/llvm/include/llvm/Support/Regex.h index b2620ab4cfc93..ae4b9516f194e 100644 --- a/llvm/include/llvm/Support/Regex.h +++ b/llvm/include/llvm/Support/Regex.h @@ -16,6 +16,7 @@ #ifndef LLVM_SUPPORT_REGEX_H #define LLVM_SUPPORT_REGEX_H +#include "llvm/ADT/BitmaskEnum.h" #include <string> struct llvm_regex; @@ -26,20 +27,22 @@ namespace llvm { class Regex { public: - enum { - NoFlags=0, + enum RegexFlags : unsigned { + NoFlags = 0, /// Compile for matching that ignores upper/lower case distinctions. - IgnoreCase=1, + IgnoreCase = 1, /// Compile for newline-sensitive matching. With this flag '[^' bracket /// expressions and '.' never match newline. A ^ anchor matches the /// null string after any newline in the string in addition to its normal /// function, and the $ anchor matches the null string before any /// newline in the string in addition to its normal function. - Newline=2, + Newline = 2, /// By default, the POSIX extended regular expression (ERE) syntax is /// assumed. Pass this flag to turn on basic regular expressions (BRE) /// instead. - BasicRegex=4 + BasicRegex = 4, + + LLVM_MARK_AS_BITMASK_ENUM(BasicRegex) }; Regex(); @@ -47,7 +50,8 @@ namespace llvm { /// /// \param Regex - referenced string is no longer needed after this /// constructor does finish. Only its compiled form is kept stored. - Regex(StringRef Regex, unsigned Flags = NoFlags); + Regex(StringRef Regex, RegexFlags Flags = NoFlags); + Regex(StringRef Regex, unsigned Flags); Regex(const Regex &) = delete; Regex &operator=(Regex regex) { std::swap(preg, regex.preg); diff --git a/llvm/include/llvm/Support/SHA1.h b/llvm/include/llvm/Support/SHA1.h index 2cfbd21793645..efd8513cc201f 100644 --- a/llvm/include/llvm/Support/SHA1.h +++ b/llvm/include/llvm/Support/SHA1.h @@ -15,14 +15,12 @@ #ifndef LLVM_SUPPORT_SHA1_H #define LLVM_SUPPORT_SHA1_H -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" - #include <array> #include <cstdint> namespace llvm { template <typename T> class ArrayRef; +class StringRef; /// A class that wrap the SHA1 algorithm. class SHA1 { @@ -36,10 +34,7 @@ public: void update(ArrayRef<uint8_t> Data); /// Digest more data. - void update(StringRef Str) { - update(ArrayRef<uint8_t>((uint8_t *)const_cast<char *>(Str.data()), - Str.size())); - } + void update(StringRef Str); /// Return a reference to the current raw 160-bits SHA1 for the digested data /// since the last call to init(). This call will add data to the internal diff --git a/llvm/include/llvm/Support/ScaledNumber.h b/llvm/include/llvm/Support/ScaledNumber.h index 552da34f357b7..a5261e419986f 100644 --- a/llvm/include/llvm/Support/ScaledNumber.h +++ b/llvm/include/llvm/Support/ScaledNumber.h @@ -418,7 +418,7 @@ namespace llvm { class raw_ostream; class ScaledNumberBase { public: - static const int DefaultPrecision = 10; + static constexpr int DefaultPrecision = 10; static void dump(uint64_t D, int16_t E, int Width); static raw_ostream &print(raw_ostream &OS, uint64_t D, int16_t E, int Width, @@ -499,7 +499,7 @@ public: private: typedef std::numeric_limits<DigitsType> DigitsLimits; - static const int Width = sizeof(DigitsType) * 8; + static constexpr int Width = sizeof(DigitsType) * 8; static_assert(Width <= 64, "invalid integer width for digits"); private: diff --git a/llvm/include/llvm/Support/SmallVectorMemoryBuffer.h b/llvm/include/llvm/Support/SmallVectorMemoryBuffer.h index b63b58e3a8ba9..62900b740b81b 100644 --- a/llvm/include/llvm/Support/SmallVectorMemoryBuffer.h +++ b/llvm/include/llvm/Support/SmallVectorMemoryBuffer.h @@ -44,7 +44,7 @@ public: /// Construct a named SmallVectorMemoryBuffer from the given /// SmallVector r-value and StringRef. SmallVectorMemoryBuffer(SmallVectorImpl<char> &&SV, StringRef Name) - : SV(std::move(SV)), BufferName(Name) { + : SV(std::move(SV)), BufferName(std::string(Name)) { init(this->SV.begin(), this->SV.end(), false); } diff --git a/llvm/include/llvm/Support/SourceMgr.h b/llvm/include/llvm/Support/SourceMgr.h index 1b005519e5d4b..a0bd3ca2e0c19 100644 --- a/llvm/include/llvm/Support/SourceMgr.h +++ b/llvm/include/llvm/Support/SourceMgr.h @@ -15,19 +15,9 @@ #ifndef LLVM_SUPPORT_SOURCEMGR_H #define LLVM_SUPPORT_SOURCEMGR_H -#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" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SMLoc.h" -#include <algorithm> -#include <cassert> -#include <memory> -#include <string> -#include <utility> #include <vector> namespace llvm { @@ -57,29 +47,29 @@ 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 = PointerUnion<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> + /// + /// Since we're storing 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. + mutable void *OffsetCache = nullptr; + + /// Look up a given \p Ptr in in the buffer, determining which line it came + /// from. unsigned getLineNumber(const char *Ptr) const; + template <typename T> + unsigned getLineNumberSpecialized(const char *Ptr) const; + + /// Return a pointer to the first character of the specified line number or + /// null if the line number is invalid. + const char *getPointerForLineNumber(unsigned LineNo) const; + template <typename T> + const char *getPointerForLineNumberSpecialized(unsigned LineNo) const; /// This is the location of the parent include, or null if at the top level. SMLoc IncludeLoc; @@ -134,9 +124,7 @@ public: return Buffers[i - 1].Buffer.get(); } - unsigned getNumBuffers() const { - return Buffers.size(); - } + unsigned getNumBuffers() const { return Buffers.size(); } unsigned getMainFileID() const { assert(getNumBuffers()); @@ -184,20 +172,24 @@ public: std::pair<unsigned, unsigned> getLineAndColumn(SMLoc Loc, unsigned BufferID = 0) const; + /// Given a line and column number in a mapped buffer, turn it into an SMLoc. + /// This will return a null SMLoc if the line/column location is invalid. + SMLoc FindLocForLineAndColumn(unsigned BufferID, unsigned LineNo, + unsigned ColNo); + /// Emit a message about the specified location with the specified string. /// /// \param ShowColors Display colored messages if output is a terminal and /// the default error handler is used. - void PrintMessage(raw_ostream &OS, SMLoc Loc, DiagKind Kind, - const Twine &Msg, - ArrayRef<SMRange> Ranges = None, - ArrayRef<SMFixIt> FixIts = None, + void PrintMessage(raw_ostream &OS, SMLoc Loc, DiagKind Kind, const Twine &Msg, + ArrayRef<SMRange> Ranges = {}, + ArrayRef<SMFixIt> FixIts = {}, bool ShowColors = true) const; /// Emits a diagnostic to llvm::errs(). void PrintMessage(SMLoc Loc, DiagKind Kind, const Twine &Msg, - ArrayRef<SMRange> Ranges = None, - ArrayRef<SMFixIt> FixIts = None, + ArrayRef<SMRange> Ranges = {}, + ArrayRef<SMFixIt> FixIts = {}, bool ShowColors = true) const; /// Emits a manually-constructed diagnostic to the given output stream. @@ -213,8 +205,8 @@ public: /// \param Msg If non-null, the kind of message (e.g., "error") which is /// prefixed to the message. SMDiagnostic GetMessage(SMLoc Loc, DiagKind Kind, const Twine &Msg, - ArrayRef<SMRange> Ranges = None, - ArrayRef<SMFixIt> FixIts = None) const; + ArrayRef<SMRange> Ranges = {}, + ArrayRef<SMFixIt> FixIts = {}) const; /// Prints the names of included files and the line of the file they were /// included from. A diagnostic handler can use this before printing its @@ -232,17 +224,10 @@ class SMFixIt { std::string Text; public: - // FIXME: Twine.str() is not very efficient. - SMFixIt(SMLoc Loc, const Twine &Insertion) - : Range(Loc, Loc), Text(Insertion.str()) { - assert(Loc.isValid()); - } + SMFixIt(SMRange R, const Twine &Replacement); - // FIXME: Twine.str() is not very efficient. - SMFixIt(SMRange R, const Twine &Replacement) - : Range(R), Text(Replacement.str()) { - assert(R.isValid()); - } + SMFixIt(SMLoc Loc, const Twine &Replacement) + : SMFixIt(SMRange(Loc, Loc), Replacement) {} StringRef getText() const { return Text; } SMRange getRange() const { return Range; } @@ -274,14 +259,13 @@ public: SMDiagnostic() = default; // Diagnostic with no location (e.g. file not found, command line arg error). SMDiagnostic(StringRef filename, SourceMgr::DiagKind Knd, StringRef Msg) - : Filename(filename), LineNo(-1), ColumnNo(-1), Kind(Knd), Message(Msg) {} + : Filename(filename), LineNo(-1), ColumnNo(-1), Kind(Knd), Message(Msg) {} // Diagnostic with a location. - SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN, - int Line, int Col, SourceMgr::DiagKind Kind, - StringRef Msg, StringRef LineStr, - ArrayRef<std::pair<unsigned,unsigned>> Ranges, - ArrayRef<SMFixIt> FixIts = None); + SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN, int Line, int Col, + SourceMgr::DiagKind Kind, StringRef Msg, StringRef LineStr, + ArrayRef<std::pair<unsigned, unsigned>> Ranges, + ArrayRef<SMFixIt> FixIts = {}); const SourceMgr *getSourceMgr() const { return SM; } SMLoc getLoc() const { return Loc; } @@ -293,13 +277,9 @@ public: StringRef getLineContents() const { return LineContents; } ArrayRef<std::pair<unsigned, unsigned>> getRanges() const { return Ranges; } - void addFixIt(const SMFixIt &Hint) { - FixIts.push_back(Hint); - } + void addFixIt(const SMFixIt &Hint) { FixIts.push_back(Hint); } - ArrayRef<SMFixIt> getFixIts() const { - return FixIts; - } + ArrayRef<SMFixIt> getFixIts() const { return FixIts; } void print(const char *ProgName, raw_ostream &S, bool ShowColors = true, bool ShowKindLabel = true) const; diff --git a/llvm/include/llvm/Support/SpecialCaseList.h b/llvm/include/llvm/Support/SpecialCaseList.h index 5b5b7f6124d68..d022a8f53706a 100644 --- a/llvm/include/llvm/Support/SpecialCaseList.h +++ b/llvm/include/llvm/Support/SpecialCaseList.h @@ -7,8 +7,8 @@ // // This is a utility class used to parse user-provided text files with // "special case lists" for code sanitizers. Such files are used to -// define an "ABI list" for DataFlowSanitizer and blacklists for sanitizers -// like AddressSanitizer or UndefinedBehaviorSanitizer. +// define an "ABI list" for DataFlowSanitizer and allow/exclusion lists for +// sanitizers like AddressSanitizer or UndefinedBehaviorSanitizer. // // Empty lines and lines starting with "#" are ignored. Sections are defined // using a '[section_name]' header and can be used to specify sanitizers the @@ -19,18 +19,18 @@ // prefix:wildcard_expression[=category] // If category is not specified, it is assumed to be empty string. // Definitions of "prefix" and "category" are sanitizer-specific. For example, -// sanitizer blacklists support prefixes "src", "fun" and "global". +// sanitizer exclusion support prefixes "src", "fun" and "global". // Wildcard expressions define, respectively, source files, functions or // globals which shouldn't be instrumented. // Examples of categories: // "functional": used in DFSan to list functions with pure functional // semantics. -// "init": used in ASan blacklist to disable initialization-order bugs +// "init": used in ASan exclusion list to disable initialization-order bugs // detection for certain globals or source files. // Full special case list file example: // --- // [address] -// # Blacklisted items: +// # Excluded items: // fun:*_ZN4base6subtle* // global:*global_with_bad_access_or_initialization* // global:*global_with_initialization_issues*=init @@ -52,18 +52,20 @@ #define LLVM_SUPPORT_SPECIALCASELIST_H #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringSet.h" #include "llvm/Support/Regex.h" #include "llvm/Support/TrigramIndex.h" -#include "llvm/Support/VirtualFileSystem.h" +#include <memory> #include <string> #include <vector> namespace llvm { class MemoryBuffer; -class Regex; class StringRef; +namespace vfs { +class FileSystem; +} + class SpecialCaseList { public: /// Parses the special case list entries from files. On failure, returns @@ -96,7 +98,7 @@ public: /// @Prefix:<E>=@Category /// \endcode /// where @Query satisfies wildcard expression <E> in a given @Section. - /// Returns zero if there is no blacklist entry corresponding to this + /// Returns zero if there is no exclusion entry corresponding to this /// expression. unsigned inSectionBlame(StringRef Section, StringRef Prefix, StringRef Query, StringRef Category = StringRef()) const; diff --git a/llvm/include/llvm/Support/StringPool.h b/llvm/include/llvm/Support/StringPool.h deleted file mode 100644 index a4f45916f53d6..0000000000000 --- a/llvm/include/llvm/Support/StringPool.h +++ /dev/null @@ -1,139 +0,0 @@ -//===- StringPool.h - Interned string pool ----------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file declares an interned string pool, which helps reduce the cost of -// strings by using the same storage for identical strings. -// -// To intern a string: -// -// StringPool Pool; -// PooledStringPtr Str = Pool.intern("wakka wakka"); -// -// To use the value of an interned string, use operator bool and operator*: -// -// if (Str) -// cerr << "the string is" << *Str << "\n"; -// -// Pooled strings are immutable, but you can change a PooledStringPtr to point -// to another instance. So that interned strings can eventually be freed, -// strings in the string pool are reference-counted (automatically). -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SUPPORT_STRINGPOOL_H -#define LLVM_SUPPORT_STRINGPOOL_H - -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" -#include <cassert> - -namespace llvm { - - class PooledStringPtr; - - /// StringPool - An interned string pool. Use the intern method to add a - /// string. Strings are removed automatically as PooledStringPtrs are - /// destroyed. - class StringPool { - /// PooledString - This is the value of an entry in the pool's interning - /// table. - struct PooledString { - StringPool *Pool = nullptr; ///< So the string can remove itself. - unsigned Refcount = 0; ///< Number of referencing PooledStringPtrs. - - public: - PooledString() = default; - }; - - friend class PooledStringPtr; - - using table_t = StringMap<PooledString>; - using entry_t = StringMapEntry<PooledString>; - table_t InternTable; - - public: - StringPool(); - ~StringPool(); - - /// intern - Adds a string to the pool and returns a reference-counted - /// pointer to it. No additional memory is allocated if the string already - /// exists in the pool. - PooledStringPtr intern(StringRef Str); - - /// empty - Checks whether the pool is empty. Returns true if so. - /// - inline bool empty() const { return InternTable.empty(); } - }; - - /// PooledStringPtr - A pointer to an interned string. Use operator bool to - /// test whether the pointer is valid, and operator * to get the string if so. - /// This is a lightweight value class with storage requirements equivalent to - /// a single pointer, but it does have reference-counting overhead when - /// copied. - class PooledStringPtr { - using entry_t = StringPool::entry_t; - - entry_t *S = nullptr; - - public: - PooledStringPtr() = default; - - explicit PooledStringPtr(entry_t *E) : S(E) { - if (S) ++S->getValue().Refcount; - } - - PooledStringPtr(const PooledStringPtr &That) : S(That.S) { - if (S) ++S->getValue().Refcount; - } - - PooledStringPtr &operator=(const PooledStringPtr &That) { - if (S != That.S) { - clear(); - S = That.S; - if (S) ++S->getValue().Refcount; - } - return *this; - } - - void clear() { - if (!S) - return; - if (--S->getValue().Refcount == 0) { - S->getValue().Pool->InternTable.remove(S); - S->Destroy(); - } - S = nullptr; - } - - ~PooledStringPtr() { clear(); } - - inline const char *begin() const { - assert(*this && "Attempt to dereference empty PooledStringPtr!"); - return S->getKeyData(); - } - - inline const char *end() const { - assert(*this && "Attempt to dereference empty PooledStringPtr!"); - return S->getKeyData() + S->getKeyLength(); - } - - inline unsigned size() const { - assert(*this && "Attempt to dereference empty PooledStringPtr!"); - return S->getKeyLength(); - } - - inline const char *operator*() const { return begin(); } - inline explicit operator bool() const { return S != nullptr; } - - inline bool operator==(const PooledStringPtr &That) const { return S == That.S; } - inline bool operator!=(const PooledStringPtr &That) const { return S != That.S; } - }; - -} // end namespace llvm - -#endif // LLVM_SUPPORT_STRINGPOOL_H diff --git a/llvm/include/llvm/Support/SuffixTree.h b/llvm/include/llvm/Support/SuffixTree.h new file mode 100644 index 0000000000000..67d513d032cef --- /dev/null +++ b/llvm/include/llvm/Support/SuffixTree.h @@ -0,0 +1,350 @@ +//===- llvm/ADT/SuffixTree.h - Tree for substrings --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the Suffix Tree class and Suffix Tree Node struct. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_SUPPORT_SUFFIXTREE_H +#define LLVM_SUPPORT_SUFFIXTREE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/Allocator.h" +#include <vector> + +namespace llvm { + +/// Represents an undefined index in the suffix tree. +const unsigned EmptyIdx = -1; + +/// A node in a suffix tree which represents a substring or suffix. +/// +/// Each node has either no children or at least two children, with the root +/// being a exception in the empty tree. +/// +/// Children are represented as a map between unsigned integers and nodes. If +/// a node N has a child M on unsigned integer k, then the mapping represented +/// by N is a proper prefix of the mapping represented by M. Note that this, +/// although similar to a trie is somewhat different: each node stores a full +/// substring of the full mapping rather than a single character state. +/// +/// Each internal node contains a pointer to the internal node representing +/// the same string, but with the first character chopped off. This is stored +/// in \p Link. Each leaf node stores the start index of its respective +/// suffix in \p SuffixIdx. +struct SuffixTreeNode { + + /// The children of this node. + /// + /// A child existing on an unsigned integer implies that from the mapping + /// represented by the current node, there is a way to reach another + /// mapping by tacking that character on the end of the current string. + llvm::DenseMap<unsigned, SuffixTreeNode *> Children; + + /// The start index of this node's substring in the main string. + unsigned StartIdx = EmptyIdx; + + /// The end index of this node's substring in the main string. + /// + /// Every leaf node must have its \p EndIdx incremented at the end of every + /// step in the construction algorithm. To avoid having to update O(N) + /// nodes individually at the end of every step, the end index is stored + /// as a pointer. + unsigned *EndIdx = nullptr; + + /// For leaves, the start index of the suffix represented by this node. + /// + /// For all other nodes, this is ignored. + unsigned SuffixIdx = EmptyIdx; + + /// For internal nodes, a pointer to the internal node representing + /// the same sequence with the first character chopped off. + /// + /// This acts as a shortcut in Ukkonen's algorithm. One of the things that + /// Ukkonen's algorithm does to achieve linear-time construction is + /// keep track of which node the next insert should be at. This makes each + /// insert O(1), and there are a total of O(N) inserts. The suffix link + /// helps with inserting children of internal nodes. + /// + /// Say we add a child to an internal node with associated mapping S. The + /// next insertion must be at the node representing S - its first character. + /// This is given by the way that we iteratively build the tree in Ukkonen's + /// algorithm. The main idea is to look at the suffixes of each prefix in the + /// string, starting with the longest suffix of the prefix, and ending with + /// the shortest. Therefore, if we keep pointers between such nodes, we can + /// move to the next insertion point in O(1) time. If we don't, then we'd + /// have to query from the root, which takes O(N) time. This would make the + /// construction algorithm O(N^2) rather than O(N). + SuffixTreeNode *Link = nullptr; + + /// The length of the string formed by concatenating the edge labels from the + /// root to this node. + unsigned ConcatLen = 0; + + /// Returns true if this node is a leaf. + bool isLeaf() const { return SuffixIdx != EmptyIdx; } + + /// Returns true if this node is the root of its owning \p SuffixTree. + bool isRoot() const { return StartIdx == EmptyIdx; } + + /// Return the number of elements in the substring associated with this node. + size_t size() const { + + // Is it the root? If so, it's the empty string so return 0. + if (isRoot()) + return 0; + + assert(*EndIdx != EmptyIdx && "EndIdx is undefined!"); + + // Size = the number of elements in the string. + // For example, [0 1 2 3] has length 4, not 3. 3-0 = 3, so we have 3-0+1. + return *EndIdx - StartIdx + 1; + } + + SuffixTreeNode(unsigned StartIdx, unsigned *EndIdx, SuffixTreeNode *Link) + : StartIdx(StartIdx), EndIdx(EndIdx), Link(Link) {} + + SuffixTreeNode() {} +}; + +/// A data structure for fast substring queries. +/// +/// Suffix trees represent the suffixes of their input strings in their leaves. +/// A suffix tree is a type of compressed trie structure where each node +/// represents an entire substring rather than a single character. Each leaf +/// of the tree is a suffix. +/// +/// A suffix tree can be seen as a type of state machine where each state is a +/// substring of the full string. The tree is structured so that, for a string +/// of length N, there are exactly N leaves in the tree. This structure allows +/// us to quickly find repeated substrings of the input string. +/// +/// In this implementation, a "string" is a vector of unsigned integers. +/// These integers may result from hashing some data type. A suffix tree can +/// contain 1 or many strings, which can then be queried as one large string. +/// +/// The suffix tree is implemented using Ukkonen's algorithm for linear-time +/// suffix tree construction. Ukkonen's algorithm is explained in more detail +/// in the paper by Esko Ukkonen "On-line construction of suffix trees. The +/// paper is available at +/// +/// https://www.cs.helsinki.fi/u/ukkonen/SuffixT1withFigs.pdf +class SuffixTree { +public: + /// Each element is an integer representing an instruction in the module. + llvm::ArrayRef<unsigned> Str; + + /// A repeated substring in the tree. + struct RepeatedSubstring { + /// The length of the string. + unsigned Length; + + /// The start indices of each occurrence. + std::vector<unsigned> StartIndices; + }; + +private: + /// Maintains each node in the tree. + llvm::SpecificBumpPtrAllocator<SuffixTreeNode> NodeAllocator; + + /// The root of the suffix tree. + /// + /// The root represents the empty string. It is maintained by the + /// \p NodeAllocator like every other node in the tree. + SuffixTreeNode *Root = nullptr; + + /// Maintains the end indices of the internal nodes in the tree. + /// + /// Each internal node is guaranteed to never have its end index change + /// during the construction algorithm; however, leaves must be updated at + /// every step. Therefore, we need to store leaf end indices by reference + /// to avoid updating O(N) leaves at every step of construction. Thus, + /// every internal node must be allocated its own end index. + llvm::BumpPtrAllocator InternalEndIdxAllocator; + + /// The end index of each leaf in the tree. + unsigned LeafEndIdx = -1; + + /// Helper struct which keeps track of the next insertion point in + /// Ukkonen's algorithm. + struct ActiveState { + /// The next node to insert at. + SuffixTreeNode *Node = nullptr; + + /// The index of the first character in the substring currently being added. + unsigned Idx = EmptyIdx; + + /// The length of the substring we have to add at the current step. + unsigned Len = 0; + }; + + /// The point the next insertion will take place at in the + /// construction algorithm. + ActiveState Active; + + /// Allocate a leaf node and add it to the tree. + /// + /// \param Parent The parent of this node. + /// \param StartIdx The start index of this node's associated string. + /// \param Edge The label on the edge leaving \p Parent to this node. + /// + /// \returns A pointer to the allocated leaf node. + SuffixTreeNode *insertLeaf(SuffixTreeNode &Parent, unsigned StartIdx, + unsigned Edge); + + /// Allocate an internal node and add it to the tree. + /// + /// \param Parent The parent of this node. Only null when allocating the root. + /// \param StartIdx The start index of this node's associated string. + /// \param EndIdx The end index of this node's associated string. + /// \param Edge The label on the edge leaving \p Parent to this node. + /// + /// \returns A pointer to the allocated internal node. + SuffixTreeNode *insertInternalNode(SuffixTreeNode *Parent, unsigned StartIdx, + unsigned EndIdx, unsigned Edge); + + /// Set the suffix indices of the leaves to the start indices of their + /// respective suffixes. + void setSuffixIndices(); + + /// Construct the suffix tree for the prefix of the input ending at + /// \p EndIdx. + /// + /// Used to construct the full suffix tree iteratively. At the end of each + /// step, the constructed suffix tree is either a valid suffix tree, or a + /// suffix tree with implicit suffixes. At the end of the final step, the + /// suffix tree is a valid tree. + /// + /// \param EndIdx The end index of the current prefix in the main string. + /// \param SuffixesToAdd The number of suffixes that must be added + /// to complete the suffix tree at the current phase. + /// + /// \returns The number of suffixes that have not been added at the end of + /// this step. + unsigned extend(unsigned EndIdx, unsigned SuffixesToAdd); + +public: + /// Construct a suffix tree from a sequence of unsigned integers. + /// + /// \param Str The string to construct the suffix tree for. + SuffixTree(const std::vector<unsigned> &Str); + + /// Iterator for finding all repeated substrings in the suffix tree. + struct RepeatedSubstringIterator { + private: + /// The current node we're visiting. + SuffixTreeNode *N = nullptr; + + /// The repeated substring associated with this node. + RepeatedSubstring RS; + + /// The nodes left to visit. + std::vector<SuffixTreeNode *> ToVisit; + + /// The minimum length of a repeated substring to find. + /// Since we're outlining, we want at least two instructions in the range. + /// FIXME: This may not be true for targets like X86 which support many + /// instruction lengths. + const unsigned MinLength = 2; + + /// Move the iterator to the next repeated substring. + void advance() { + // Clear the current state. If we're at the end of the range, then this + // is the state we want to be in. + RS = RepeatedSubstring(); + N = nullptr; + + // Each leaf node represents a repeat of a string. + std::vector<SuffixTreeNode *> LeafChildren; + + // Continue visiting nodes until we find one which repeats more than once. + while (!ToVisit.empty()) { + SuffixTreeNode *Curr = ToVisit.back(); + ToVisit.pop_back(); + LeafChildren.clear(); + + // Keep track of the length of the string associated with the node. If + // it's too short, we'll quit. + unsigned Length = Curr->ConcatLen; + + // Iterate over each child, saving internal nodes for visiting, and + // leaf nodes in LeafChildren. Internal nodes represent individual + // strings, which may repeat. + for (auto &ChildPair : Curr->Children) { + // Save all of this node's children for processing. + if (!ChildPair.second->isLeaf()) + ToVisit.push_back(ChildPair.second); + + // It's not an internal node, so it must be a leaf. If we have a + // long enough string, then save the leaf children. + else if (Length >= MinLength) + LeafChildren.push_back(ChildPair.second); + } + + // The root never represents a repeated substring. If we're looking at + // that, then skip it. + if (Curr->isRoot()) + continue; + + // Do we have any repeated substrings? + if (LeafChildren.size() >= 2) { + // Yes. Update the state to reflect this, and then bail out. + N = Curr; + RS.Length = Length; + for (SuffixTreeNode *Leaf : LeafChildren) + RS.StartIndices.push_back(Leaf->SuffixIdx); + break; + } + } + + // At this point, either NewRS is an empty RepeatedSubstring, or it was + // set in the above loop. Similarly, N is either nullptr, or the node + // associated with NewRS. + } + + public: + /// Return the current repeated substring. + RepeatedSubstring &operator*() { return RS; } + + RepeatedSubstringIterator &operator++() { + advance(); + return *this; + } + + RepeatedSubstringIterator operator++(int I) { + RepeatedSubstringIterator It(*this); + advance(); + return It; + } + + bool operator==(const RepeatedSubstringIterator &Other) { + return N == Other.N; + } + bool operator!=(const RepeatedSubstringIterator &Other) { + return !(*this == Other); + } + + RepeatedSubstringIterator(SuffixTreeNode *N) : N(N) { + // Do we have a non-null node? + if (N) { + // Yes. At the first step, we need to visit all of N's children. + // Note: This means that we visit N last. + ToVisit.push_back(N); + advance(); + } + } + }; + + typedef RepeatedSubstringIterator iterator; + iterator begin() { return iterator(Root); } + iterator end() { return iterator(nullptr); } +}; + +} // namespace llvm + +#endif // LLVM_SUPPORT_SUFFIXTREE_H diff --git a/llvm/include/llvm/Support/SwapByteOrder.h b/llvm/include/llvm/Support/SwapByteOrder.h index 6cec87006c02c..0e544fc7e71ee 100644 --- a/llvm/include/llvm/Support/SwapByteOrder.h +++ b/llvm/include/llvm/Support/SwapByteOrder.h @@ -14,15 +14,15 @@ #ifndef LLVM_SUPPORT_SWAPBYTEORDER_H #define LLVM_SUPPORT_SWAPBYTEORDER_H -#include "llvm/Support/Compiler.h" -#include "llvm/Support/DataTypes.h" #include <cstddef> +#include <cstdint> #include <type_traits> #if defined(_MSC_VER) && !defined(_DEBUG) #include <stdlib.h> #endif -#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) +#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) || \ + defined(__EMSCRIPTEN__) #include <endian.h> #elif defined(_AIX) #include <sys/machine.h> @@ -36,6 +36,10 @@ #else #define BYTE_ORDER LITTLE_ENDIAN #endif +#elif defined(__MVS__) +#define BIG_ENDIAN 4321 +#define LITTLE_ENDIAN 1234 +#define BYTE_ORDER BIG_ENDIAN #else #if !defined(BYTE_ORDER) && !defined(_WIN32) #include <machine/endian.h> @@ -43,19 +47,10 @@ #endif namespace llvm { -namespace sys { -#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN -constexpr bool IsBigEndianHost = true; -#else -constexpr bool IsBigEndianHost = false; -#endif - -static const bool IsLittleEndianHost = !IsBigEndianHost; - -/// SwapByteOrder_16 - This function returns a byte-swapped representation of +/// ByteSwap_16 - This function returns a byte-swapped representation of /// the 16-bit argument. -inline uint16_t SwapByteOrder_16(uint16_t value) { +inline uint16_t ByteSwap_16(uint16_t value) { #if defined(_MSC_VER) && !defined(_DEBUG) // The DLL version of the runtime lacks these functions (bug!?), but in a // release build they're replaced with BSWAP instructions anyway. @@ -68,7 +63,7 @@ inline uint16_t SwapByteOrder_16(uint16_t value) { } /// This function returns a byte-swapped representation of the 32-bit argument. -inline uint32_t SwapByteOrder_32(uint32_t value) { +inline uint32_t ByteSwap_32(uint32_t value) { #if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC)) return __builtin_bswap32(value); #elif defined(_MSC_VER) && !defined(_DEBUG) @@ -83,43 +78,54 @@ inline uint32_t SwapByteOrder_32(uint32_t value) { } /// This function returns a byte-swapped representation of the 64-bit argument. -inline uint64_t SwapByteOrder_64(uint64_t value) { +inline uint64_t ByteSwap_64(uint64_t value) { #if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC)) return __builtin_bswap64(value); #elif defined(_MSC_VER) && !defined(_DEBUG) return _byteswap_uint64(value); #else - uint64_t Hi = SwapByteOrder_32(uint32_t(value)); - uint32_t Lo = SwapByteOrder_32(uint32_t(value >> 32)); + uint64_t Hi = ByteSwap_32(uint32_t(value)); + uint32_t Lo = ByteSwap_32(uint32_t(value >> 32)); return (Hi << 32) | Lo; #endif } +namespace sys { + +#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN +constexpr bool IsBigEndianHost = true; +#else +constexpr bool IsBigEndianHost = false; +#endif + +static const bool IsLittleEndianHost = !IsBigEndianHost; + inline unsigned char getSwappedBytes(unsigned char C) { return C; } inline signed char getSwappedBytes(signed char C) { return C; } inline char getSwappedBytes(char C) { return C; } -inline unsigned short getSwappedBytes(unsigned short C) { return SwapByteOrder_16(C); } -inline signed short getSwappedBytes( signed short C) { return SwapByteOrder_16(C); } +inline unsigned short getSwappedBytes(unsigned short C) { return ByteSwap_16(C); } +inline signed short getSwappedBytes( signed short C) { return ByteSwap_16(C); } -inline unsigned int getSwappedBytes(unsigned int C) { return SwapByteOrder_32(C); } -inline signed int getSwappedBytes( signed int C) { return SwapByteOrder_32(C); } +inline unsigned int getSwappedBytes(unsigned int C) { return ByteSwap_32(C); } +inline signed int getSwappedBytes( signed int C) { return ByteSwap_32(C); } -#if __LONG_MAX__ == __INT_MAX__ -inline unsigned long getSwappedBytes(unsigned long C) { return SwapByteOrder_32(C); } -inline signed long getSwappedBytes( signed long C) { return SwapByteOrder_32(C); } -#elif __LONG_MAX__ == __LONG_LONG_MAX__ -inline unsigned long getSwappedBytes(unsigned long C) { return SwapByteOrder_64(C); } -inline signed long getSwappedBytes( signed long C) { return SwapByteOrder_64(C); } -#else -#error "Unknown long size!" -#endif +inline unsigned long getSwappedBytes(unsigned long C) { + // Handle LLP64 and LP64 platforms. + return sizeof(long) == sizeof(int) ? ByteSwap_32((uint32_t)C) + : ByteSwap_64((uint64_t)C); +} +inline signed long getSwappedBytes(signed long C) { + // Handle LLP64 and LP64 platforms. + return sizeof(long) == sizeof(int) ? ByteSwap_32((uint32_t)C) + : ByteSwap_64((uint64_t)C); +} inline unsigned long long getSwappedBytes(unsigned long long C) { - return SwapByteOrder_64(C); + return ByteSwap_64(C); } inline signed long long getSwappedBytes(signed long long C) { - return SwapByteOrder_64(C); + return ByteSwap_64(C); } inline float getSwappedBytes(float C) { @@ -128,7 +134,7 @@ inline float getSwappedBytes(float C) { float f; } in, out; in.f = C; - out.i = SwapByteOrder_32(in.i); + out.i = ByteSwap_32(in.i); return out.f; } @@ -138,15 +144,14 @@ inline double getSwappedBytes(double C) { double d; } in, out; in.d = C; - out.i = SwapByteOrder_64(in.i); + out.i = ByteSwap_64(in.i); return out.d; } template <typename T> -inline typename std::enable_if<std::is_enum<T>::value, T>::type -getSwappedBytes(T C) { +inline std::enable_if_t<std::is_enum<T>::value, T> getSwappedBytes(T C) { return static_cast<T>( - getSwappedBytes(static_cast<typename std::underlying_type<T>::type>(C))); + getSwappedBytes(static_cast<std::underlying_type_t<T>>(C))); } template<typename T> diff --git a/llvm/include/llvm/Support/SystemUtils.h b/llvm/include/llvm/Support/SystemUtils.h index 77deddb9ee1c2..786bea3fcfae6 100644 --- a/llvm/include/llvm/Support/SystemUtils.h +++ b/llvm/include/llvm/Support/SystemUtils.h @@ -15,17 +15,16 @@ #define LLVM_SUPPORT_SYSTEMUTILS_H namespace llvm { - class raw_ostream; +class raw_ostream; /// 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. /// 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 + raw_ostream &stream_to_check ///< The stream to be checked ); -} // End llvm namespace +} // namespace llvm #endif diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def index e004550059d41..c069f5d22ba83 100644 --- a/llvm/include/llvm/Support/TargetOpcodes.def +++ b/llvm/include/llvm/Support/TargetOpcodes.def @@ -127,6 +127,12 @@ HANDLE_TARGET_OPCODE(PATCHPOINT) /// additionally expand this pseudo after register allocation. HANDLE_TARGET_OPCODE(LOAD_STACK_GUARD) +/// These are used to support call sites that must have the stack adjusted +/// before the call (e.g. to initialize an argument passed by value). +/// See llvm.call.preallocated.{setup,arg} in the LangRef for more details. +HANDLE_TARGET_OPCODE(PREALLOCATED_SETUP) +HANDLE_TARGET_OPCODE(PREALLOCATED_ARG) + /// 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 @@ -279,6 +285,9 @@ HANDLE_TARGET_OPCODE(G_INTTOPTR) /// COPY is the relevant instruction. HANDLE_TARGET_OPCODE(G_BITCAST) +/// Generic freeze. +HANDLE_TARGET_OPCODE(G_FREEZE) + /// INTRINSIC trunc intrinsic. HANDLE_TARGET_OPCODE(G_INTRINSIC_TRUNC) @@ -385,6 +394,12 @@ HANDLE_TARGET_OPCODE(G_LSHR) // Generic arithmetic right-shift HANDLE_TARGET_OPCODE(G_ASHR) +// Generic funnel left shift +HANDLE_TARGET_OPCODE(G_FSHL) + +// Generic funnel right shift +HANDLE_TARGET_OPCODE(G_FSHR) + /// Generic integer-base comparison, also applicable to vectors of integers. HANDLE_TARGET_OPCODE(G_ICMP) @@ -442,6 +457,18 @@ HANDLE_TARGET_OPCODE(G_UMULH) // the high half of the result. HANDLE_TARGET_OPCODE(G_SMULH) +/// Generic saturating unsigned addition. +HANDLE_TARGET_OPCODE(G_UADDSAT) + +/// Generic saturating signed addition. +HANDLE_TARGET_OPCODE(G_SADDSAT) + +/// Generic saturating unsigned subtraction. +HANDLE_TARGET_OPCODE(G_USUBSAT) + +/// Generic saturating signed subtraction. +HANDLE_TARGET_OPCODE(G_SSUBSAT) + /// Generic FP addition. HANDLE_TARGET_OPCODE(G_FADD) @@ -529,9 +556,8 @@ HANDLE_TARGET_OPCODE(G_FMAXIMUM) /// Generic pointer offset HANDLE_TARGET_OPCODE(G_PTR_ADD) -/// 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) +/// Clear the specified bits in a pointer. +HANDLE_TARGET_OPCODE(G_PTRMASK) /// Generic signed integer minimum. HANDLE_TARGET_OPCODE(G_SMIN) @@ -614,6 +640,15 @@ HANDLE_TARGET_OPCODE(G_JUMP_TABLE) /// Generic dynamic stack allocation. HANDLE_TARGET_OPCODE(G_DYN_STACKALLOC) +/// Strict floating point instructions. +HANDLE_TARGET_OPCODE(G_STRICT_FADD) +HANDLE_TARGET_OPCODE(G_STRICT_FSUB) +HANDLE_TARGET_OPCODE(G_STRICT_FMUL) +HANDLE_TARGET_OPCODE(G_STRICT_FDIV) +HANDLE_TARGET_OPCODE(G_STRICT_FREM) +HANDLE_TARGET_OPCODE(G_STRICT_FMA) +HANDLE_TARGET_OPCODE(G_STRICT_FSQRT) + /// read_register intrinsic HANDLE_TARGET_OPCODE(G_READ_REGISTER) diff --git a/llvm/include/llvm/Support/TargetParser.h b/llvm/include/llvm/Support/TargetParser.h index a7e1a752d0810..a0bd88c153b6e 100644 --- a/llvm/include/llvm/Support/TargetParser.h +++ b/llvm/include/llvm/Support/TargetParser.h @@ -25,55 +25,12 @@ namespace llvm { class StringRef; // Target specific information in their own namespaces. -// (ARM/AArch64 are declared in ARM/AArch64TargetParser.h) +// (ARM/AArch64/X86 are declared in ARM/AArch64/X86TargetParser.h) // These should be generated from TableGen because the information is already // there, and there is where new information about targets will be added. // FIXME: To TableGen this we need to make some table generated files available // even if the back-end is not compiled with LLVM, plus we need to create a new // back-end to TableGen to create these clean tables. -namespace X86 { - -// This should be kept in sync with libcc/compiler-rt as its included by clang -// as a proxy for what's in libgcc/compiler-rt. -enum ProcessorVendors : unsigned { - VENDOR_DUMMY, -#define X86_VENDOR(ENUM, STRING) \ - ENUM, -#include "llvm/Support/X86TargetParser.def" - VENDOR_OTHER -}; - -// This should be kept in sync with libcc/compiler-rt as its included by clang -// as a proxy for what's in libgcc/compiler-rt. -enum ProcessorTypes : unsigned { - CPU_TYPE_DUMMY, -#define X86_CPU_TYPE(ARCHNAME, ENUM) \ - ENUM, -#include "llvm/Support/X86TargetParser.def" - CPU_TYPE_MAX -}; - -// This should be kept in sync with libcc/compiler-rt as its included by clang -// as a proxy for what's in libgcc/compiler-rt. -enum ProcessorSubtypes : unsigned { - CPU_SUBTYPE_DUMMY, -#define X86_CPU_SUBTYPE(ARCHNAME, ENUM) \ - ENUM, -#include "llvm/Support/X86TargetParser.def" - CPU_SUBTYPE_MAX -}; - -// This should be kept in sync with libcc/compiler-rt as it should be used -// by clang as a proxy for what's in libgcc/compiler-rt. -enum ProcessorFeatures { -#define X86_FEATURE(VAL, ENUM) \ - ENUM = VAL, -#include "llvm/Support/X86TargetParser.def" - -}; - -} // namespace X86 - namespace AMDGPU { /// GPU kinds supported by the AMDGPU target. @@ -127,9 +84,10 @@ enum GPUKind : uint32_t { GK_GFX1010 = 71, GK_GFX1011 = 72, GK_GFX1012 = 73, + GK_GFX1030 = 75, GK_AMDGCN_FIRST = GK_GFX600, - GK_AMDGCN_LAST = GK_GFX1012, + GK_AMDGCN_LAST = GK_GFX1030, }; /// Instruction set architecture version. @@ -151,7 +109,10 @@ enum ArchFeatureKind : uint32_t { // Common features. FEATURE_FAST_FMA_F32 = 1 << 4, - FEATURE_FAST_DENORMAL_F32 = 1 << 5 + FEATURE_FAST_DENORMAL_F32 = 1 << 5, + + // Wavefront 32 is available. + FEATURE_WAVE32 = 1 << 6 }; StringRef getArchNameAMDGCN(GPUKind AK); diff --git a/llvm/include/llvm/Support/TaskQueue.h b/llvm/include/llvm/Support/TaskQueue.h index df2ffdee2cc24..4ceb056391af0 100644 --- a/llvm/include/llvm/Support/TaskQueue.h +++ b/llvm/include/llvm/Support/TaskQueue.h @@ -38,7 +38,7 @@ class TaskQueue { // 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; + using ResultTy = std::result_of_t<Callable()>; explicit Task(Callable C, TaskQueue &Parent) : C(std::move(C)), P(std::make_shared<std::promise<ResultTy>>()), Parent(&Parent) {} @@ -78,13 +78,13 @@ public: /// 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) { + std::future<std::result_of_t<Callable()>> 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; + using ResultTy = std::result_of_t<Callable()>; std::future<ResultTy> F = T.P->get_future(); { std::lock_guard<std::mutex> Lock(QueueLock); diff --git a/llvm/include/llvm/Support/ThreadPool.h b/llvm/include/llvm/Support/ThreadPool.h index 4bcbaa3142fd4..528fb32525eb2 100644 --- a/llvm/include/llvm/Support/ThreadPool.h +++ b/llvm/include/llvm/Support/ThreadPool.h @@ -14,6 +14,7 @@ #define LLVM_SUPPORT_THREAD_POOL_H #include "llvm/Config/llvm-config.h" +#include "llvm/Support/Threading.h" #include "llvm/Support/thread.h" #include <future> @@ -38,12 +39,11 @@ public: using TaskTy = std::function<void()>; using PackagedTaskTy = std::packaged_task<void()>; - /// Construct a pool with the number of threads found by - /// hardware_concurrency(). - ThreadPool(); - - /// Construct a pool of \p ThreadCount threads - ThreadPool(unsigned ThreadCount); + /// Construct a pool using the hardware strategy \p S for mapping hardware + /// execution resources (threads, cores, CPUs) + /// Defaults to using the maximum execution resources in the system, but + /// accounting for the affinity mask. + ThreadPool(ThreadPoolStrategy S = hardware_concurrency()); /// Blocking destructor: the pool will wait for all the threads to complete. ~ThreadPool(); @@ -68,7 +68,11 @@ public: /// It is an error to try to add new tasks while blocking on this call. void wait(); + unsigned getThreadCount() const { return ThreadCount; } + private: + bool workCompletedUnlocked() { return !ActiveThreads && Tasks.empty(); } + /// Asynchronous submission of a task to the pool. The returned future can be /// used to wait for the task to finish and is *non-blocking* on destruction. std::shared_future<void> asyncImpl(TaskTy F); @@ -83,17 +87,18 @@ private: std::mutex QueueLock; std::condition_variable QueueCondition; - /// Locking and signaling for job completion - std::mutex CompletionLock; + /// Signaling for job completion std::condition_variable CompletionCondition; /// Keep track of the number of thread actually busy - std::atomic<unsigned> ActiveThreads; + unsigned ActiveThreads = 0; #if LLVM_ENABLE_THREADS // avoids warning for unused variable /// Signal for the destruction of the pool, asking thread to exit. - bool EnableFlag; + bool EnableFlag = true; #endif + + unsigned ThreadCount; }; } diff --git a/llvm/include/llvm/Support/Threading.h b/llvm/include/llvm/Support/Threading.h index bacab8fa23b6d..13000575f270e 100644 --- a/llvm/include/llvm/Support/Threading.h +++ b/llvm/include/llvm/Support/Threading.h @@ -14,6 +14,7 @@ #ifndef LLVM_SUPPORT_THREADING_H #define LLVM_SUPPORT_THREADING_H +#include "llvm/ADT/BitVector.h" #include "llvm/ADT/FunctionExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX @@ -143,20 +144,81 @@ void llvm_execute_on_thread_async( #endif } - /// Get the amount of currency to use for tasks requiring significant - /// memory or other resources. Currently based on physical cores, if - /// available for the host system, otherwise falls back to - /// thread::hardware_concurrency(). - /// Returns 1 when LLVM is configured with LLVM_ENABLE_THREADS=OFF - unsigned heavyweight_hardware_concurrency(); - - /// Get the number of threads that the current program can execute - /// concurrently. On some systems std::thread::hardware_concurrency() returns - /// the total number of cores, without taking affinity into consideration. - /// Returns 1 when LLVM is configured with LLVM_ENABLE_THREADS=OFF. - /// Fallback to std::thread::hardware_concurrency() if sched_getaffinity is - /// not available. - unsigned hardware_concurrency(); + /// This tells how a thread pool will be used + class ThreadPoolStrategy { + public: + // The default value (0) means all available threads should be used, + // taking the affinity mask into account. If set, this value only represents + // a suggested high bound, the runtime might choose a lower value (not + // higher). + unsigned ThreadsRequested = 0; + + // If SMT is active, use hyper threads. If false, there will be only one + // std::thread per core. + bool UseHyperThreads = true; + + // If set, will constrain 'ThreadsRequested' to the number of hardware + // threads, or hardware cores. + bool Limit = false; + + /// Retrieves the max available threads for the current strategy. This + /// accounts for affinity masks and takes advantage of all CPU sockets. + unsigned compute_thread_count() const; + + /// Assign the current thread to an ideal hardware CPU or NUMA node. In a + /// multi-socket system, this ensures threads are assigned to all CPU + /// sockets. \p ThreadPoolNum represents a number bounded by [0, + /// compute_thread_count()). + void apply_thread_strategy(unsigned ThreadPoolNum) const; + + /// Finds the CPU socket where a thread should go. Returns 'None' if the + /// thread shall remain on the actual CPU socket. + Optional<unsigned> compute_cpu_socket(unsigned ThreadPoolNum) const; + }; + + /// Build a strategy from a number of threads as a string provided in \p Num. + /// When Num is above the max number of threads specified by the \p Default + /// strategy, we attempt to equally allocate the threads on all CPU sockets. + /// "0" or an empty string will return the \p Default strategy. + /// "all" for using all hardware threads. + Optional<ThreadPoolStrategy> + get_threadpool_strategy(StringRef Num, ThreadPoolStrategy Default = {}); + + /// Returns a thread strategy for tasks requiring significant memory or other + /// resources. To be used for workloads where hardware_concurrency() proves to + /// be less efficient. Avoid this strategy if doing lots of I/O. Currently + /// based on physical cores, if available for the host system, otherwise falls + /// back to hardware_concurrency(). Returns 1 when LLVM is configured with + /// LLVM_ENABLE_THREADS = OFF. + inline ThreadPoolStrategy + heavyweight_hardware_concurrency(unsigned ThreadCount = 0) { + ThreadPoolStrategy S; + S.UseHyperThreads = false; + S.ThreadsRequested = ThreadCount; + return S; + } + + /// Like heavyweight_hardware_concurrency() above, but builds a strategy + /// based on the rules described for get_threadpool_strategy(). + /// If \p Num is invalid, returns a default strategy where one thread per + /// hardware core is used. + inline ThreadPoolStrategy heavyweight_hardware_concurrency(StringRef Num) { + Optional<ThreadPoolStrategy> S = + get_threadpool_strategy(Num, heavyweight_hardware_concurrency()); + if (S) + return *S; + return heavyweight_hardware_concurrency(); + } + + /// Returns a default thread strategy where all available hardware ressources + /// are to be used, except for those initially excluded by an affinity mask. + /// This function takes affinity into consideration. Returns 1 when LLVM is + /// configured with LLVM_ENABLE_THREADS=OFF. + inline ThreadPoolStrategy hardware_concurrency(unsigned ThreadCount = 0) { + ThreadPoolStrategy S; + S.ThreadsRequested = ThreadCount; + return S; + } /// Return the current thread id, as used in various OS system calls. /// Note that not all platforms guarantee that the value returned will be @@ -184,6 +246,14 @@ void llvm_execute_on_thread_async( /// the operation succeeded or failed is returned. void get_thread_name(SmallVectorImpl<char> &Name); + /// Returns a mask that represents on which hardware thread, core, CPU, NUMA + /// group, the calling thread can be executed. On Windows, threads cannot + /// cross CPU sockets boundaries. + llvm::BitVector get_thread_affinity_mask(); + + /// Returns how many physical CPUs or NUMA groups the system has. + unsigned get_cpus(); + enum class ThreadPriority { Background = 0, Default = 1, diff --git a/llvm/include/llvm/Support/TimeProfiler.h b/llvm/include/llvm/Support/TimeProfiler.h index 678f8c1368111..b6f8a647e3ee8 100644 --- a/llvm/include/llvm/Support/TimeProfiler.h +++ b/llvm/include/llvm/Support/TimeProfiler.h @@ -9,12 +9,13 @@ #ifndef LLVM_SUPPORT_TIME_PROFILER_H #define LLVM_SUPPORT_TIME_PROFILER_H +#include "llvm/Support/Error.h" #include "llvm/Support/raw_ostream.h" namespace llvm { struct TimeTraceProfiler; -extern TimeTraceProfiler *TimeTraceProfilerInstance; +TimeTraceProfiler *getTimeTraceProfilerInstance(); /// Initialize the time trace profiler. /// This sets up the global \p TimeTraceProfilerInstance @@ -25,16 +26,27 @@ void timeTraceProfilerInitialize(unsigned TimeTraceGranularity, /// Cleanup the time trace profiler, if it was initialized. void timeTraceProfilerCleanup(); +/// Finish a time trace profiler running on a worker thread. +void timeTraceProfilerFinishThread(); + /// Is the time trace profiler enabled, i.e. initialized? inline bool timeTraceProfilerEnabled() { - return TimeTraceProfilerInstance != nullptr; + return getTimeTraceProfilerInstance() != nullptr; } -/// Write profiling data to output file. +/// Write profiling data to output stream. /// Data produced is JSON, in Chrome "Trace Event" format, see /// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview void timeTraceProfilerWrite(raw_pwrite_stream &OS); +/// Write profiling data to a file. +/// The function will write to \p PreferredFileName if provided, if not +/// then will write to \p FallbackFileName appending .time-trace. +/// Returns a StringError indicating a failure if the function is +/// unable to open the file for writing. +Error timeTraceProfilerWrite(StringRef PreferredFileName, + StringRef FallbackFileName); + /// Manually begin a time section, with the given \p Name and \p Detail. /// Profiler copies the string data, so the pointers can be given into /// temporaries. Time sections can be hierarchical; every Begin must have a @@ -59,19 +71,19 @@ struct TimeTraceScope { TimeTraceScope &operator=(TimeTraceScope &&) = delete; TimeTraceScope(StringRef Name) { - if (TimeTraceProfilerInstance != nullptr) + if (getTimeTraceProfilerInstance() != nullptr) timeTraceProfilerBegin(Name, StringRef("")); } TimeTraceScope(StringRef Name, StringRef Detail) { - if (TimeTraceProfilerInstance != nullptr) + if (getTimeTraceProfilerInstance() != nullptr) timeTraceProfilerBegin(Name, Detail); } TimeTraceScope(StringRef Name, llvm::function_ref<std::string()> Detail) { - if (TimeTraceProfilerInstance != nullptr) + if (getTimeTraceProfilerInstance() != nullptr) timeTraceProfilerBegin(Name, Detail); } ~TimeTraceScope() { - if (TimeTraceProfilerInstance != nullptr) + if (getTimeTraceProfilerInstance() != nullptr) timeTraceProfilerEnd(); } }; diff --git a/llvm/include/llvm/Support/Timer.h b/llvm/include/llvm/Support/Timer.h index a298ecd904046..045ac448bdb42 100644 --- a/llvm/include/llvm/Support/Timer.h +++ b/llvm/include/llvm/Support/Timer.h @@ -230,6 +230,11 @@ public: /// used by the Statistic code to influence the construction and destruction /// order of the global timer lists. static void ConstructTimerLists(); + + /// This makes the default group unmanaged, and lets the user manage the + /// group's lifetime. + static std::unique_ptr<TimerGroup> aquireDefaultGroup(); + private: friend class Timer; friend void PrintStatisticsJSON(raw_ostream &OS); diff --git a/llvm/include/llvm/Support/ToolOutputFile.h b/llvm/include/llvm/Support/ToolOutputFile.h index a99e327f8db70..cf01b9ecefc50 100644 --- a/llvm/include/llvm/Support/ToolOutputFile.h +++ b/llvm/include/llvm/Support/ToolOutputFile.h @@ -13,6 +13,7 @@ #ifndef LLVM_SUPPORT_TOOLOUTPUTFILE_H #define LLVM_SUPPORT_TOOLOUTPUTFILE_H +#include "llvm/ADT/Optional.h" #include "llvm/Support/raw_ostream.h" namespace llvm { @@ -38,8 +39,12 @@ class ToolOutputFile { ~CleanupInstaller(); } Installer; - /// The contained stream. This is intentionally declared after Installer. - raw_fd_ostream OS; + /// Storage for the stream, if we're owning our own stream. This is + /// intentionally declared after Installer. + Optional<raw_fd_ostream> OSHolder; + + /// The actual stream to use. + raw_fd_ostream *OS; public: /// This constructor's arguments are passed to raw_fd_ostream's @@ -50,7 +55,7 @@ public: ToolOutputFile(StringRef Filename, int FD); /// Return the contained raw_fd_ostream. - raw_fd_ostream &os() { return OS; } + raw_fd_ostream &os() { return *OS; } /// Indicate that the tool's job wrt this output file has been successful and /// the file should not be deleted. diff --git a/llvm/include/llvm/Support/TrailingObjects.h b/llvm/include/llvm/Support/TrailingObjects.h index 49be89613c434..0d9c4503aa9be 100644 --- a/llvm/include/llvm/Support/TrailingObjects.h +++ b/llvm/include/llvm/Support/TrailingObjects.h @@ -326,8 +326,8 @@ public: /// used in the class; they are supplied here redundantly only so /// that it's clear what the counts are counting in callers. template <typename... Tys> - static constexpr typename std::enable_if< - std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value, size_t>::type + static constexpr std::enable_if_t< + std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value, size_t> additionalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType< TrailingTys, size_t>::type... Counts) { return ParentType::additionalSizeToAllocImpl(0, Counts...); @@ -338,8 +338,8 @@ public: /// additionalSizeToAlloc, except it *does* include the size of the base /// object. template <typename... Tys> - static constexpr typename std::enable_if< - std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value, size_t>::type + static constexpr std::enable_if_t< + std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value, size_t> totalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType< TrailingTys, size_t>::type... Counts) { return sizeof(BaseTy) + ParentType::additionalSizeToAllocImpl(0, Counts...); diff --git a/llvm/include/llvm/Support/TrigramIndex.h b/llvm/include/llvm/Support/TrigramIndex.h index 9351c2db169a7..d635694eb5fd3 100644 --- a/llvm/include/llvm/Support/TrigramIndex.h +++ b/llvm/include/llvm/Support/TrigramIndex.h @@ -27,7 +27,6 @@ #define LLVM_SUPPORT_TRIGRAMINDEX_H #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringMap.h" #include <string> #include <unordered_map> diff --git a/llvm/include/llvm/Support/TypeSize.h b/llvm/include/llvm/Support/TypeSize.h index 7ea651f0f22cf..76564c401e8ed 100644 --- a/llvm/include/llvm/Support/TypeSize.h +++ b/llvm/include/llvm/Support/TypeSize.h @@ -15,17 +15,24 @@ #ifndef LLVM_SUPPORT_TYPESIZE_H #define LLVM_SUPPORT_TYPESIZE_H +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/WithColor.h" + +#include <cstdint> #include <cassert> -#include <tuple> namespace llvm { +template <typename T> struct DenseMapInfo; + class ElementCount { public: unsigned Min; // Minimum number of vector elements. bool Scalable; // If true, NumElements is a multiple of 'Min' determined // at runtime rather than compile time. + ElementCount() = default; + ElementCount(unsigned Min, bool Scalable) : Min(Min), Scalable(Scalable) {} @@ -33,6 +40,7 @@ public: return { Min * RHS, Scalable }; } ElementCount operator/(unsigned RHS) { + assert(Min % RHS == 0 && "Min is not a multiple of RHS."); return { Min / RHS, Scalable }; } @@ -42,6 +50,12 @@ public: bool operator!=(const ElementCount& RHS) const { return !(*this == RHS); } + bool operator==(unsigned RHS) const { return Min == RHS && !Scalable; } + bool operator!=(unsigned RHS) const { return !(*this == RHS); } + + ElementCount NextPowerOf2() const { + return ElementCount(llvm::NextPowerOf2(Min), Scalable); + } }; // This class is used to represent the size of types. If the type is of fixed @@ -68,8 +82,7 @@ public: // not guaranteed to be the same size at runtime, so they are never // considered to be equal. friend bool operator==(const TypeSize &LHS, const TypeSize &RHS) { - return std::tie(LHS.MinSize, LHS.IsScalable) == - std::tie(RHS.MinSize, RHS.IsScalable); + return LHS.MinSize == RHS.MinSize && LHS.IsScalable == RHS.IsScalable; } friend bool operator!=(const TypeSize &LHS, const TypeSize &RHS) { @@ -143,12 +156,40 @@ public: return (MinSize & 7) == 0; } + // Returns true if the type size is non-zero. + bool isNonZero() const { return MinSize != 0; } + + // Returns true if the type size is zero. + bool isZero() const { return MinSize == 0; } + // Casts to a uint64_t if this is a fixed-width size. // - // NOTE: This interface is obsolete and will be removed in a future version - // of LLVM in favour of calling getFixedSize() directly. + // This interface is deprecated and will be removed in a future version + // of LLVM in favour of upgrading uses that rely on this implicit conversion + // to uint64_t. Calls to functions that return a TypeSize should use the + // proper interfaces to TypeSize. + // In practice this is mostly calls to MVT/EVT::getSizeInBits(). + // + // To determine how to upgrade the code: + // + // if (<algorithm works for both scalable and fixed-width vectors>) + // use getKnownMinSize() + // else if (<algorithm works only for fixed-width vectors>) { + // if <algorithm can be adapted for both scalable and fixed-width vectors> + // update the algorithm and use getKnownMinSize() + // else + // bail out early for scalable vectors and use getFixedSize() + // } operator uint64_t() const { +#ifdef STRICT_FIXED_SIZE_VECTORS return getFixedSize(); +#else + if (isScalable()) + WithColor::warning() << "Compiler has made implicit assumption that " + "TypeSize is not scalable. This may or may not " + "lead to broken code.\n"; + return getKnownMinSize(); +#endif } // Additional convenience operators needed to avoid ambiguous parses. @@ -188,6 +229,10 @@ public: TypeSize operator/(int64_t RHS) const { return { MinSize / RHS, IsScalable }; } + + TypeSize NextPowerOf2() const { + return TypeSize(llvm::NextPowerOf2(MinSize), IsScalable); + } }; /// Returns a TypeSize with a known minimum size that is the next integer @@ -201,6 +246,21 @@ inline TypeSize alignTo(TypeSize Size, uint64_t Align) { Size.isScalable()}; } +template <> struct DenseMapInfo<ElementCount> { + static inline ElementCount getEmptyKey() { return {~0U, true}; } + static inline ElementCount getTombstoneKey() { return {~0U - 1, false}; } + static unsigned getHashValue(const ElementCount& EltCnt) { + if (EltCnt.Scalable) + return (EltCnt.Min * 37U) - 1U; + + return EltCnt.Min * 37U; + } + + static bool isEqual(const ElementCount& LHS, const ElementCount& RHS) { + return LHS == RHS; + } +}; + } // end namespace llvm #endif // LLVM_SUPPORT_TypeSize_H diff --git a/llvm/include/llvm/Support/VersionTuple.h b/llvm/include/llvm/Support/VersionTuple.h index f3eeea2f7b446..6f3711f06f1a0 100644 --- a/llvm/include/llvm/Support/VersionTuple.h +++ b/llvm/include/llvm/Support/VersionTuple.h @@ -14,13 +14,14 @@ #ifndef LLVM_SUPPORT_VERSIONTUPLE_H #define LLVM_SUPPORT_VERSIONTUPLE_H +#include "llvm/ADT/Hashing.h" #include "llvm/ADT/Optional.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/raw_ostream.h" #include <string> #include <tuple> namespace llvm { +class raw_ostream; +class StringRef; /// Represents a version number in the form major[.minor[.subminor[.build]]]. class VersionTuple { @@ -144,6 +145,10 @@ public: return !(X < Y); } + friend llvm::hash_code hash_value(const VersionTuple &VT) { + return llvm::hash_combine(VT.Major, VT.Minor, VT.Subminor, VT.Build); + } + /// Retrieve a string representation of the version number. std::string getAsString() const; diff --git a/llvm/include/llvm/Support/VirtualFileSystem.h b/llvm/include/llvm/Support/VirtualFileSystem.h index e45e6e7567863..af09c21085c5e 100644 --- a/llvm/include/llvm/Support/VirtualFileSystem.h +++ b/llvm/include/llvm/Support/VirtualFileSystem.h @@ -19,7 +19,6 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Twine.h" #include "llvm/Support/Chrono.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" @@ -38,6 +37,7 @@ namespace llvm { class MemoryBuffer; +class Twine; namespace vfs { @@ -506,10 +506,12 @@ getVFSFromYAML(std::unique_ptr<llvm::MemoryBuffer> Buffer, struct YAMLVFSEntry { template <typename T1, typename T2> - YAMLVFSEntry(T1 &&VPath, T2 &&RPath) - : VPath(std::forward<T1>(VPath)), RPath(std::forward<T2>(RPath)) {} + YAMLVFSEntry(T1 &&VPath, T2 &&RPath, bool IsDirectory = false) + : VPath(std::forward<T1>(VPath)), RPath(std::forward<T2>(RPath)), + IsDirectory(IsDirectory) {} std::string VPath; std::string RPath; + bool IsDirectory = false; }; class VFSFromYamlDirIterImpl; @@ -654,7 +656,7 @@ private: // In a RedirectingFileSystem, keys can be specified in Posix or Windows // style (or even a mixture of both), so this comparison helper allows // slashes (representing a root) to match backslashes (and vice versa). Note - // that, other than the root, patch components should not contain slashes or + // that, other than the root, path components should not contain slashes or // backslashes. bool pathComponentMatches(llvm::StringRef lhs, llvm::StringRef rhs) const { if ((CaseSensitive ? lhs.equals(rhs) : lhs.equals_lower(rhs))) @@ -705,16 +707,6 @@ private: bool IsFallthrough = true; /// @} - /// Virtual file paths and external files could be canonicalized without "..", - /// "." and "./" in their paths. FIXME: some unittests currently fail on - /// win32 when using remove_dots and remove_leading_dotslash on paths. - bool UseCanonicalizedPaths = -#ifdef _WIN32 - false; -#else - true; -#endif - RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS); /// Looks up the path <tt>[Start, End)</tt> in \p From, possibly @@ -781,10 +773,13 @@ class YAMLVFSWriter { Optional<bool> UseExternalNames; std::string OverlayDir; + void addEntry(StringRef VirtualPath, StringRef RealPath, bool IsDirectory); + public: YAMLVFSWriter() = default; void addFileMapping(StringRef VirtualPath, StringRef RealPath); + void addDirectoryMapping(StringRef VirtualPath, StringRef RealPath); void setCaseSensitivity(bool CaseSensitive) { IsCaseSensitive = CaseSensitive; diff --git a/llvm/include/llvm/Support/Windows/WindowsSupport.h b/llvm/include/llvm/Support/Windows/WindowsSupport.h new file mode 100644 index 0000000000000..bd5a90c2c3f00 --- /dev/null +++ b/llvm/include/llvm/Support/Windows/WindowsSupport.h @@ -0,0 +1,249 @@ +//===- WindowsSupport.h - Common Windows Include File -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines things specific to Windows implementations. In addition to +// providing some helpers for working with win32 APIs, this header wraps +// <windows.h> with some portability macros. Always include WindowsSupport.h +// instead of including <windows.h> directly. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Win32 code that +//=== is guaranteed to work on *all* Win32 variants. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_WINDOWSSUPPORT_H +#define LLVM_SUPPORT_WINDOWSSUPPORT_H + +// mingw-w64 tends to define it as 0x0502 in its headers. +#undef _WIN32_WINNT +#undef _WIN32_IE + +// Require at least Windows 7 API. +#define _WIN32_WINNT 0x0601 +#define _WIN32_IE 0x0800 // MinGW at it again. FIXME: verify if still needed. +#define WIN32_LEAN_AND_MEAN +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Config/config.h" // Get build system configuration settings +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Chrono.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/VersionTuple.h" +#include <cassert> +#include <string> +#include <system_error> +#include <windows.h> + +// Must be included after windows.h +#include <wincrypt.h> + +namespace llvm { + +/// Determines if the program is running on Windows 8 or newer. This +/// reimplements one of the helpers in the Windows 8.1 SDK, which are intended +/// to supercede raw calls to GetVersionEx. Old SDKs, Cygwin, and MinGW don't +/// yet have VersionHelpers.h, so we have our own helper. +bool RunningWindows8OrGreater(); + +/// Returns the Windows version as Major.Minor.0.BuildNumber. Uses +/// RtlGetVersion or GetVersionEx under the hood depending on what is available. +/// GetVersionEx is deprecated, but this API exposes the build number which can +/// be useful for working around certain kernel bugs. +llvm::VersionTuple GetWindowsOSVersion(); + +bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix); + +// Include GetLastError() in a fatal error message. +LLVM_ATTRIBUTE_NORETURN inline void ReportLastErrorFatal(const char *Msg) { + std::string ErrMsg; + MakeErrMsg(&ErrMsg, Msg); + llvm::report_fatal_error(ErrMsg); +} + +template <typename HandleTraits> +class ScopedHandle { + typedef typename HandleTraits::handle_type handle_type; + handle_type Handle; + + ScopedHandle(const ScopedHandle &other) = delete; + void operator=(const ScopedHandle &other) = delete; +public: + ScopedHandle() + : Handle(HandleTraits::GetInvalid()) {} + + explicit ScopedHandle(handle_type h) + : Handle(h) {} + + ~ScopedHandle() { + if (HandleTraits::IsValid(Handle)) + HandleTraits::Close(Handle); + } + + handle_type take() { + handle_type t = Handle; + Handle = HandleTraits::GetInvalid(); + return t; + } + + ScopedHandle &operator=(handle_type h) { + if (HandleTraits::IsValid(Handle)) + HandleTraits::Close(Handle); + Handle = h; + return *this; + } + + // True if Handle is valid. + explicit operator bool() const { + return HandleTraits::IsValid(Handle) ? true : false; + } + + operator handle_type() const { + return Handle; + } +}; + +struct CommonHandleTraits { + typedef HANDLE handle_type; + + static handle_type GetInvalid() { + return INVALID_HANDLE_VALUE; + } + + static void Close(handle_type h) { + ::CloseHandle(h); + } + + static bool IsValid(handle_type h) { + return h != GetInvalid(); + } +}; + +struct JobHandleTraits : CommonHandleTraits { + static handle_type GetInvalid() { + return NULL; + } +}; + +struct CryptContextTraits : CommonHandleTraits { + typedef HCRYPTPROV handle_type; + + static handle_type GetInvalid() { + return 0; + } + + static void Close(handle_type h) { + ::CryptReleaseContext(h, 0); + } + + static bool IsValid(handle_type h) { + return h != GetInvalid(); + } +}; + +struct RegTraits : CommonHandleTraits { + typedef HKEY handle_type; + + static handle_type GetInvalid() { + return NULL; + } + + static void Close(handle_type h) { + ::RegCloseKey(h); + } + + static bool IsValid(handle_type h) { + return h != GetInvalid(); + } +}; + +struct FindHandleTraits : CommonHandleTraits { + static void Close(handle_type h) { + ::FindClose(h); + } +}; + +struct FileHandleTraits : CommonHandleTraits {}; + +typedef ScopedHandle<CommonHandleTraits> ScopedCommonHandle; +typedef ScopedHandle<FileHandleTraits> ScopedFileHandle; +typedef ScopedHandle<CryptContextTraits> ScopedCryptContext; +typedef ScopedHandle<RegTraits> ScopedRegHandle; +typedef ScopedHandle<FindHandleTraits> ScopedFindHandle; +typedef ScopedHandle<JobHandleTraits> ScopedJobHandle; + +template <class T> +class SmallVectorImpl; + +template <class T> +typename SmallVectorImpl<T>::const_pointer +c_str(SmallVectorImpl<T> &str) { + str.push_back(0); + str.pop_back(); + return str.data(); +} + +namespace sys { + +inline std::chrono::nanoseconds toDuration(FILETIME Time) { + ULARGE_INTEGER TimeInteger; + TimeInteger.LowPart = Time.dwLowDateTime; + TimeInteger.HighPart = Time.dwHighDateTime; + + // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond) + return std::chrono::nanoseconds(100 * TimeInteger.QuadPart); +} + +inline TimePoint<> toTimePoint(FILETIME Time) { + ULARGE_INTEGER TimeInteger; + TimeInteger.LowPart = Time.dwLowDateTime; + TimeInteger.HighPart = Time.dwHighDateTime; + + // Adjust for different epoch + TimeInteger.QuadPart -= 11644473600ll * 10000000; + + // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond) + return TimePoint<>(std::chrono::nanoseconds(100 * TimeInteger.QuadPart)); +} + +inline FILETIME toFILETIME(TimePoint<> TP) { + ULARGE_INTEGER TimeInteger; + TimeInteger.QuadPart = TP.time_since_epoch().count() / 100; + TimeInteger.QuadPart += 11644473600ll * 10000000; + + FILETIME Time; + Time.dwLowDateTime = TimeInteger.LowPart; + Time.dwHighDateTime = TimeInteger.HighPart; + return Time; +} + +namespace windows { +// Returns command line arguments. Unlike arguments given to main(), +// this function guarantees that the returned arguments are encoded in +// UTF-8 regardless of the current code page setting. +std::error_code GetCommandLineArguments(SmallVectorImpl<const char *> &Args, + BumpPtrAllocator &Alloc); + +/// Convert UTF-8 path to a suitable UTF-16 path for use with the Win32 Unicode +/// File API. +std::error_code widenPath(const Twine &Path8, SmallVectorImpl<wchar_t> &Path16, + size_t MaxPathLen = MAX_PATH); + +} // end namespace windows +} // end namespace sys +} // end namespace llvm. + +#endif diff --git a/llvm/include/llvm/Support/WithColor.h b/llvm/include/llvm/Support/WithColor.h index f4e1075811794..eea4a72293392 100644 --- a/llvm/include/llvm/Support/WithColor.h +++ b/llvm/include/llvm/Support/WithColor.h @@ -9,14 +9,18 @@ #ifndef LLVM_SUPPORT_WITHCOLOR_H #define LLVM_SUPPORT_WITHCOLOR_H -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" namespace llvm { -extern cl::OptionCategory ColorCategory; +class Error; +class StringRef; + +namespace cl { +class OptionCategory; +} -class raw_ostream; +extern cl::OptionCategory ColorCategory; // Symbolic names for various syntax elements. enum class HighlightColor { @@ -32,31 +36,43 @@ enum class HighlightColor { Remark }; +enum class ColorMode { + /// Determine whether to use color based on the command line argument and the + /// raw_ostream. + Auto, + /// Enable colors. Because raw_ostream is the one implementing colors, this + /// has no effect if the stream does not support colors or has colors + /// disabled. + Enable, + /// Disable colors. + Disable, +}; + /// An RAII object that temporarily switches an output stream to a specific /// color. class WithColor { raw_ostream &OS; - bool DisableColors; + ColorMode Mode; public: /// To be used like this: WithColor(OS, HighlightColor::String) << "text"; /// @param OS The output stream /// @param S Symbolic name for syntax element to color - /// @param DisableColors Whether to ignore color changes regardless of -color - /// and support in OS - WithColor(raw_ostream &OS, HighlightColor S, bool DisableColors = false); + /// @param Mode Enable, disable or compute whether to use colors. + WithColor(raw_ostream &OS, HighlightColor S, + ColorMode Mode = ColorMode::Auto); /// To be used like this: WithColor(OS, raw_ostream::Black) << "text"; /// @param OS The output stream /// @param Color ANSI color to use, the special SAVEDCOLOR can be used to /// change only the bold attribute, and keep colors untouched /// @param Bold Bold/brighter text, default false /// @param BG If true, change the background, default: change foreground - /// @param DisableColors Whether to ignore color changes regardless of -color - /// and support in OS + /// @param Mode Enable, disable or compute whether to use colors. WithColor(raw_ostream &OS, raw_ostream::Colors Color = raw_ostream::SAVEDCOLOR, - bool Bold = false, bool BG = false, bool DisableColors = false) - : OS(OS), DisableColors(DisableColors) { + bool Bold = false, bool BG = false, + ColorMode Mode = ColorMode::Auto) + : OS(OS), Mode(Mode) { changeColor(Color, Bold, BG); } ~WithColor(); @@ -108,6 +124,14 @@ public: /// Reset the colors to terminal defaults. Call this when you are done /// outputting colored text, or before program exit. WithColor &resetColor(); + + /// Implement default handling for Error. + /// Print "error: " to stderr. + static void defaultErrorHandler(Error Err); + + /// Implement default handling for Warning. + /// Print "warning: " to stderr. + static void defaultWarningHandler(Error Warning); }; } // end namespace llvm diff --git a/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h b/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h index baf842b12a27b..5697ff9a01dc1 100644 --- a/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h +++ b/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h @@ -361,6 +361,7 @@ enum ModRMDecisionType { 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_SIB, "Force SIB operand in ModR/M byte.") \ 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") \ @@ -374,7 +375,7 @@ enum ModRMDecisionType { 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 " \ + ENUM_ENTRY(ENCODING_RB, "(AL..DIL, R8B..R15B) Register code added to " \ "the opcode byte") \ ENUM_ENTRY(ENCODING_RW, "(AX..DI, R8W..R15W)") \ ENUM_ENTRY(ENCODING_RD, "(EAX..EDI, R8D..R15D)") \ @@ -411,6 +412,7 @@ enum OperandEncoding { ENUM_ENTRY(TYPE_IMM, "immediate operand") \ ENUM_ENTRY(TYPE_UIMM8, "1-byte unsigned immediate operand") \ ENUM_ENTRY(TYPE_M, "Memory operand") \ + ENUM_ENTRY(TYPE_MSIB, "Memory operand force sib encoding") \ 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") \ @@ -424,6 +426,7 @@ enum OperandEncoding { ENUM_ENTRY(TYPE_ZMM, "64-byte") \ ENUM_ENTRY(TYPE_VK, "mask register") \ ENUM_ENTRY(TYPE_VK_PAIR, "mask register pair") \ + ENUM_ENTRY(TYPE_TMM, "tile") \ ENUM_ENTRY(TYPE_SEGMENTREG, "Segment register operand") \ ENUM_ENTRY(TYPE_DEBUGREG, "Debug register operand") \ ENUM_ENTRY(TYPE_CONTROLREG, "Control register operand") \ diff --git a/llvm/include/llvm/Support/X86TargetParser.def b/llvm/include/llvm/Support/X86TargetParser.def index 4ebf2d79cb8d6..697f8c70f962d 100644 --- a/llvm/include/llvm/Support/X86TargetParser.def +++ b/llvm/include/llvm/Support/X86TargetParser.def @@ -19,155 +19,176 @@ X86_VENDOR(VENDOR_INTEL, "intel") X86_VENDOR(VENDOR_AMD, "amd") #undef X86_VENDOR -// This macro is used to implement CPU types that have an alias. As of now -// there is only ever one alias. -#ifndef X86_CPU_TYPE_COMPAT_WITH_ALIAS -#define X86_CPU_TYPE_COMPAT_WITH_ALIAS(ARCHNAME, ENUM, STR, ALIAS) X86_CPU_TYPE_COMPAT(ARCHNAME, ENUM, STR) -#endif - // This macro is used for cpu types present in compiler-rt/libgcc. -#ifndef X86_CPU_TYPE_COMPAT -#define X86_CPU_TYPE_COMPAT(ARCHNAME, ENUM, STR) X86_CPU_TYPE(ARCHNAME, ENUM) +#ifndef X86_CPU_TYPE +#define X86_CPU_TYPE(ENUM, STR) #endif -#ifndef X86_CPU_TYPE -#define X86_CPU_TYPE(ARCHNAME, ENUM) +#ifndef X86_CPU_TYPE_ALIAS +#define X86_CPU_TYPE_ALIAS(ENUM, STR) #endif -// The first part of this list must match what is implemented in libgcc and -// compilert-rt. Clang uses this to know how to implement __builtin_cpu_is. -X86_CPU_TYPE_COMPAT_WITH_ALIAS("bonnell", INTEL_BONNELL, "bonnell", "atom") -X86_CPU_TYPE_COMPAT ("core2", INTEL_CORE2, "core2") -X86_CPU_TYPE_COMPAT ("nehalem", INTEL_COREI7, "corei7") -X86_CPU_TYPE_COMPAT_WITH_ALIAS("amdfam10", AMDFAM10H, "amdfam10h", "amdfam10") -X86_CPU_TYPE_COMPAT_WITH_ALIAS("bdver1", AMDFAM15H, "amdfam15h", "amdfam15") -X86_CPU_TYPE_COMPAT_WITH_ALIAS("silvermont", INTEL_SILVERMONT, "silvermont", "slm") -X86_CPU_TYPE_COMPAT ("knl", INTEL_KNL, "knl") -X86_CPU_TYPE_COMPAT ("btver1", AMD_BTVER1, "btver1") -X86_CPU_TYPE_COMPAT ("btver2", AMD_BTVER2, "btver2") -X86_CPU_TYPE_COMPAT ("znver1", AMDFAM17H, "amdfam17h") -X86_CPU_TYPE_COMPAT ("knm", INTEL_KNM, "knm") -X86_CPU_TYPE_COMPAT ("goldmont", INTEL_GOLDMONT, "goldmont") -X86_CPU_TYPE_COMPAT ("goldmont-plus", INTEL_GOLDMONT_PLUS, "goldmont-plus") -X86_CPU_TYPE_COMPAT ("tremont", INTEL_TREMONT, "tremont") -// Entries below this are not in libgcc/compiler-rt. -X86_CPU_TYPE ("i386", INTEL_i386) -X86_CPU_TYPE ("i486", INTEL_i486) -X86_CPU_TYPE ("pentium", INTEL_PENTIUM) -X86_CPU_TYPE ("pentium-mmx", INTEL_PENTIUM_MMX) -X86_CPU_TYPE ("pentiumpro", INTEL_PENTIUM_PRO) -X86_CPU_TYPE ("pentium2", INTEL_PENTIUM_II) -X86_CPU_TYPE ("pentium3", INTEL_PENTIUM_III) -X86_CPU_TYPE ("pentium4", INTEL_PENTIUM_IV) -X86_CPU_TYPE ("pentium-m", INTEL_PENTIUM_M) -X86_CPU_TYPE ("yonah", INTEL_CORE_DUO) -X86_CPU_TYPE ("nocona", INTEL_NOCONA) -X86_CPU_TYPE ("prescott", INTEL_PRESCOTT) -X86_CPU_TYPE ("i486", AMD_i486) -X86_CPU_TYPE ("pentium", AMDPENTIUM) -X86_CPU_TYPE ("athlon", AMD_ATHLON) -X86_CPU_TYPE ("athlon-xp", AMD_ATHLON_XP) -X86_CPU_TYPE ("k8", AMD_K8) -X86_CPU_TYPE ("k8-sse3", AMD_K8SSE3) -#undef X86_CPU_TYPE_COMPAT_WITH_ALIAS -#undef X86_CPU_TYPE_COMPAT + +// This list must match what is implemented in libgcc and compilert-rt. Clang +// uses this to know how to implement __builtin_cpu_is. +X86_CPU_TYPE(INTEL_BONNELL, "bonnell") +X86_CPU_TYPE(INTEL_CORE2, "core2") +X86_CPU_TYPE(INTEL_COREI7, "corei7") +X86_CPU_TYPE(AMDFAM10H, "amdfam10h") +X86_CPU_TYPE(AMDFAM15H, "amdfam15h") +X86_CPU_TYPE(INTEL_SILVERMONT, "silvermont") +X86_CPU_TYPE(INTEL_KNL, "knl") +X86_CPU_TYPE(AMD_BTVER1, "btver1") +X86_CPU_TYPE(AMD_BTVER2, "btver2") +X86_CPU_TYPE(AMDFAM17H, "amdfam17h") +X86_CPU_TYPE(INTEL_KNM, "knm") +X86_CPU_TYPE(INTEL_GOLDMONT, "goldmont") +X86_CPU_TYPE(INTEL_GOLDMONT_PLUS, "goldmont-plus") +X86_CPU_TYPE(INTEL_TREMONT, "tremont") + +// Alternate names supported by __builtin_cpu_is and target multiversioning. +X86_CPU_TYPE_ALIAS(INTEL_BONNELL, "atom") +X86_CPU_TYPE_ALIAS(AMDFAM10H, "amdfam10") +X86_CPU_TYPE_ALIAS(AMDFAM15H, "amdfam15") +X86_CPU_TYPE_ALIAS(INTEL_SILVERMONT, "slm") + +#undef X86_CPU_TYPE_ALIAS #undef X86_CPU_TYPE // This macro is used for cpu subtypes present in compiler-rt/libgcc. -#ifndef X86_CPU_SUBTYPE_COMPAT -#define X86_CPU_SUBTYPE_COMPAT(ARCHNAME, ENUM, STR) X86_CPU_SUBTYPE(ARCHNAME, ENUM) -#endif - #ifndef X86_CPU_SUBTYPE -#define X86_CPU_SUBTYPE(ARCHNAME, ENUM) +#define X86_CPU_SUBTYPE(ENUM, STR) #endif -// The first part of this list must match what is implemented in libgcc and -// compilert-rt. Clang uses this to know how to implement __builtin_cpu_is. -X86_CPU_SUBTYPE_COMPAT("nehalem", INTEL_COREI7_NEHALEM, "nehalem") -X86_CPU_SUBTYPE_COMPAT("westmere", INTEL_COREI7_WESTMERE, "westmere") -X86_CPU_SUBTYPE_COMPAT("sandybridge", INTEL_COREI7_SANDYBRIDGE, "sandybridge") -X86_CPU_SUBTYPE_COMPAT("amdfam10", AMDFAM10H_BARCELONA, "barcelona") -X86_CPU_SUBTYPE_COMPAT("amdfam10", AMDFAM10H_SHANGHAI, "shanghai") -X86_CPU_SUBTYPE_COMPAT("amdfam10", AMDFAM10H_ISTANBUL, "istanbul") -X86_CPU_SUBTYPE_COMPAT("bdver1", AMDFAM15H_BDVER1, "bdver1") -X86_CPU_SUBTYPE_COMPAT("bdver2", AMDFAM15H_BDVER2, "bdver2") -X86_CPU_SUBTYPE_COMPAT("bdver3", AMDFAM15H_BDVER3, "bdver3") -X86_CPU_SUBTYPE_COMPAT("bdver4", AMDFAM15H_BDVER4, "bdver4") -X86_CPU_SUBTYPE_COMPAT("znver1", AMDFAM17H_ZNVER1, "znver1") -X86_CPU_SUBTYPE_COMPAT("ivybridge", INTEL_COREI7_IVYBRIDGE, "ivybridge") -X86_CPU_SUBTYPE_COMPAT("haswell", INTEL_COREI7_HASWELL, "haswell") -X86_CPU_SUBTYPE_COMPAT("broadwell", INTEL_COREI7_BROADWELL, "broadwell") -X86_CPU_SUBTYPE_COMPAT("skylake", INTEL_COREI7_SKYLAKE, "skylake") -X86_CPU_SUBTYPE_COMPAT("skylake-avx512", INTEL_COREI7_SKYLAKE_AVX512, "skylake-avx512") -X86_CPU_SUBTYPE_COMPAT("cannonlake", INTEL_COREI7_CANNONLAKE, "cannonlake") -X86_CPU_SUBTYPE_COMPAT("icelake-client", INTEL_COREI7_ICELAKE_CLIENT, "icelake-client") -X86_CPU_SUBTYPE_COMPAT("icelake-server", INTEL_COREI7_ICELAKE_SERVER, "icelake-server") -X86_CPU_SUBTYPE_COMPAT("znver2", AMDFAM17H_ZNVER2, "znver2") -X86_CPU_SUBTYPE_COMPAT("cascadelake", INTEL_COREI7_CASCADELAKE, "cascadelake") -// Entries below this are not in libgcc/compiler-rt. -X86_CPU_SUBTYPE ("core2", INTEL_CORE2_65) -X86_CPU_SUBTYPE ("penryn", INTEL_CORE2_45) -X86_CPU_SUBTYPE ("k6", AMDPENTIUM_K6) -X86_CPU_SUBTYPE ("k6-2", AMDPENTIUM_K62) -X86_CPU_SUBTYPE ("k6-3", AMDPENTIUM_K63) -X86_CPU_SUBTYPE ("geode", AMDPENTIUM_GEODE) -X86_CPU_SUBTYPE ("cooperlake", INTEL_COREI7_COOPERLAKE) -X86_CPU_SUBTYPE ("tigerlake", INTEL_COREI7_TIGERLAKE) -#undef X86_CPU_SUBTYPE_COMPAT +// This list must match what is implemented in libgcc and compilert-rt. Clang +// uses this to know how to implement __builtin_cpu_is. +X86_CPU_SUBTYPE(INTEL_COREI7_NEHALEM, "nehalem") +X86_CPU_SUBTYPE(INTEL_COREI7_WESTMERE, "westmere") +X86_CPU_SUBTYPE(INTEL_COREI7_SANDYBRIDGE, "sandybridge") +X86_CPU_SUBTYPE(AMDFAM10H_BARCELONA, "barcelona") +X86_CPU_SUBTYPE(AMDFAM10H_SHANGHAI, "shanghai") +X86_CPU_SUBTYPE(AMDFAM10H_ISTANBUL, "istanbul") +X86_CPU_SUBTYPE(AMDFAM15H_BDVER1, "bdver1") +X86_CPU_SUBTYPE(AMDFAM15H_BDVER2, "bdver2") +X86_CPU_SUBTYPE(AMDFAM15H_BDVER3, "bdver3") +X86_CPU_SUBTYPE(AMDFAM15H_BDVER4, "bdver4") +X86_CPU_SUBTYPE(AMDFAM17H_ZNVER1, "znver1") +X86_CPU_SUBTYPE(INTEL_COREI7_IVYBRIDGE, "ivybridge") +X86_CPU_SUBTYPE(INTEL_COREI7_HASWELL, "haswell") +X86_CPU_SUBTYPE(INTEL_COREI7_BROADWELL, "broadwell") +X86_CPU_SUBTYPE(INTEL_COREI7_SKYLAKE, "skylake") +X86_CPU_SUBTYPE(INTEL_COREI7_SKYLAKE_AVX512, "skylake-avx512") +X86_CPU_SUBTYPE(INTEL_COREI7_CANNONLAKE, "cannonlake") +X86_CPU_SUBTYPE(INTEL_COREI7_ICELAKE_CLIENT, "icelake-client") +X86_CPU_SUBTYPE(INTEL_COREI7_ICELAKE_SERVER, "icelake-server") +X86_CPU_SUBTYPE(AMDFAM17H_ZNVER2, "znver2") +X86_CPU_SUBTYPE(INTEL_COREI7_CASCADELAKE, "cascadelake") +X86_CPU_SUBTYPE(INTEL_COREI7_TIGERLAKE, "tigerlake") +X86_CPU_SUBTYPE(INTEL_COREI7_COOPERLAKE, "cooperlake") #undef X86_CPU_SUBTYPE // This macro is used for cpu types present in compiler-rt/libgcc. #ifndef X86_FEATURE_COMPAT -#define X86_FEATURE_COMPAT(VAL, ENUM, STR) X86_FEATURE(VAL, ENUM) +#define X86_FEATURE_COMPAT(ENUM, STR) X86_FEATURE(ENUM, STR) #endif #ifndef X86_FEATURE -#define X86_FEATURE(VAL, ENUM) +#define X86_FEATURE(ENUM, STR) #endif -X86_FEATURE_COMPAT( 0, FEATURE_CMOV, "cmov") -X86_FEATURE_COMPAT( 1, FEATURE_MMX, "mmx") -X86_FEATURE_COMPAT( 2, FEATURE_POPCNT, "popcnt") -X86_FEATURE_COMPAT( 3, FEATURE_SSE, "sse") -X86_FEATURE_COMPAT( 4, FEATURE_SSE2, "sse2") -X86_FEATURE_COMPAT( 5, FEATURE_SSE3, "sse3") -X86_FEATURE_COMPAT( 6, FEATURE_SSSE3, "ssse3") -X86_FEATURE_COMPAT( 7, FEATURE_SSE4_1, "sse4.1") -X86_FEATURE_COMPAT( 8, FEATURE_SSE4_2, "sse4.2") -X86_FEATURE_COMPAT( 9, FEATURE_AVX, "avx") -X86_FEATURE_COMPAT(10, FEATURE_AVX2, "avx2") -X86_FEATURE_COMPAT(11, FEATURE_SSE4_A, "sse4a") -X86_FEATURE_COMPAT(12, FEATURE_FMA4, "fma4") -X86_FEATURE_COMPAT(13, FEATURE_XOP, "xop") -X86_FEATURE_COMPAT(14, FEATURE_FMA, "fma") -X86_FEATURE_COMPAT(15, FEATURE_AVX512F, "avx512f") -X86_FEATURE_COMPAT(16, FEATURE_BMI, "bmi") -X86_FEATURE_COMPAT(17, FEATURE_BMI2, "bmi2") -X86_FEATURE_COMPAT(18, FEATURE_AES, "aes") -X86_FEATURE_COMPAT(19, FEATURE_PCLMUL, "pclmul") -X86_FEATURE_COMPAT(20, FEATURE_AVX512VL, "avx512vl") -X86_FEATURE_COMPAT(21, FEATURE_AVX512BW, "avx512bw") -X86_FEATURE_COMPAT(22, FEATURE_AVX512DQ, "avx512dq") -X86_FEATURE_COMPAT(23, FEATURE_AVX512CD, "avx512cd") -X86_FEATURE_COMPAT(24, FEATURE_AVX512ER, "avx512er") -X86_FEATURE_COMPAT(25, FEATURE_AVX512PF, "avx512pf") -X86_FEATURE_COMPAT(26, FEATURE_AVX512VBMI, "avx512vbmi") -X86_FEATURE_COMPAT(27, FEATURE_AVX512IFMA, "avx512ifma") -X86_FEATURE_COMPAT(28, FEATURE_AVX5124VNNIW, "avx5124vnniw") -X86_FEATURE_COMPAT(29, FEATURE_AVX5124FMAPS, "avx5124fmaps") -X86_FEATURE_COMPAT(30, FEATURE_AVX512VPOPCNTDQ, "avx512vpopcntdq") -X86_FEATURE_COMPAT(31, FEATURE_AVX512VBMI2, "avx512vbmi2") -X86_FEATURE_COMPAT(32, FEATURE_GFNI, "gfni") -X86_FEATURE_COMPAT(33, FEATURE_VPCLMULQDQ, "vpclmulqdq") -X86_FEATURE_COMPAT(34, FEATURE_AVX512VNNI, "avx512vnni") -X86_FEATURE_COMPAT(35, FEATURE_AVX512BITALG, "avx512bitalg") -X86_FEATURE_COMPAT(36, FEATURE_AVX512BF16, "avx512bf16") + +X86_FEATURE_COMPAT(CMOV, "cmov") +X86_FEATURE_COMPAT(MMX, "mmx") +X86_FEATURE_COMPAT(POPCNT, "popcnt") +X86_FEATURE_COMPAT(SSE, "sse") +X86_FEATURE_COMPAT(SSE2, "sse2") +X86_FEATURE_COMPAT(SSE3, "sse3") +X86_FEATURE_COMPAT(SSSE3, "ssse3") +X86_FEATURE_COMPAT(SSE4_1, "sse4.1") +X86_FEATURE_COMPAT(SSE4_2, "sse4.2") +X86_FEATURE_COMPAT(AVX, "avx") +X86_FEATURE_COMPAT(AVX2, "avx2") +X86_FEATURE_COMPAT(SSE4_A, "sse4a") +X86_FEATURE_COMPAT(FMA4, "fma4") +X86_FEATURE_COMPAT(XOP, "xop") +X86_FEATURE_COMPAT(FMA, "fma") +X86_FEATURE_COMPAT(AVX512F, "avx512f") +X86_FEATURE_COMPAT(BMI, "bmi") +X86_FEATURE_COMPAT(BMI2, "bmi2") +X86_FEATURE_COMPAT(AES, "aes") +X86_FEATURE_COMPAT(PCLMUL, "pclmul") +X86_FEATURE_COMPAT(AVX512VL, "avx512vl") +X86_FEATURE_COMPAT(AVX512BW, "avx512bw") +X86_FEATURE_COMPAT(AVX512DQ, "avx512dq") +X86_FEATURE_COMPAT(AVX512CD, "avx512cd") +X86_FEATURE_COMPAT(AVX512ER, "avx512er") +X86_FEATURE_COMPAT(AVX512PF, "avx512pf") +X86_FEATURE_COMPAT(AVX512VBMI, "avx512vbmi") +X86_FEATURE_COMPAT(AVX512IFMA, "avx512ifma") +X86_FEATURE_COMPAT(AVX5124VNNIW, "avx5124vnniw") +X86_FEATURE_COMPAT(AVX5124FMAPS, "avx5124fmaps") +X86_FEATURE_COMPAT(AVX512VPOPCNTDQ, "avx512vpopcntdq") +X86_FEATURE_COMPAT(AVX512VBMI2, "avx512vbmi2") +X86_FEATURE_COMPAT(GFNI, "gfni") +X86_FEATURE_COMPAT(VPCLMULQDQ, "vpclmulqdq") +X86_FEATURE_COMPAT(AVX512VNNI, "avx512vnni") +X86_FEATURE_COMPAT(AVX512BITALG, "avx512bitalg") +X86_FEATURE_COMPAT(AVX512BF16, "avx512bf16") +X86_FEATURE_COMPAT(AVX512VP2INTERSECT, "avx512vp2intersect") // Features below here are not in libgcc/compiler-rt. -X86_FEATURE (64, FEATURE_MOVBE) -X86_FEATURE (65, FEATURE_ADX) -X86_FEATURE (66, FEATURE_EM64T) -X86_FEATURE (67, FEATURE_CLFLUSHOPT) -X86_FEATURE (68, FEATURE_SHA) -X86_FEATURE (69, FEATURE_AVX512VP2INTERSECT) +X86_FEATURE (3DNOW, "3dnow") +X86_FEATURE (3DNOWA, "3dnowa") +X86_FEATURE (64BIT, "64bit") +X86_FEATURE (ADX, "adx") +X86_FEATURE (AMX_BF16, "amx-bf16") +X86_FEATURE (AMX_INT8, "amx-int8") +X86_FEATURE (AMX_TILE, "amx-tile") +X86_FEATURE (CLDEMOTE, "cldemote") +X86_FEATURE (CLFLUSHOPT, "clflushopt") +X86_FEATURE (CLWB, "clwb") +X86_FEATURE (CLZERO, "clzero") +X86_FEATURE (CMPXCHG16B, "cx16") +X86_FEATURE (CMPXCHG8B, "cx8") +X86_FEATURE (ENQCMD, "enqcmd") +X86_FEATURE (F16C, "f16c") +X86_FEATURE (FSGSBASE, "fsgsbase") +X86_FEATURE (FXSR, "fxsr") +X86_FEATURE (INVPCID, "invpcid") +X86_FEATURE (LWP, "lwp") +X86_FEATURE (LZCNT, "lzcnt") +X86_FEATURE (MOVBE, "movbe") +X86_FEATURE (MOVDIR64B, "movdir64b") +X86_FEATURE (MOVDIRI, "movdiri") +X86_FEATURE (MWAITX, "mwaitx") +X86_FEATURE (PCONFIG, "pconfig") +X86_FEATURE (PKU, "pku") +X86_FEATURE (PREFETCHWT1, "prefetchwt1") +X86_FEATURE (PRFCHW, "prfchw") +X86_FEATURE (PTWRITE, "ptwrite") +X86_FEATURE (RDPID, "rdpid") +X86_FEATURE (RDRND, "rdrnd") +X86_FEATURE (RDSEED, "rdseed") +X86_FEATURE (RTM, "rtm") +X86_FEATURE (SAHF, "sahf") +X86_FEATURE (SERIALIZE, "serialize") +X86_FEATURE (SGX, "sgx") +X86_FEATURE (SHA, "sha") +X86_FEATURE (SHSTK, "shstk") +X86_FEATURE (TBM, "tbm") +X86_FEATURE (TSXLDTRK, "tsxldtrk") +X86_FEATURE (VAES, "vaes") +X86_FEATURE (VZEROUPPER, "vzeroupper") +X86_FEATURE (WAITPKG, "waitpkg") +X86_FEATURE (WBNOINVD, "wbnoinvd") +X86_FEATURE (X87, "x87") +X86_FEATURE (XSAVE, "xsave") +X86_FEATURE (XSAVEC, "xsavec") +X86_FEATURE (XSAVEOPT, "xsaveopt") +X86_FEATURE (XSAVES, "xsaves") +// These features aren't really CPU features, but the frontend can set them. +X86_FEATURE (RETPOLINE_EXTERNAL_THUNK, "retpoline-external-thunk") +X86_FEATURE (RETPOLINE_INDIRECT_BRANCHES, "retpoline-indirect-branches") +X86_FEATURE (RETPOLINE_INDIRECT_CALLS, "retpoline-indirect-calls") +X86_FEATURE (LVI_CFI, "lvi-cfi") +X86_FEATURE (LVI_LOAD_HARDENING, "lvi-load-hardening") #undef X86_FEATURE_COMPAT #undef X86_FEATURE diff --git a/llvm/include/llvm/Support/X86TargetParser.h b/llvm/include/llvm/Support/X86TargetParser.h new file mode 100644 index 0000000000000..66c474b5c2750 --- /dev/null +++ b/llvm/include/llvm/Support/X86TargetParser.h @@ -0,0 +1,148 @@ +//===-- X86TargetParser - Parser for X86 features ---------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements a target parser to recognise X86 hardware features. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_X86TARGETPARSERCOMMON_H +#define LLVM_SUPPORT_X86TARGETPARSERCOMMON_H + +#include "llvm/ADT/SmallVector.h" + +namespace llvm { +class StringRef; + +namespace X86 { + +// This should be kept in sync with libcc/compiler-rt as its included by clang +// as a proxy for what's in libgcc/compiler-rt. +enum ProcessorVendors : unsigned { + VENDOR_DUMMY, +#define X86_VENDOR(ENUM, STRING) \ + ENUM, +#include "llvm/Support/X86TargetParser.def" + VENDOR_OTHER +}; + +// This should be kept in sync with libcc/compiler-rt as its included by clang +// as a proxy for what's in libgcc/compiler-rt. +enum ProcessorTypes : unsigned { + CPU_TYPE_DUMMY, +#define X86_CPU_TYPE(ENUM, STRING) \ + ENUM, +#include "llvm/Support/X86TargetParser.def" + CPU_TYPE_MAX +}; + +// This should be kept in sync with libcc/compiler-rt as its included by clang +// as a proxy for what's in libgcc/compiler-rt. +enum ProcessorSubtypes : unsigned { + CPU_SUBTYPE_DUMMY, +#define X86_CPU_SUBTYPE(ENUM, STRING) \ + ENUM, +#include "llvm/Support/X86TargetParser.def" + CPU_SUBTYPE_MAX +}; + +// This should be kept in sync with libcc/compiler-rt as it should be used +// by clang as a proxy for what's in libgcc/compiler-rt. +enum ProcessorFeatures { +#define X86_FEATURE(ENUM, STRING) FEATURE_##ENUM, +#include "llvm/Support/X86TargetParser.def" + CPU_FEATURE_MAX +}; + +enum CPUKind { + CK_None, + CK_i386, + CK_i486, + CK_WinChipC6, + CK_WinChip2, + CK_C3, + CK_i586, + CK_Pentium, + CK_PentiumMMX, + CK_PentiumPro, + CK_i686, + CK_Pentium2, + CK_Pentium3, + CK_PentiumM, + CK_C3_2, + CK_Yonah, + CK_Pentium4, + CK_Prescott, + CK_Nocona, + CK_Core2, + CK_Penryn, + CK_Bonnell, + CK_Silvermont, + CK_Goldmont, + CK_GoldmontPlus, + CK_Tremont, + CK_Nehalem, + CK_Westmere, + CK_SandyBridge, + CK_IvyBridge, + CK_Haswell, + CK_Broadwell, + CK_SkylakeClient, + CK_SkylakeServer, + CK_Cascadelake, + CK_Cooperlake, + CK_Cannonlake, + CK_IcelakeClient, + CK_IcelakeServer, + CK_Tigerlake, + CK_KNL, + CK_KNM, + CK_Lakemont, + CK_K6, + CK_K6_2, + CK_K6_3, + CK_Athlon, + CK_AthlonXP, + CK_K8, + CK_K8SSE3, + CK_AMDFAM10, + CK_BTVER1, + CK_BTVER2, + CK_BDVER1, + CK_BDVER2, + CK_BDVER3, + CK_BDVER4, + CK_ZNVER1, + CK_ZNVER2, + CK_x86_64, + CK_Geode, +}; + +/// Parse \p CPU string into a CPUKind. Will only accept 64-bit capable CPUs if +/// \p Only64Bit is true. +CPUKind parseArchX86(StringRef CPU, bool Only64Bit = false); + +/// Provide a list of valid CPU names. If \p Only64Bit is true, the list will +/// only contain 64-bit capable CPUs. +void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values, + bool ArchIs32Bit); + +/// Get the key feature prioritizing target multiversioning. +ProcessorFeatures getKeyFeature(CPUKind Kind); + +/// Fill in the features that \p CPU supports into \p Features. +void getFeaturesForCPU(StringRef CPU, SmallVectorImpl<StringRef> &Features); + +/// Fill \p Features with the features that are implied to be enabled/disabled +/// by the provided \p Feature. +void getImpliedFeatures(StringRef Feature, bool Enabled, + SmallVectorImpl<StringRef> &Features); + +} // namespace X86 +} // namespace llvm + +#endif diff --git a/llvm/include/llvm/Support/YAMLParser.h b/llvm/include/llvm/Support/YAMLParser.h index 3570119a3bfdb..53009d7ff4aad 100644 --- a/llvm/include/llvm/Support/YAMLParser.h +++ b/llvm/include/llvm/Support/YAMLParser.h @@ -139,7 +139,7 @@ public: void operator delete(void *Ptr, BumpPtrAllocator &Alloc, size_t Size) noexcept { - Alloc.Deallocate(Ptr, Size); + Alloc.Deallocate(Ptr, Size, 0); } void operator delete(void *) noexcept = delete; diff --git a/llvm/include/llvm/Support/YAMLTraits.h b/llvm/include/llvm/Support/YAMLTraits.h index 8642069ad540c..44e34a4a09b46 100644 --- a/llvm/include/llvm/Support/YAMLTraits.h +++ b/llvm/include/llvm/Support/YAMLTraits.h @@ -649,24 +649,25 @@ inline bool isBool(StringRef S) { inline QuotingType needsQuotes(StringRef S) { if (S.empty()) return QuotingType::Single; - if (isspace(static_cast<unsigned char>(S.front())) || - isspace(static_cast<unsigned char>(S.back()))) - return QuotingType::Single; + + QuotingType MaxQuotingNeeded = QuotingType::None; + if (isSpace(static_cast<unsigned char>(S.front())) || + isSpace(static_cast<unsigned char>(S.back()))) + MaxQuotingNeeded = QuotingType::Single; if (isNull(S)) - return QuotingType::Single; + MaxQuotingNeeded = QuotingType::Single; if (isBool(S)) - return QuotingType::Single; + MaxQuotingNeeded = QuotingType::Single; if (isNumeric(S)) - return QuotingType::Single; + MaxQuotingNeeded = 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; + MaxQuotingNeeded = QuotingType::Single; - QuotingType MaxQuotingNeeded = QuotingType::None; for (unsigned char C : S) { // Alphanum is safe. if (isAlnum(C)) @@ -684,11 +685,11 @@ inline QuotingType needsQuotes(StringRef S) { case 0x9: continue; // LF(0xA) and CR(0xD) may delimit values and so require at least single - // quotes. + // quotes. LLVM YAML parser cannot handle single quoted multiline so use + // double quoting to produce valid YAML. case 0xA: case 0xD: - MaxQuotingNeeded = QuotingType::Single; - continue; + return QuotingType::Double; // DEL (0x7F) are excluded from the allowed character range. case 0x7F: return QuotingType::Double; @@ -868,7 +869,7 @@ public: } template <typename T, typename Context> - typename std::enable_if<has_SequenceTraits<T>::value, void>::type + std::enable_if_t<has_SequenceTraits<T>::value, void> mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) { // omit key/value instead of outputting empty sequence if (this->canElideEmptySequence() && !(Val.begin() != Val.end())) @@ -883,7 +884,7 @@ public: } template <typename T, typename Context> - typename std::enable_if<!has_SequenceTraits<T>::value, void>::type + std::enable_if_t<!has_SequenceTraits<T>::value, void> mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) { this->processKey(Key, Val, false, Ctx); } @@ -965,7 +966,7 @@ template <typename T> void doMapping(IO &io, T &Val, EmptyContext &Ctx) { } // end namespace detail template <typename T> -typename std::enable_if<has_ScalarEnumerationTraits<T>::value, void>::type +std::enable_if_t<has_ScalarEnumerationTraits<T>::value, void> yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { io.beginEnumScalar(); ScalarEnumerationTraits<T>::enumeration(io, Val); @@ -973,7 +974,7 @@ yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { } template <typename T> -typename std::enable_if<has_ScalarBitSetTraits<T>::value, void>::type +std::enable_if_t<has_ScalarBitSetTraits<T>::value, void> yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { bool DoClear; if ( io.beginBitSetScalar(DoClear) ) { @@ -985,8 +986,8 @@ yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { } template <typename T> -typename std::enable_if<has_ScalarTraits<T>::value, void>::type -yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { +std::enable_if_t<has_ScalarTraits<T>::value, void> yamlize(IO &io, T &Val, bool, + EmptyContext &Ctx) { if ( io.outputting() ) { std::string Storage; raw_string_ostream Buffer(Storage); @@ -1005,7 +1006,7 @@ yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { } template <typename T> -typename std::enable_if<has_BlockScalarTraits<T>::value, void>::type +std::enable_if_t<has_BlockScalarTraits<T>::value, void> yamlize(IO &YamlIO, T &Val, bool, EmptyContext &Ctx) { if (YamlIO.outputting()) { std::string Storage; @@ -1024,7 +1025,7 @@ yamlize(IO &YamlIO, T &Val, bool, EmptyContext &Ctx) { } template <typename T> -typename std::enable_if<has_TaggedScalarTraits<T>::value, void>::type +std::enable_if_t<has_TaggedScalarTraits<T>::value, void> yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { if (io.outputting()) { std::string ScalarStorage, TagStorage; @@ -1049,7 +1050,7 @@ yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { } template <typename T, typename Context> -typename std::enable_if<validatedMappingTraits<T, Context>::value, void>::type +std::enable_if_t<validatedMappingTraits<T, Context>::value, void> yamlize(IO &io, T &Val, bool, Context &Ctx) { if (has_FlowTraits<MappingTraits<T>>::value) io.beginFlowMapping(); @@ -1075,7 +1076,7 @@ yamlize(IO &io, T &Val, bool, Context &Ctx) { } template <typename T, typename Context> -typename std::enable_if<unvalidatedMappingTraits<T, Context>::value, void>::type +std::enable_if_t<unvalidatedMappingTraits<T, Context>::value, void> yamlize(IO &io, T &Val, bool, Context &Ctx) { if (has_FlowTraits<MappingTraits<T>>::value) { io.beginFlowMapping(); @@ -1089,7 +1090,7 @@ yamlize(IO &io, T &Val, bool, Context &Ctx) { } template <typename T> -typename std::enable_if<has_CustomMappingTraits<T>::value, void>::type +std::enable_if_t<has_CustomMappingTraits<T>::value, void> yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { if ( io.outputting() ) { io.beginMapping(); @@ -1104,7 +1105,7 @@ yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { } template <typename T> -typename std::enable_if<has_PolymorphicTraits<T>::value, void>::type +std::enable_if_t<has_PolymorphicTraits<T>::value, void> yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { switch (io.outputting() ? PolymorphicTraits<T>::getKind(Val) : io.getNodeKind()) { @@ -1118,13 +1119,13 @@ yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { } template <typename T> -typename std::enable_if<missingTraits<T, EmptyContext>::value, void>::type +std::enable_if_t<missingTraits<T, EmptyContext>::value, void> yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; } template <typename T, typename Context> -typename std::enable_if<has_SequenceTraits<T>::value, void>::type +std::enable_if_t<has_SequenceTraits<T>::value, void> yamlize(IO &io, T &Seq, bool, Context &Ctx) { if ( has_FlowTraits< SequenceTraits<T>>::value ) { unsigned incnt = io.beginFlowSequence(); @@ -1247,10 +1248,9 @@ struct ScalarTraits<double> { // type. This way endian aware types are supported whenever the traits are // defined for the underlying type. template <typename value_type, support::endianness endian, size_t alignment> -struct ScalarTraits< - support::detail::packed_endian_specific_integral<value_type, endian, - alignment>, - typename std::enable_if<has_ScalarTraits<value_type>::value>::type> { +struct ScalarTraits<support::detail::packed_endian_specific_integral< + value_type, endian, alignment>, + std::enable_if_t<has_ScalarTraits<value_type>::value>> { using endian_type = support::detail::packed_endian_specific_integral<value_type, endian, alignment>; @@ -1275,8 +1275,7 @@ template <typename value_type, support::endianness endian, size_t alignment> struct ScalarEnumerationTraits< support::detail::packed_endian_specific_integral<value_type, endian, alignment>, - typename std::enable_if< - has_ScalarEnumerationTraits<value_type>::value>::type> { + std::enable_if_t<has_ScalarEnumerationTraits<value_type>::value>> { using endian_type = support::detail::packed_endian_specific_integral<value_type, endian, alignment>; @@ -1292,7 +1291,7 @@ template <typename value_type, support::endianness endian, size_t alignment> struct ScalarBitSetTraits< support::detail::packed_endian_specific_integral<value_type, endian, alignment>, - typename std::enable_if<has_ScalarBitSetTraits<value_type>::value>::type> { + std::enable_if_t<has_ScalarBitSetTraits<value_type>::value>> { using endian_type = support::detail::packed_endian_specific_integral<value_type, endian, alignment>; @@ -1688,8 +1687,7 @@ struct ScalarTraits<Hex64> { // Define non-member operator>> so that Input can stream in a document list. template <typename T> -inline -typename std::enable_if<has_DocumentListTraits<T>::value, Input &>::type +inline std::enable_if_t<has_DocumentListTraits<T>::value, Input &> operator>>(Input &yin, T &docList) { int i = 0; EmptyContext Ctx; @@ -1705,8 +1703,7 @@ operator>>(Input &yin, T &docList) { // Define non-member operator>> so that Input can stream in a map as a document. template <typename T> -inline typename std::enable_if<has_MappingTraits<T, EmptyContext>::value, - Input &>::type +inline std::enable_if_t<has_MappingTraits<T, EmptyContext>::value, Input &> operator>>(Input &yin, T &docMap) { EmptyContext Ctx; yin.setCurrentDocument(); @@ -1717,8 +1714,7 @@ operator>>(Input &yin, T &docMap) { // Define non-member operator>> so that Input can stream in a sequence as // a document. template <typename T> -inline -typename std::enable_if<has_SequenceTraits<T>::value, Input &>::type +inline std::enable_if_t<has_SequenceTraits<T>::value, Input &> operator>>(Input &yin, T &docSeq) { EmptyContext Ctx; if (yin.setCurrentDocument()) @@ -1728,8 +1724,7 @@ operator>>(Input &yin, T &docSeq) { // Define non-member operator>> so that Input can stream in a block scalar. template <typename T> -inline -typename std::enable_if<has_BlockScalarTraits<T>::value, Input &>::type +inline std::enable_if_t<has_BlockScalarTraits<T>::value, Input &> operator>>(Input &In, T &Val) { EmptyContext Ctx; if (In.setCurrentDocument()) @@ -1739,8 +1734,7 @@ operator>>(Input &In, T &Val) { // Define non-member operator>> so that Input can stream in a string map. template <typename T> -inline -typename std::enable_if<has_CustomMappingTraits<T>::value, Input &>::type +inline std::enable_if_t<has_CustomMappingTraits<T>::value, Input &> operator>>(Input &In, T &Val) { EmptyContext Ctx; if (In.setCurrentDocument()) @@ -1750,7 +1744,7 @@ operator>>(Input &In, T &Val) { // Define non-member operator>> so that Input can stream in a polymorphic type. template <typename T> -inline typename std::enable_if<has_PolymorphicTraits<T>::value, Input &>::type +inline std::enable_if_t<has_PolymorphicTraits<T>::value, Input &> operator>>(Input &In, T &Val) { EmptyContext Ctx; if (In.setCurrentDocument()) @@ -1760,8 +1754,7 @@ operator>>(Input &In, T &Val) { // Provide better error message about types missing a trait specialization template <typename T> -inline typename std::enable_if<missingTraits<T, EmptyContext>::value, - Input &>::type +inline std::enable_if_t<missingTraits<T, EmptyContext>::value, Input &> operator>>(Input &yin, T &docSeq) { char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; return yin; @@ -1769,8 +1762,7 @@ operator>>(Input &yin, T &docSeq) { // Define non-member operator<< so that Output can stream out document list. template <typename T> -inline -typename std::enable_if<has_DocumentListTraits<T>::value, Output &>::type +inline std::enable_if_t<has_DocumentListTraits<T>::value, Output &> operator<<(Output &yout, T &docList) { EmptyContext Ctx; yout.beginDocuments(); @@ -1788,8 +1780,7 @@ operator<<(Output &yout, T &docList) { // Define non-member operator<< so that Output can stream out a map. template <typename T> -inline typename std::enable_if<has_MappingTraits<T, EmptyContext>::value, - Output &>::type +inline std::enable_if_t<has_MappingTraits<T, EmptyContext>::value, Output &> operator<<(Output &yout, T &map) { EmptyContext Ctx; yout.beginDocuments(); @@ -1803,8 +1794,7 @@ operator<<(Output &yout, T &map) { // Define non-member operator<< so that Output can stream out a sequence. template <typename T> -inline -typename std::enable_if<has_SequenceTraits<T>::value, Output &>::type +inline std::enable_if_t<has_SequenceTraits<T>::value, Output &> operator<<(Output &yout, T &seq) { EmptyContext Ctx; yout.beginDocuments(); @@ -1818,8 +1808,7 @@ operator<<(Output &yout, T &seq) { // Define non-member operator<< so that Output can stream out a block scalar. template <typename T> -inline -typename std::enable_if<has_BlockScalarTraits<T>::value, Output &>::type +inline std::enable_if_t<has_BlockScalarTraits<T>::value, Output &> operator<<(Output &Out, T &Val) { EmptyContext Ctx; Out.beginDocuments(); @@ -1833,8 +1822,7 @@ operator<<(Output &Out, T &Val) { // Define non-member operator<< so that Output can stream out a string map. template <typename T> -inline -typename std::enable_if<has_CustomMappingTraits<T>::value, Output &>::type +inline std::enable_if_t<has_CustomMappingTraits<T>::value, Output &> operator<<(Output &Out, T &Val) { EmptyContext Ctx; Out.beginDocuments(); @@ -1849,7 +1837,7 @@ operator<<(Output &Out, T &Val) { // Define non-member operator<< so that Output can stream out a polymorphic // type. template <typename T> -inline typename std::enable_if<has_PolymorphicTraits<T>::value, Output &>::type +inline std::enable_if_t<has_PolymorphicTraits<T>::value, Output &> operator<<(Output &Out, T &Val) { EmptyContext Ctx; Out.beginDocuments(); @@ -1866,8 +1854,7 @@ operator<<(Output &Out, T &Val) { // Provide better error message about types missing a trait specialization template <typename T> -inline typename std::enable_if<missingTraits<T, EmptyContext>::value, - Output &>::type +inline std::enable_if_t<missingTraits<T, EmptyContext>::value, Output &> operator<<(Output &yout, T &seq) { char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; return yout; @@ -1898,25 +1885,25 @@ template <bool> struct CheckIsBool { static const bool value = true; }; // If T has SequenceElementTraits, then vector<T> and SmallVector<T, N> have // SequenceTraits that do the obvious thing. template <typename T> -struct SequenceTraits<std::vector<T>, - typename std::enable_if<CheckIsBool< - SequenceElementTraits<T>::flow>::value>::type> +struct SequenceTraits< + std::vector<T>, + std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>> : SequenceTraitsImpl<std::vector<T>, SequenceElementTraits<T>::flow> {}; template <typename T, unsigned N> -struct SequenceTraits<SmallVector<T, N>, - typename std::enable_if<CheckIsBool< - SequenceElementTraits<T>::flow>::value>::type> +struct SequenceTraits< + SmallVector<T, N>, + std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>> : SequenceTraitsImpl<SmallVector<T, N>, SequenceElementTraits<T>::flow> {}; template <typename T> -struct SequenceTraits<SmallVectorImpl<T>, - typename std::enable_if<CheckIsBool< - SequenceElementTraits<T>::flow>::value>::type> +struct SequenceTraits< + SmallVectorImpl<T>, + std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>> : SequenceTraitsImpl<SmallVectorImpl<T>, SequenceElementTraits<T>::flow> {}; // Sequences of fundamental types use flow formatting. template <typename T> -struct SequenceElementTraits< - T, typename std::enable_if<std::is_fundamental<T>::value>::type> { +struct SequenceElementTraits<T, + std::enable_if_t<std::is_fundamental<T>::value>> { static const bool flow = true; }; @@ -1936,7 +1923,7 @@ template <typename T> struct StdMapStringCustomMappingTraitsImpl { using map_type = std::map<std::string, T>; static void inputOne(IO &io, StringRef key, map_type &v) { - io.mapRequired(key.str().c_str(), v[key]); + io.mapRequired(key.str().c_str(), v[std::string(key)]); } static void output(IO &io, map_type &v) { diff --git a/llvm/include/llvm/Support/circular_raw_ostream.h b/llvm/include/llvm/Support/circular_raw_ostream.h index a72acd4fe002a..d2f01ea6a7f29 100644 --- a/llvm/include/llvm/Support/circular_raw_ostream.h +++ b/llvm/include/llvm/Support/circular_raw_ostream.h @@ -27,12 +27,12 @@ namespace llvm { /// stream and is responsible for cleanup, memory management /// issues, etc. /// - static const bool TAKE_OWNERSHIP = true; + static constexpr bool TAKE_OWNERSHIP = true; /// REFERENCE_ONLY - Tell this stream it should not manage the /// held stream. /// - static const bool REFERENCE_ONLY = false; + static constexpr bool REFERENCE_ONLY = false; private: /// TheStream - The real stream we output to. We set it to be diff --git a/llvm/include/llvm/Support/raw_ostream.h b/llvm/include/llvm/Support/raw_ostream.h index c8770c3375881..8d289f7c765f9 100644 --- a/llvm/include/llvm/Support/raw_ostream.h +++ b/llvm/include/llvm/Support/raw_ostream.h @@ -64,6 +64,11 @@ private: /// for a \see write_impl() call to handle the data which has been put into /// this buffer. char *OutBufStart, *OutBufEnd, *OutBufCur; + bool ColorEnabled = false; + + /// Optional stream this stream is tied to. If this stream is written to, the + /// tied-to stream will be flushed first. + raw_ostream *TiedStream = nullptr; enum class BufferKind { Unbuffered = 0, @@ -86,16 +91,16 @@ public: RESET, }; - static const Colors BLACK = Colors::BLACK; - static const Colors RED = Colors::RED; - static const Colors GREEN = Colors::GREEN; - static const Colors YELLOW = Colors::YELLOW; - static const Colors BLUE = Colors::BLUE; - static const Colors MAGENTA = Colors::MAGENTA; - static const Colors CYAN = Colors::CYAN; - static const Colors WHITE = Colors::WHITE; - static const Colors SAVEDCOLOR = Colors::SAVEDCOLOR; - static const Colors RESET = Colors::RESET; + static constexpr Colors BLACK = Colors::BLACK; + static constexpr Colors RED = Colors::RED; + static constexpr Colors GREEN = Colors::GREEN; + static constexpr Colors YELLOW = Colors::YELLOW; + static constexpr Colors BLUE = Colors::BLUE; + static constexpr Colors MAGENTA = Colors::MAGENTA; + static constexpr Colors CYAN = Colors::CYAN; + static constexpr Colors WHITE = Colors::WHITE; + static constexpr Colors SAVEDCOLOR = Colors::SAVEDCOLOR; + static constexpr Colors RESET = Colors::RESET; explicit raw_ostream(bool unbuffered = false) : BufferMode(unbuffered ? BufferKind::Unbuffered @@ -270,21 +275,15 @@ public: /// @param Bold bold/brighter text, default false /// @param BG if true change the background, default: change foreground /// @returns itself so it can be used within << invocations - virtual raw_ostream &changeColor(enum Colors Color, - bool Bold = false, - bool BG = false) { - (void)Color; - (void)Bold; - (void)BG; - return *this; - } + virtual raw_ostream &changeColor(enum Colors Color, bool Bold = false, + bool BG = false); /// Resets the colors to terminal defaults. Call this when you are done /// outputting colored text, or before program exit. - virtual raw_ostream &resetColor() { return *this; } + virtual raw_ostream &resetColor(); /// Reverses the foreground and background colors. - virtual raw_ostream &reverseColor() { return *this; } + virtual raw_ostream &reverseColor(); /// This function determines if this stream is connected to a "tty" or /// "console" window. That is, the output would be displayed to the user @@ -292,11 +291,16 @@ public: virtual bool is_displayed() const { return false; } /// This function determines if this stream is displayed and supports colors. + /// The result is unaffected by calls to enable_color(). virtual bool has_colors() const { return is_displayed(); } - // Enable or disable colors. Once disable_colors() is called, - // changeColor() has no effect until enable_colors() is called. - virtual void enable_colors(bool /*enable*/) {} + // Enable or disable colors. Once enable_colors(false) is called, + // changeColor() has no effect until enable_colors(true) is called. + virtual void enable_colors(bool enable) { ColorEnabled = enable; } + + /// Tie this stream to the specified stream. Replaces any existing tied-to + /// stream. Specifying a nullptr unties the stream. + void tie(raw_ostream *TieTo) { TiedStream = TieTo; } //===--------------------------------------------------------------------===// // Subclass Interface @@ -352,15 +356,22 @@ private: /// unused bytes in the buffer. void copy_to_buffer(const char *Ptr, size_t Size); + /// Compute whether colors should be used and do the necessary work such as + /// flushing. The result is affected by calls to enable_color(). + bool prepare_colors(); + + /// Flush the tied-to stream (if present) and then write the required data. + void flush_tied_then_write(const char *Ptr, size_t Size); + virtual void anchor(); }; /// Call the appropriate insertion operator, given an rvalue reference to a /// raw_ostream object and return a stream of the same type as the argument. template <typename OStream, typename T> -typename std::enable_if<!std::is_reference<OStream>::value && - std::is_base_of<raw_ostream, OStream>::value, - OStream &&>::type +std::enable_if_t<!std::is_reference<OStream>::value && + std::is_base_of<raw_ostream, OStream>::value, + OStream &&> operator<<(OStream &&OS, const T &Value) { OS << Value; return std::move(OS); @@ -398,7 +409,6 @@ class raw_fd_ostream : public raw_pwrite_stream { int FD; bool ShouldClose; bool SupportsSeeking = false; - bool ColorEnabled = true; #ifdef _WIN32 /// True if this fd refers to a Windows console device. Mintty and other @@ -464,18 +474,10 @@ public: /// to the offset specified from the beginning of the file. uint64_t seek(uint64_t off); - raw_ostream &changeColor(enum Colors colors, bool bold=false, - bool bg=false) override; - raw_ostream &resetColor() override; - - raw_ostream &reverseColor() override; - bool is_displayed() const override; bool has_colors() const override; - void enable_colors(bool enable) override { ColorEnabled = enable; } - std::error_code error() const { return EC; } /// Return the value of the flag in this raw_fd_ostream indicating whether an @@ -496,13 +498,16 @@ public: void clear_error() { EC = std::error_code(); } }; -/// This returns a reference to a raw_ostream for standard output. Use it like: -/// outs() << "foo" << "bar"; -raw_ostream &outs(); +/// This returns a reference to a raw_fd_ostream for standard output. Use it +/// like: outs() << "foo" << "bar"; +raw_fd_ostream &outs(); -/// This returns a reference to a raw_ostream for standard error. Use it like: -/// errs() << "foo" << "bar"; -raw_ostream &errs(); +/// This returns a reference to a raw_ostream for standard error. +/// Use it like: errs() << "foo" << "bar"; +/// By default, the stream is tied to stdout to ensure stdout is flushed before +/// stderr is written, to ensure the error messages are written in their +/// expected place. +raw_fd_ostream &errs(); /// This returns a reference to a raw_ostream which simply discards output. raw_ostream &nulls(); @@ -524,7 +529,9 @@ class raw_string_ostream : public raw_ostream { uint64_t current_pos() const override { return OS.size(); } public: - explicit raw_string_ostream(std::string &O) : OS(O) {} + explicit raw_string_ostream(std::string &O) : OS(O) { + SetUnbuffered(); + } ~raw_string_ostream() override; /// Flushes the stream contents to the target string and returns the string's @@ -565,7 +572,7 @@ public: void flush() = delete; /// Return a StringRef for the vector contents. - StringRef str() { return StringRef(OS.data(), OS.size()); } + StringRef str() const { return StringRef(OS.data(), OS.size()); } }; /// A raw_ostream that discards all output. diff --git a/llvm/include/llvm/Support/type_traits.h b/llvm/include/llvm/Support/type_traits.h index b7d48e8e1ade5..7b7d5d991f3f5 100644 --- a/llvm/include/llvm/Support/type_traits.h +++ b/llvm/include/llvm/Support/type_traits.h @@ -28,7 +28,7 @@ namespace llvm { /// Also note that enum classes aren't implicitly convertible to integral types, /// the value may therefore need to be explicitly converted before being used. template <typename T> class is_integral_or_enum { - using UnderlyingT = typename std::remove_reference<T>::type; + using UnderlyingT = std::remove_reference_t<T>; public: static const bool value = @@ -45,7 +45,7 @@ struct add_lvalue_reference_if_not_pointer { using type = T &; }; template <typename T> struct add_lvalue_reference_if_not_pointer< - T, typename std::enable_if<std::is_pointer<T>::value>::type> { + T, std::enable_if_t<std::is_pointer<T>::value>> { using type = T; }; @@ -55,9 +55,8 @@ template<typename T, typename Enable = void> struct add_const_past_pointer { using type = const T; }; template <typename T> -struct add_const_past_pointer< - T, typename std::enable_if<std::is_pointer<T>::value>::type> { - using type = const typename std::remove_pointer<T>::type *; +struct add_const_past_pointer<T, std::enable_if_t<std::is_pointer<T>::value>> { + using type = const std::remove_pointer_t<T> *; }; template <typename T, typename Enable = void> @@ -65,8 +64,8 @@ struct const_pointer_or_const_ref { using type = const T &; }; template <typename T> -struct const_pointer_or_const_ref< - T, typename std::enable_if<std::is_pointer<T>::value>::type> { +struct const_pointer_or_const_ref<T, + std::enable_if_t<std::is_pointer<T>::value>> { using type = typename add_const_past_pointer<T>::type; }; |