[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