[llvm] r369847 - Use a bit of relaxed constexpr to make FeatureBitset costant intializable

Benjamin Kramer via llvm-commits llvm-commits at lists.llvm.org
Sat Aug 24 08:02:44 PDT 2019


Author: d0k
Date: Sat Aug 24 08:02:44 2019
New Revision: 369847

URL: http://llvm.org/viewvc/llvm-project?rev=369847&view=rev
Log:
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.

Modified:
    llvm/trunk/include/llvm/MC/SubtargetFeature.h
    llvm/trunk/lib/Target/AArch64/Utils/AArch64BaseInfo.h
    llvm/trunk/lib/Target/Hexagon/HexagonSubtarget.cpp
    llvm/trunk/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
    llvm/trunk/test/TableGen/GlobalISelEmitter.td
    llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp
    llvm/trunk/utils/TableGen/CodeEmitterGen.cpp
    llvm/trunk/utils/TableGen/SearchableTableEmitter.cpp
    llvm/trunk/utils/TableGen/SubtargetFeatureInfo.cpp

Modified: llvm/trunk/include/llvm/MC/SubtargetFeature.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/SubtargetFeature.h?rev=369847&r1=369846&r2=369847&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/SubtargetFeature.h (original)
+++ llvm/trunk/include/llvm/MC/SubtargetFeature.h Sat Aug 24 08:02:44 2019
@@ -18,6 +18,7 @@
 #define LLVM_MC_SUBTARGETFEATURE_H
 
 #include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MathExtras.h"
 #include <array>
 #include <bitset>
 #include <initializer_list>
@@ -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<MAX_SUBTARGET_FEATURES> {
+/// 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<uint64_t, MAX_SUBTARGET_WORDS> &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<MAX_SUBTARGET_FEATURES>& B) : bitset(B) {}
-
-  FeatureBitset(std::initializer_list<unsigned> Init) {
+  constexpr FeatureBitset(std::initializer_list<unsigned> 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<uint64_t, MAX_SUBTARGET_WORDS> Bits;
-
+class FeatureBitArray : public FeatureBitset {
 public:
   constexpr FeatureBitArray(const std::array<uint64_t, MAX_SUBTARGET_WORDS> &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; }
 };
 
 //===----------------------------------------------------------------------===//

Modified: llvm/trunk/lib/Target/AArch64/Utils/AArch64BaseInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/Utils/AArch64BaseInfo.h?rev=369847&r1=369846&r2=369847&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/Utils/AArch64BaseInfo.h (original)
+++ llvm/trunk/lib/Target/AArch64/Utils/AArch64BaseInfo.h Sat Aug 24 08:02:44 2019
@@ -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{

Modified: llvm/trunk/lib/Target/Hexagon/HexagonSubtarget.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Hexagon/HexagonSubtarget.cpp?rev=369847&r1=369846&r2=369847&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Hexagon/HexagonSubtarget.cpp (original)
+++ llvm/trunk/lib/Target/Hexagon/HexagonSubtarget.cpp Sat Aug 24 08:02:44 2019
@@ -119,7 +119,7 @@ HexagonSubtarget::initializeSubtargetDep
 
   FeatureBitset Features = getFeatureBits();
   if (HexagonDisableDuplex)
-    setFeatureBits(Features.set(Hexagon::FeatureDuplex, false));
+    setFeatureBits(Features.reset(Hexagon::FeatureDuplex));
   setFeatureBits(Hexagon_MC::completeHVXFeatures(Features));
 
   return *this;

Modified: llvm/trunk/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp?rev=369847&r1=369846&r2=369847&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp (original)
+++ llvm/trunk/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp Sat Aug 24 08:02:44 2019
@@ -264,14 +264,12 @@ createHexagonObjectTargetStreamer(MCStre
 }
 
 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::createHexag
   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()));

Modified: llvm/trunk/test/TableGen/GlobalISelEmitter.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/GlobalISelEmitter.td?rev=369847&r1=369846&r2=369847&view=diff
==============================================================================
--- llvm/trunk/test/TableGen/GlobalISelEmitter.td (original)
+++ llvm/trunk/test/TableGen/GlobalISelEmitter.td Sat Aug 24 08:02:44 2019
@@ -96,9 +96,9 @@ def HasC : Predicate<"Subtarget->hasC()"
 // 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()"
 // 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:  }
 

Modified: llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp?rev=369847&r1=369846&r2=369847&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp (original)
+++ llvm/trunk/utils/TableGen/AsmMatcherEmitter.cpp Sat Aug 24 08:02:44 2019
@@ -3366,7 +3366,7 @@ void AsmMatcherEmitter::run(raw_ostream
     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())

Modified: llvm/trunk/utils/TableGen/CodeEmitterGen.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/CodeEmitterGen.cpp?rev=369847&r1=369846&r2=369847&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/CodeEmitterGen.cpp (original)
+++ llvm/trunk/utils/TableGen/CodeEmitterGen.cpp Sat Aug 24 08:02:44 2019
@@ -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;

Modified: llvm/trunk/utils/TableGen/SearchableTableEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/SearchableTableEmitter.cpp?rev=369847&r1=369846&r2=369847&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/SearchableTableEmitter.cpp (original)
+++ llvm/trunk/utils/TableGen/SearchableTableEmitter.cpp Sat Aug 24 08:02:44 2019
@@ -496,7 +496,7 @@ void SearchableTableEmitter::emitGeneric
   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 << "  { ";

Modified: llvm/trunk/utils/TableGen/SubtargetFeatureInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/SubtargetFeatureInfo.cpp?rev=369847&r1=369846&r2=369847&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/SubtargetFeatureInfo.cpp (original)
+++ llvm/trunk/utils/TableGen/SubtargetFeatureInfo.cpp Sat Aug 24 08:02:44 2019
@@ -103,7 +103,7 @@ void SubtargetFeatureInfo::emitComputeAv
     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::emitComputeAs
     } while (true);
 
     OS << ")\n";
-    OS << "    Features[" << SFI.getEnumBitName() << "] = 1;\n";
+    OS << "    Features.set(" << SFI.getEnumBitName() << ");\n";
   }
   OS << "  return Features;\n";
   OS << "}\n\n";




More information about the llvm-commits mailing list