[llvm] e1a0e82 - [GlobalISel] Copy the implementation of SubtargetFeature and use it for PredicateBitset.

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 23 15:58:45 PDT 2023


Author: Craig Topper
Date: 2023-08-23T15:55:44-07:00
New Revision: e1a0e8258f788a86b248b4cc6bde8a96444a4720

URL: https://github.com/llvm/llvm-project/commit/e1a0e8258f788a86b248b4cc6bde8a96444a4720
DIFF: https://github.com/llvm/llvm-project/commit/e1a0e8258f788a86b248b4cc6bde8a96444a4720.diff

LOG: [GlobalISel] Copy the implementation of SubtargetFeature and use it for PredicateBitset.

PredicateBitset currently uses std::bitset, but std::bitset doesn't
have a constexpr constructor or any constexpr methods until C++23.
Each target that supports GlobalIsel has as an array of PredicateBitset
objects that currently use a global constructor.

SubtargetFeature used by the MC layer for feature bits, has its own
implementation of std::bitset that has constexpr constructor and methods
that provides all the capabilities that PredicateBitset needs.

This patch copies the implementation from SubtargetFeature, makes
it a template class, and puts it in ADT. I'll migrate SubtargetFeature
in a separate patch. Adapting all existing users to it being a template
was distracting from the goal of this patch.

This reduces the binary size of llc built with gcc 8.5.0 on my local
build by ~15k.

Reviewed By: arsenm

Differential Revision: https://reviews.llvm.org/D158576

Added: 
    llvm/include/llvm/ADT/Bitset.h

Modified: 
    llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
    llvm/test/TableGen/GlobalISelEmitter.td
    llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ADT/Bitset.h b/llvm/include/llvm/ADT/Bitset.h
new file mode 100644
index 00000000000000..660c1037b6376f
--- /dev/null
+++ b/llvm/include/llvm/ADT/Bitset.h
@@ -0,0 +1,160 @@
+//=== llvm/ADT/Bitset.h - constexpr std::bitset -----------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a std::bitset like container that can be used in constexprs.
+// That constructor and many of the methods are constexpr. std::bitset doesn't
+// get constexpr methods until C++23. This class also provides a constexpr
+// constructor that accepts an initializer_list of bits to set.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_BITSET_H
+#define LLVM_ADT_BITSET_H
+
+#include <llvm/ADT/STLExtras.h>
+#include <array>
+#include <climits>
+#include <cstdint>
+
+namespace llvm {
+
+/// Container class for 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.
+template <unsigned NumBits>
+class Bitset {
+  typedef uintptr_t BitWord;
+
+  enum { BITWORD_SIZE = (unsigned)sizeof(BitWord) * CHAR_BIT };
+
+  static_assert(BITWORD_SIZE == 64 || BITWORD_SIZE == 32,
+                "Unsupported word size");
+
+  static constexpr unsigned NumWords = (NumBits + BITWORD_SIZE-1) / BITWORD_SIZE;
+  std::array<BitWord, NumWords> Bits{};
+
+protected:
+  constexpr Bitset(const std::array<BitWord, NumWords> &B)
+      : Bits{B} {}
+
+public:
+  constexpr Bitset() = default;
+  constexpr Bitset(std::initializer_list<unsigned> Init) {
+    for (auto I : Init)
+      set(I);
+  }
+
+  Bitset &set() {
+    std::fill(std::begin(Bits), std::end(Bits), -BitWord(0));
+    return *this;
+  }
+
+  constexpr Bitset &set(unsigned I) {
+    // GCC <6.2 crashes if this is written in a single statement.
+    BitWord NewBits = Bits[I / BITWORD_SIZE] | (BitWord(1) << (I % BITWORD_SIZE));
+    Bits[I / BITWORD_SIZE] = NewBits;
+    return *this;
+  }
+
+  constexpr Bitset &reset(unsigned I) {
+    // GCC <6.2 crashes if this is written in a single statement.
+    BitWord NewBits = Bits[I / BITWORD_SIZE] & ~(BitWord(1) << (I % BITWORD_SIZE));
+    Bits[I / BITWORD_SIZE] = NewBits;
+    return *this;
+  }
+
+  constexpr Bitset &flip(unsigned I) {
+    // GCC <6.2 crashes if this is written in a single statement.
+    BitWord NewBits = Bits[I / BITWORD_SIZE] ^ (BitWord(1) << (I % BITWORD_SIZE));
+    Bits[I / BITWORD_SIZE] = NewBits;
+    return *this;
+  }
+
+  constexpr bool operator[](unsigned I) const {
+    BitWord Mask = BitWord(1) << (I % BITWORD_SIZE);
+    return (Bits[I / BITWORD_SIZE] & Mask) != 0;
+  }
+
+  constexpr bool test(unsigned I) const { return (*this)[I]; }
+
+  constexpr size_t size() const { return NumBits; }
+
+  bool any() const {
+    return llvm::any_of(Bits, [](BitWord I) { return I != 0; });
+  }
+  bool none() const { return !any(); }
+  size_t count() const {
+    size_t Count = 0;
+    for (auto B : Bits)
+      Count += llvm::popcount(B);
+    return Count;
+  }
+
+  constexpr Bitset &operator^=(const Bitset &RHS) {
+    for (unsigned I = 0, E = Bits.size(); I != E; ++I) {
+      Bits[I] ^= RHS.Bits[I];
+    }
+    return *this;
+  }
+  constexpr Bitset operator^(const Bitset &RHS) const {
+    Bitset Result = *this;
+    Result ^= RHS;
+    return Result;
+  }
+
+  constexpr Bitset &operator&=(const Bitset &RHS) {
+    for (unsigned I = 0, E = Bits.size(); I != E; ++I) {
+      Bits[I] &= RHS.Bits[I];
+    }
+    return *this;
+  }
+  constexpr Bitset operator&(const Bitset &RHS) const {
+    Bitset Result = *this;
+    Result &= RHS;
+    return Result;
+  }
+
+  constexpr Bitset &operator|=(const Bitset &RHS) {
+    for (unsigned I = 0, E = Bits.size(); I != E; ++I) {
+      Bits[I] |= RHS.Bits[I];
+    }
+    return *this;
+  }
+  constexpr Bitset operator|(const Bitset &RHS) const {
+    Bitset Result = *this;
+    Result |= RHS;
+    return Result;
+  }
+
+  constexpr Bitset operator~() const {
+    Bitset Result = *this;
+    for (auto &B : Result.Bits)
+      B = ~B;
+    return Result;
+  }
+
+  bool operator==(const Bitset &RHS) const {
+    return std::equal(std::begin(Bits), std::end(Bits), std::begin(RHS.Bits));
+  }
+
+  bool operator!=(const Bitset &RHS) const { return !(*this == RHS); }
+
+  bool operator < (const Bitset &Other) const {
+    for (unsigned I = 0, E = size(); I != E; ++I) {
+      bool LHS = test(I), RHS = Other.test(I);
+      if (LHS != RHS)
+        return LHS < RHS;
+    }
+    return false;
+  }
+};
+
+} // end namespace llvm
+
+#endif

diff  --git a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
index b9f6fec9f46427..868f82e88a278d 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
@@ -15,6 +15,7 @@
 #ifndef LLVM_CODEGEN_GLOBALISEL_GIMATCHTABLEEXECUTOR_H
 #define LLVM_CODEGEN_GLOBALISEL_GIMATCHTABLEEXECUTOR_H
 
+#include "llvm/ADT/Bitset.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/CodeGen/GlobalISel/Utils.h"
@@ -47,32 +48,6 @@ class RegisterBankInfo;
 class TargetInstrInfo;
 class TargetRegisterInfo;
 
-/// Container class for CodeGen predicate results.
-/// This is convenient because std::bitset does not have a constructor
-/// with an initializer list of set bits.
-///
-/// Each GIMatchTableExecutor subclass should define a PredicateBitset class
-/// with:
-///   const unsigned MAX_SUBTARGET_PREDICATES = 192;
-///   using PredicateBitset = PredicateBitsetImpl<MAX_SUBTARGET_PREDICATES>;
-/// and updating the constant to suit the target. Tablegen provides a suitable
-/// definition for the predicates in use in <Target>GenGlobalISel.inc when
-/// GET_GLOBALISEL_PREDICATE_BITSET is defined.
-template <std::size_t MaxPredicates>
-class PredicateBitsetImpl : public std::bitset<MaxPredicates> {
-public:
-  // Cannot inherit constructors because it's not supported by VC++..
-  PredicateBitsetImpl() = default;
-
-  PredicateBitsetImpl(const std::bitset<MaxPredicates> &B)
-      : std::bitset<MaxPredicates>(B) {}
-
-  PredicateBitsetImpl(std::initializer_list<unsigned> Init) {
-    for (auto I : Init)
-      std::bitset<MaxPredicates>::set(I);
-  }
-};
-
 enum {
   GICXXPred_Invalid = 0,
   GICXXCustomAction_Invalid = 0,

diff  --git a/llvm/test/TableGen/GlobalISelEmitter.td b/llvm/test/TableGen/GlobalISelEmitter.td
index f00eea3970894a..7cca2d52e4062e 100644
--- a/llvm/test/TableGen/GlobalISelEmitter.td
+++ b/llvm/test/TableGen/GlobalISelEmitter.td
@@ -67,7 +67,7 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
 //===- Test the function boilerplate. -------------------------------------===//
 
 // CHECK: const unsigned MAX_SUBTARGET_PREDICATES = 3;
-// CHECK: using PredicateBitset = llvm::PredicateBitsetImpl<MAX_SUBTARGET_PREDICATES>;
+// CHECK: using PredicateBitset = llvm::Bitset<MAX_SUBTARGET_PREDICATES>;
 
 // CHECK-LABEL: #ifdef GET_GLOBALISEL_TEMPORARIES_DECL
 // CHECK-NEXT:    mutable MatcherState State;
@@ -131,7 +131,7 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
 // CHECK-NEXT:    GIFBS_HasA,
 // CHECK-NEXT:    GIFBS_HasA_HasB_HasC,
 // CHECK-NEXT:  }
-// CHECK-NEXT:  const static PredicateBitset FeatureBitsets[] {
+// CHECK-NEXT:  constexpr static PredicateBitset FeatureBitsets[] {
 // CHECK-NEXT:    {}, // GIFBS_Invalid
 // CHECK-NEXT:    {Feature_HasABit, },
 // CHECK-NEXT:    {Feature_HasABit, Feature_HasBBit, Feature_HasCBit, },

diff  --git a/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp b/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp
index ae3d85c717b1f8..cf9c261cb0be23 100644
--- a/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp
@@ -79,7 +79,7 @@ void GlobalISelMatchTableExecutorEmitter::emitSubtargetFeatureBitsetImpl(
     OS << "  " << getNameForFeatureBitset(FeatureBitset) << ",\n";
   }
   OS << "};\n"
-     << "const static PredicateBitset FeatureBitsets[] {\n"
+     << "constexpr static PredicateBitset FeatureBitsets[] {\n"
      << "  {}, // GIFBS_Invalid\n";
   for (const auto &FeatureBitset : FeatureBitsets) {
     if (FeatureBitset.empty())
@@ -188,7 +188,7 @@ void GlobalISelMatchTableExecutorEmitter::emitPredicateBitset(
      << "const unsigned MAX_SUBTARGET_PREDICATES = " << SubtargetFeatures.size()
      << ";\n"
      << "using PredicateBitset = "
-        "llvm::PredicateBitsetImpl<MAX_SUBTARGET_PREDICATES>;\n"
+        "llvm::Bitset<MAX_SUBTARGET_PREDICATES>;\n"
      << "#endif // ifdef " << IfDefName << "\n\n";
 }
 


        


More information about the llvm-commits mailing list