From: Benjamin Kramer Date: Sat, 24 Aug 2019 15:02:44 +0000 (+0000) Subject: Use a bit of relaxed constexpr to make FeatureBitset costant intializable X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4acc3db23fa7a3c37ffb4b53597518054ab446fa;p=llvm Use a bit of relaxed constexpr to make FeatureBitset costant intializable This requires std::intializer_list to be a literal type, which it is starting with C++14. The downside is that std::bitset is still not constexpr-friendly so this change contains a re-implementation of most of it. Shrinks clang by ~60k. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@369847 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/MC/SubtargetFeature.h b/include/llvm/MC/SubtargetFeature.h index fc9565ceafa..9bd94efcb01 100644 --- a/include/llvm/MC/SubtargetFeature.h +++ b/include/llvm/MC/SubtargetFeature.h @@ -18,6 +18,7 @@ #define LLVM_MC_SUBTARGETFEATURE_H #include "llvm/ADT/StringRef.h" +#include "llvm/Support/MathExtras.h" #include #include #include @@ -33,20 +34,117 @@ const unsigned MAX_SUBTARGET_WORDS = 3; const unsigned MAX_SUBTARGET_FEATURES = MAX_SUBTARGET_WORDS * 64; /// Container class for subtarget features. -/// This is convenient because std::bitset does not have a constructor -/// with an initializer list of set bits. -class FeatureBitset : public std::bitset { +/// This is a constexpr reimplementation of a subset of std::bitset. It would be +/// nice to use std::bitset directly, but it doesn't support constant +/// initialization. +class FeatureBitset { + static_assert((MAX_SUBTARGET_FEATURES % 64) == 0, + "Should be a multiple of 64!"); + // This cannot be a std::array, operator[] is not constexpr until C++17. + uint64_t Bits[MAX_SUBTARGET_WORDS] = {}; + +protected: + constexpr FeatureBitset(const std::array &B) { + for (unsigned I = 0; I != B.size(); ++I) + Bits[I] = B[I]; + } + public: - // Cannot inherit constructors because it's not supported by VC++.. FeatureBitset() = default; - - FeatureBitset(const bitset& B) : bitset(B) {} - - FeatureBitset(std::initializer_list Init) { + constexpr FeatureBitset(std::initializer_list Init) { for (auto I : Init) set(I); } + FeatureBitset &set() { + std::fill(std::begin(Bits), std::end(Bits), -1ULL); + return *this; + } + + constexpr FeatureBitset &set(unsigned I) { + Bits[I / 64] |= uint64_t(1) << (I % 64); + return *this; + } + + constexpr FeatureBitset &reset(unsigned I) { + Bits[I / 64] &= ~(uint64_t(1) << (I % 64)); + return *this; + } + + constexpr FeatureBitset &flip(unsigned I) { + Bits[I / 64] ^= uint64_t(1) << (I % 64); + return *this; + } + + constexpr bool operator[](unsigned I) const { + uint64_t Mask = uint64_t(1) << (I % 64); + return (Bits[I / 64] & Mask) != 0; + } + + constexpr bool test(unsigned I) const { return (*this)[I]; } + + constexpr size_t size() const { return MAX_SUBTARGET_FEATURES; } + + bool any() const { + return llvm::any_of(Bits, [](uint64_t I) { return I != 0; }); + } + bool none() const { return !any(); } + size_t count() const { + size_t Count = 0; + for (auto B : Bits) + Count += countPopulation(B); + return Count; + } + + constexpr FeatureBitset &operator^=(const FeatureBitset &RHS) { + for (unsigned I = 0, E = array_lengthof(Bits); I != E; ++I) { + Bits[I] ^= RHS.Bits[I]; + } + return *this; + } + constexpr FeatureBitset operator^(const FeatureBitset &RHS) const { + FeatureBitset Result = *this; + Result ^= RHS; + return Result; + } + + constexpr FeatureBitset &operator&=(const FeatureBitset &RHS) { + for (unsigned I = 0, E = array_lengthof(Bits); I != E; ++I) { + Bits[I] &= RHS.Bits[I]; + } + return *this; + } + constexpr FeatureBitset operator&(const FeatureBitset &RHS) const { + FeatureBitset Result = *this; + Result &= RHS; + return Result; + } + + constexpr FeatureBitset &operator|=(const FeatureBitset &RHS) { + for (unsigned I = 0, E = array_lengthof(Bits); I != E; ++I) { + Bits[I] |= RHS.Bits[I]; + } + return *this; + } + constexpr FeatureBitset operator|(const FeatureBitset &RHS) const { + FeatureBitset Result = *this; + Result |= RHS; + return Result; + } + + constexpr FeatureBitset operator~() const { + FeatureBitset Result = *this; + for (auto &B : Result.Bits) + B = ~B; + return Result; + } + + bool operator==(const FeatureBitset &RHS) const { + return std::equal(std::begin(Bits), std::end(Bits), std::begin(RHS.Bits)); + } + + bool operator!=(const FeatureBitset &RHS) const { return !(*this == RHS); } + bool operator < (const FeatureBitset &Other) const { for (unsigned I = 0, E = size(); I != E; ++I) { bool LHS = test(I), RHS = Other.test(I); @@ -58,23 +156,12 @@ public: }; /// Class used to store the subtarget bits in the tables created by tablegen. -/// The std::initializer_list constructor of FeatureBitset can't be done at -/// compile time and requires a static constructor to run at startup. -class FeatureBitArray { - std::array Bits; - +class FeatureBitArray : public FeatureBitset { public: constexpr FeatureBitArray(const std::array &B) - : Bits(B) {} - - FeatureBitset getAsBitset() const { - FeatureBitset Result; - - for (unsigned i = 0, e = Bits.size(); i != e; ++i) - Result |= FeatureBitset(Bits[i]) << (64 * i); + : FeatureBitset(B) {} - return Result; - } + const FeatureBitset &getAsBitset() const { return *this; } }; //===----------------------------------------------------------------------===// diff --git a/lib/Target/AArch64/Utils/AArch64BaseInfo.h b/lib/Target/AArch64/Utils/AArch64BaseInfo.h index 0545329a583..71b84246953 100644 --- a/lib/Target/AArch64/Utils/AArch64BaseInfo.h +++ b/lib/Target/AArch64/Utils/AArch64BaseInfo.h @@ -313,9 +313,9 @@ struct SysAlias { uint16_t Encoding; FeatureBitset FeaturesRequired; - SysAlias (const char *N, uint16_t E) : Name(N), Encoding(E) {}; - SysAlias (const char *N, uint16_t E, FeatureBitset F) : - Name(N), Encoding(E), FeaturesRequired(F) {}; + constexpr SysAlias(const char *N, uint16_t E) : Name(N), Encoding(E) {} + constexpr SysAlias(const char *N, uint16_t E, FeatureBitset F) + : Name(N), Encoding(E), FeaturesRequired(F) {} bool haveFeatures(FeatureBitset ActiveFeatures) const { return (FeaturesRequired & ActiveFeatures) == FeaturesRequired; @@ -326,9 +326,10 @@ struct SysAlias { struct SysAliasReg : SysAlias { bool NeedsReg; - SysAliasReg(const char *N, uint16_t E, bool R) : SysAlias(N, E), NeedsReg(R) {}; - SysAliasReg(const char *N, uint16_t E, bool R, FeatureBitset F) : SysAlias(N, E, F), - NeedsReg(R) {}; + constexpr SysAliasReg(const char *N, uint16_t E, bool R) + : SysAlias(N, E), NeedsReg(R) {} + constexpr SysAliasReg(const char *N, uint16_t E, bool R, FeatureBitset F) + : SysAlias(N, E, F), NeedsReg(R) {} }; namespace AArch64AT{ diff --git a/lib/Target/Hexagon/HexagonSubtarget.cpp b/lib/Target/Hexagon/HexagonSubtarget.cpp index 761d7d7aa0b..6c706fea096 100644 --- a/lib/Target/Hexagon/HexagonSubtarget.cpp +++ b/lib/Target/Hexagon/HexagonSubtarget.cpp @@ -119,7 +119,7 @@ HexagonSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) { FeatureBitset Features = getFeatureBits(); if (HexagonDisableDuplex) - setFeatureBits(Features.set(Hexagon::FeatureDuplex, false)); + setFeatureBits(Features.reset(Hexagon::FeatureDuplex)); setFeatureBits(Hexagon_MC::completeHVXFeatures(Features)); return *this; diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp b/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp index 7758c37d612..870ab9e94a6 100644 --- a/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp +++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp @@ -264,14 +264,12 @@ createHexagonObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) { } static void LLVM_ATTRIBUTE_UNUSED clearFeature(MCSubtargetInfo* STI, uint64_t F) { - uint64_t FB = STI->getFeatureBits().to_ullong(); - if (FB & (1ULL << F)) + if (STI->getFeatureBits()[F]) STI->ToggleFeature(F); } static bool LLVM_ATTRIBUTE_UNUSED checkFeature(MCSubtargetInfo* STI, uint64_t F) { - uint64_t FB = STI->getFeatureBits().to_ullong(); - return (FB & (1ULL << F)) != 0; + return STI->getFeatureBits()[F]; } namespace { @@ -398,7 +396,7 @@ MCSubtargetInfo *Hexagon_MC::createHexagonMCSubtargetInfo(const Triple &TT, MCSubtargetInfo *X = createHexagonMCSubtargetInfoImpl(TT, CPUName, ArchFS); if (HexagonDisableDuplex) { llvm::FeatureBitset Features = X->getFeatureBits(); - X->setFeatureBits(Features.set(Hexagon::FeatureDuplex, false)); + X->setFeatureBits(Features.reset(Hexagon::FeatureDuplex)); } X->setFeatureBits(completeHVXFeatures(X->getFeatureBits())); diff --git a/test/TableGen/GlobalISelEmitter.td b/test/TableGen/GlobalISelEmitter.td index 62c1e4673e3..41c825950ca 100644 --- a/test/TableGen/GlobalISelEmitter.td +++ b/test/TableGen/GlobalISelEmitter.td @@ -96,9 +96,9 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; } // CHECK-NEXT: computeAvailableModuleFeatures(const MyTargetSubtarget *Subtarget) const { // CHECK-NEXT: PredicateBitset Features; // CHECK-NEXT: if (Subtarget->hasA()) -// CHECK-NEXT: Features[Feature_HasABit] = 1; +// CHECK-NEXT: Features.set(Feature_HasABit); // CHECK-NEXT: if (Subtarget->hasB()) -// CHECK-NEXT: Features[Feature_HasBBit] = 1; +// CHECK-NEXT: Features.set(Feature_HasBBit); // CHECK-NEXT: return Features; // CHECK-NEXT: } @@ -106,7 +106,7 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; } // CHECK-NEXT: computeAvailableFunctionFeatures(const MyTargetSubtarget *Subtarget, const MachineFunction *MF) const { // CHECK-NEXT: PredicateBitset Features; // CHECK-NEXT: if (Subtarget->hasC()) -// CHECK-NEXT: Features[Feature_HasCBit] = 1; +// CHECK-NEXT: Features.set(Feature_HasCBit); // CHECK-NEXT: return Features; // CHECK-NEXT: } diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index df07f1cd809..508efa8bf5e 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -3366,7 +3366,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " " << getNameForFeatureBitset(FeatureBitset) << ",\n"; } OS << "};\n\n" - << "const static FeatureBitset FeatureBitsets[] {\n" + << "static constexpr FeatureBitset FeatureBitsets[] = {\n" << " {}, // AMFBS_None\n"; for (const auto &FeatureBitset : FeatureBitsets) { if (FeatureBitset.empty()) diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp index da65763905a..a653238c704 100644 --- a/utils/TableGen/CodeEmitterGen.cpp +++ b/utils/TableGen/CodeEmitterGen.cpp @@ -385,8 +385,8 @@ void CodeEmitterGen::run(raw_ostream &o) { o << " " << getNameForFeatureBitset(FeatureBitset) << ",\n"; } o << "};\n\n" - << "const static FeatureBitset FeatureBitsets[] {\n" - << " {}, // CEFBS_None\n"; + << "static constexpr FeatureBitset FeatureBitsets[] = {\n" + << " {}, // CEFBS_None\n"; for (const auto &FeatureBitset : FeatureBitsets) { if (FeatureBitset.empty()) continue; diff --git a/utils/TableGen/SearchableTableEmitter.cpp b/utils/TableGen/SearchableTableEmitter.cpp index e274415f3ed..f08f8aa0195 100644 --- a/utils/TableGen/SearchableTableEmitter.cpp +++ b/utils/TableGen/SearchableTableEmitter.cpp @@ -496,7 +496,7 @@ void SearchableTableEmitter::emitGenericTable(const GenericTable &Table, emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_IMPL").str(), OS); // The primary data table contains all the fields defined for this map. - OS << "const " << Table.CppTypeName << " " << Table.Name << "[] = {\n"; + OS << "constexpr " << Table.CppTypeName << " " << Table.Name << "[] = {\n"; for (unsigned i = 0; i < Table.Entries.size(); ++i) { Record *Entry = Table.Entries[i]; OS << " { "; diff --git a/utils/TableGen/SubtargetFeatureInfo.cpp b/utils/TableGen/SubtargetFeatureInfo.cpp index 33475f2d111..5430f73d5e0 100644 --- a/utils/TableGen/SubtargetFeatureInfo.cpp +++ b/utils/TableGen/SubtargetFeatureInfo.cpp @@ -103,7 +103,7 @@ void SubtargetFeatureInfo::emitComputeAvailableFeatures( assert(!CondStr.empty() && "true predicate should have been filtered"); OS << " if (" << CondStr << ")\n"; - OS << " Features[" << SFI.getEnumBitName() << "] = 1;\n"; + OS << " Features.set(" << SFI.getEnumBitName() << ");\n"; } OS << " return Features;\n"; OS << "}\n\n"; @@ -148,7 +148,7 @@ void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures( } while (true); OS << ")\n"; - OS << " Features[" << SFI.getEnumBitName() << "] = 1;\n"; + OS << " Features.set(" << SFI.getEnumBitName() << ");\n"; } OS << " return Features;\n"; OS << "}\n\n";