[llvm] [llvm][TableGen] Pool subtarget feature masks (PR #202664)

David Zbarsky via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 9 07:02:08 PDT 2026


https://github.com/dzbarsky created https://github.com/llvm/llvm-project/pull/202664

SubtargetFeatureKV and SubtargetSubTypeKV currently embed one or two
48-byte FeatureBitArray values in every generated row. Many feature,
CPU, and tune CPU rows contain identical masks, so these values account
for 176,800 bytes across the enabled target metadata in a downstream
all-target build.

Compute the transitive feature masks in TableGen, intern them in one
pool per target, and store uint16_t pool indices in the generated rows.
Preserve the existing unnamed-feature behavior when computing closure.
This also replaces recursive runtime expansion with a direct pool
lookup for CPU and feature strings and one table scan for arbitrary
FeatureBitset inputs.

Add generator overflow checking for the uint16_t index and static
assertions for the 32-bit and 64-bit row layouts. Add a TableGen test for
mask sharing, transitive closure, CPU/tune sharing, and unnamed features
in both the subtarget and basic target-feature emitters.

In a downstream LLVM 22 all-target build, linked feature and CPU
metadata shrinks from 176,800 to 90,040 bytes. Stripped binaries shrink
by 65,760 bytes for llvm-mc, 82,272 bytes for llc, 98,720 bytes for
clang, and 100,576 bytes for the multicall LLVM binary.

Paired child CPU measurements over 100 samples show CPU/feature parsing
improving from 71.242 ms to 7.506 ms, an 89.657% reduction with a 95%
confidence interval of [89.240%, 90.057%]. The llc, clang, and multicall
code generation confidence intervals include zero.

The downstream all-target remote build passes. llc output is
byte-identical for all ten enabled targets, llvm-mc objects are
byte-identical for all assembler-capable enabled targets, and Clang's
PowerPC pwr10 CPU/feature expansion is identical.

Work towards #202616

>From 0f83718da576c3173b0ea9cd731a40da0c961a8f Mon Sep 17 00:00:00 2001
From: David Zbarsky <dzbarsky at gmail.com>
Date: Tue, 9 Jun 2026 07:23:59 -0400
Subject: [PATCH] [llvm][TableGen] Pool subtarget feature masks

SubtargetFeatureKV and SubtargetSubTypeKV currently embed one or two
48-byte FeatureBitArray values in every generated row. Many feature,
CPU, and tune CPU rows contain identical masks, so these values account
for 176,800 bytes across the enabled target metadata in a downstream
all-target build.

Compute the transitive feature masks in TableGen, intern them in one
pool per target, and store uint16_t pool indices in the generated rows.
Preserve the existing unnamed-feature behavior when computing closure.
This also replaces recursive runtime expansion with a direct pool
lookup for CPU and feature strings and one table scan for arbitrary
FeatureBitset inputs.

Add generator overflow checking for the uint16_t index and static
assertions for the 32-bit and 64-bit row layouts. Add a TableGen test for
mask sharing, transitive closure, CPU/tune sharing, and unnamed features
in both the subtarget and basic target-feature emitters.

In a downstream LLVM 22 all-target build, linked feature and CPU
metadata shrinks from 176,800 to 90,040 bytes. Stripped binaries shrink
by 65,760 bytes for llvm-mc, 82,272 bytes for llc, 98,720 bytes for
clang, and 100,576 bytes for the multicall LLVM binary.

Paired child CPU measurements over 100 samples show CPU/feature parsing
improving from 71.242 ms to 7.506 ms, an 89.657% reduction with a 95%
confidence interval of [89.240%, 90.057%]. The llc, clang, and multicall
code generation confidence intervals include zero.

The downstream all-target remote build passes. llc output is
byte-identical for all ten enabled targets, llvm-mc objects are
byte-identical for all assembler-capable enabled targets, and Clang's
PowerPC pwr10 CPU/feature expansion is identical.
---
 .../llvm/CodeGen/TargetSubtargetInfo.h        |  1 +
 llvm/include/llvm/MC/MCSubtargetInfo.h        | 17 +++-
 .../llvm/TargetParser/SubtargetFeature.h      |  2 +
 llvm/include/llvm/TargetParser/TargetParser.h | 11 ++-
 llvm/lib/CodeGen/TargetSubtargetInfo.cpp      | 11 +--
 llvm/lib/MC/MCSubtargetInfo.cpp               | 81 ++++++++----------
 .../AMDGPURemoveIncompatibleFunctions.cpp     | 15 +---
 .../Target/RISCV/AsmParser/RISCVAsmParser.cpp |  3 +-
 llvm/lib/TargetParser/PPCTargetParser.cpp     |  4 +-
 llvm/lib/TargetParser/TargetParser.cpp        | 16 +---
 .../TableGen/SubtargetFeatureMaskPooling.td   | 60 ++++++++++++++
 llvm/unittests/CodeGen/MFCommon.inc           |  2 +-
 .../TableGen/Basic/TargetFeaturesEmitter.cpp  | 82 ++++++++++++++++---
 .../TableGen/Basic/TargetFeaturesEmitter.h    | 25 ++++--
 llvm/utils/TableGen/SubtargetEmitter.cpp      | 55 +++++++++----
 15 files changed, 264 insertions(+), 121 deletions(-)
 create mode 100644 llvm/test/TableGen/SubtargetFeatureMaskPooling.td

diff --git a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
index 6f95f0fea6441..598f16f597f59 100644
--- a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
@@ -69,6 +69,7 @@ class LLVM_ABI TargetSubtargetInfo : public MCSubtargetInfo {
                       StringRef FS, ArrayRef<StringRef> PN,
                       ArrayRef<SubtargetFeatureKV> PF,
                       ArrayRef<SubtargetSubTypeKV> PD,
+                      const FeatureBitArray *PFB,
                       const MCWriteProcResEntry *WPR,
                       const MCWriteLatencyEntry *WL,
                       const MCReadAdvanceEntry *RA, const InstrStage *IS,
diff --git a/llvm/include/llvm/MC/MCSubtargetInfo.h b/llvm/include/llvm/MC/MCSubtargetInfo.h
index 708de6d98f40b..003c48f36d48f 100644
--- a/llvm/include/llvm/MC/MCSubtargetInfo.h
+++ b/llvm/include/llvm/MC/MCSubtargetInfo.h
@@ -37,7 +37,7 @@ struct SubtargetFeatureKV {
   const char *Key;                      ///< K-V key string
   const char *Desc;                     ///< Help descriptor
   unsigned Value;                       ///< K-V integer value
-  FeatureBitArray Implies;              ///< K-V bit mask
+  FeatureBitsetIndex Implies; ///< Index into transitive feature mask table
 
   /// Compare routine for std::lower_bound
   bool operator<(StringRef S) const {
@@ -49,14 +49,16 @@ struct SubtargetFeatureKV {
     return StringRef(Key) < StringRef(Other.Key);
   }
 };
+static_assert(sizeof(void *) != 8 || sizeof(SubtargetFeatureKV) == 24);
+static_assert(sizeof(void *) != 4 || sizeof(SubtargetFeatureKV) == 16);
 
 //===----------------------------------------------------------------------===//
 
 /// Used to provide key value pairs for feature and CPU bit flags.
 struct SubtargetSubTypeKV {
   const char *Key;                      ///< K-V key string
-  FeatureBitArray Implies;              ///< K-V bit mask
-  FeatureBitArray TuneImplies;          ///< K-V bit mask
+  FeatureBitsetIndex Implies;     ///< Index into transitive feature mask table
+  FeatureBitsetIndex TuneImplies; ///< Index into transitive feature mask table
   const MCSchedModel *SchedModel;
 
   /// Compare routine for std::lower_bound
@@ -69,6 +71,8 @@ struct SubtargetSubTypeKV {
     return StringRef(Key) < StringRef(Other.Key);
   }
 };
+static_assert(sizeof(void *) != 8 || sizeof(SubtargetSubTypeKV) == 24);
+static_assert(sizeof(void *) != 4 || sizeof(SubtargetSubTypeKV) == 12);
 
 //===----------------------------------------------------------------------===//
 ///
@@ -81,6 +85,7 @@ class LLVM_ABI MCSubtargetInfo {
   ArrayRef<StringRef> ProcNames; // Processor list, including aliases
   ArrayRef<SubtargetFeatureKV> ProcFeatures;  // Processor feature list
   ArrayRef<SubtargetSubTypeKV> ProcDesc;  // Processor descriptions
+  const FeatureBitArray *ProcFeatureMasks;
 
   // Scheduler machine model
   const MCWriteProcResEntry *WriteProcResTable;
@@ -99,7 +104,7 @@ class LLVM_ABI MCSubtargetInfo {
   MCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef TuneCPU,
                   StringRef FS, ArrayRef<StringRef> PN,
                   ArrayRef<SubtargetFeatureKV> PF,
-                  ArrayRef<SubtargetSubTypeKV> PD,
+                  ArrayRef<SubtargetSubTypeKV> PD, const FeatureBitArray *PFB,
                   const MCWriteProcResEntry *WPR, const MCWriteLatencyEntry *WL,
                   const MCReadAdvanceEntry *RA, const InstrStage *IS,
                   const unsigned *OC, const unsigned *FP);
@@ -243,6 +248,10 @@ class LLVM_ABI MCSubtargetInfo {
     return ProcFeatures;
   }
 
+  const FeatureBitset &getFeatureMask(FeatureBitsetIndex Index) const {
+    return ProcFeatureMasks[Index].getAsBitset();
+  }
+
   /// Return the list of processor features currently enabled.
   std::vector<SubtargetFeatureKV> getEnabledProcessorFeatures() const;
 
diff --git a/llvm/include/llvm/TargetParser/SubtargetFeature.h b/llvm/include/llvm/TargetParser/SubtargetFeature.h
index a48b18745352a..04847ff843a1a 100644
--- a/llvm/include/llvm/TargetParser/SubtargetFeature.h
+++ b/llvm/include/llvm/TargetParser/SubtargetFeature.h
@@ -23,6 +23,7 @@
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/MathExtras.h"
 #include <array>
+#include <cstdint>
 #include <initializer_list>
 #include <string>
 #include <vector>
@@ -34,6 +35,7 @@ class Triple;
 
 const unsigned MAX_SUBTARGET_WORDS = 6;
 const unsigned MAX_SUBTARGET_FEATURES = MAX_SUBTARGET_WORDS * 64;
+using FeatureBitsetIndex = uint16_t;
 
 /// Container class for subtarget features.
 /// This is a constexpr reimplementation of a subset of std::bitset. It would be
diff --git a/llvm/include/llvm/TargetParser/TargetParser.h b/llvm/include/llvm/TargetParser/TargetParser.h
index b65ff37dfc958..ed2344ea2b1a3 100644
--- a/llvm/include/llvm/TargetParser/TargetParser.h
+++ b/llvm/include/llvm/TargetParser/TargetParser.h
@@ -26,13 +26,15 @@ namespace llvm {
 struct BasicSubtargetFeatureKV {
   const char *Key;         ///< K-V key string
   unsigned Value;          ///< K-V integer value
-  FeatureBitArray Implies; ///< K-V bit mask
+  FeatureBitsetIndex Implies; ///< Index into transitive feature mask table
 };
+static_assert(sizeof(void *) != 8 || sizeof(BasicSubtargetFeatureKV) == 16);
+static_assert(sizeof(void *) != 4 || sizeof(BasicSubtargetFeatureKV) == 12);
 
 /// Used to provide key value pairs for feature and CPU bit flags.
 struct BasicSubtargetSubTypeKV {
   const char *Key;         ///< K-V key string
-  FeatureBitArray Implies; ///< K-V bit mask
+  FeatureBitsetIndex Implies; ///< Index into transitive feature mask table
 
   /// Compare routine for std::lower_bound
   bool operator<(StringRef S) const { return StringRef(Key) < S; }
@@ -42,11 +44,14 @@ struct BasicSubtargetSubTypeKV {
     return StringRef(Key) < StringRef(Other.Key);
   }
 };
+static_assert(sizeof(void *) != 8 || sizeof(BasicSubtargetSubTypeKV) == 16);
+static_assert(sizeof(void *) != 4 || sizeof(BasicSubtargetSubTypeKV) == 8);
 
 LLVM_ABI std::optional<llvm::StringMap<bool>>
 getCPUDefaultTargetFeatures(StringRef CPU,
                             ArrayRef<BasicSubtargetSubTypeKV> ProcDesc,
-                            ArrayRef<BasicSubtargetFeatureKV> ProcFeatures);
+                            ArrayRef<BasicSubtargetFeatureKV> ProcFeatures,
+                            ArrayRef<FeatureBitArray> FeatureMasks);
 } // namespace llvm
 
 #endif
diff --git a/llvm/lib/CodeGen/TargetSubtargetInfo.cpp b/llvm/lib/CodeGen/TargetSubtargetInfo.cpp
index cd396e6a619a8..0f551809f4511 100644
--- a/llvm/lib/CodeGen/TargetSubtargetInfo.cpp
+++ b/llvm/lib/CodeGen/TargetSubtargetInfo.cpp
@@ -17,11 +17,12 @@ using namespace llvm;
 TargetSubtargetInfo::TargetSubtargetInfo(
     const Triple &TT, StringRef CPU, StringRef TuneCPU, StringRef FS,
     ArrayRef<StringRef> PN, ArrayRef<SubtargetFeatureKV> PF,
-    ArrayRef<SubtargetSubTypeKV> PD, const MCWriteProcResEntry *WPR,
-    const MCWriteLatencyEntry *WL, const MCReadAdvanceEntry *RA,
-    const InstrStage *IS, const unsigned *OC, const unsigned *FP)
-    : MCSubtargetInfo(TT, CPU, TuneCPU, FS, PN, PF, PD, WPR, WL, RA, IS, OC,
-                      FP) {}
+    ArrayRef<SubtargetSubTypeKV> PD, const FeatureBitArray *PFB,
+    const MCWriteProcResEntry *WPR, const MCWriteLatencyEntry *WL,
+    const MCReadAdvanceEntry *RA, const InstrStage *IS, const unsigned *OC,
+    const unsigned *FP)
+    : MCSubtargetInfo(TT, CPU, TuneCPU, FS, PN, PF, PD, PFB, WPR, WL, RA, IS,
+                      OC, FP) {}
 
 TargetSubtargetInfo::~TargetSubtargetInfo() = default;
 
diff --git a/llvm/lib/MC/MCSubtargetInfo.cpp b/llvm/lib/MC/MCSubtargetInfo.cpp
index ed263a2b4817f..02cfb7c5378e0 100644
--- a/llvm/lib/MC/MCSubtargetInfo.cpp
+++ b/llvm/lib/MC/MCSubtargetInfo.cpp
@@ -35,38 +35,27 @@ static const T *Find(StringRef S, ArrayRef<T> A) {
 
 /// For each feature that is (transitively) implied by this feature, set it.
 static void SetImpliedBits(FeatureBitset &Bits, FeatureBitset Implies,
-                           ArrayRef<SubtargetFeatureKV> FeatureTable) {
-  // Transitively set all features implied. We don't assume that the features in
-  // Bits have already had their implied features set.
-  FeatureBitset NewBits = Implies;
-  while (Implies.any()) {
-    FeatureBitset Implied;
-    for (const SubtargetFeatureKV &FE : FeatureTable) {
-      if (Implies.test(FE.Value))
-        Implied |= FE.Implies.getAsBitset();
-    }
-
-    // Only continue for bits that haven't been set yet.
-    Implies = Implied & ~NewBits;
-    NewBits |= Implies;
-  }
-  Bits |= NewBits;
+                           ArrayRef<SubtargetFeatureKV> FeatureTable,
+                           const FeatureBitArray *FeatureMasks) {
+  Bits |= Implies;
+  for (const SubtargetFeatureKV &FE : FeatureTable)
+    if (Implies.test(FE.Value))
+      Bits |= FeatureMasks[FE.Implies].getAsBitset();
 }
 
 /// For each feature that (transitively) implies this feature, clear it.
-static
-void ClearImpliedBits(FeatureBitset &Bits, unsigned Value,
-                      ArrayRef<SubtargetFeatureKV> FeatureTable) {
+static void ClearImpliedBits(FeatureBitset &Bits, unsigned Value,
+                             ArrayRef<SubtargetFeatureKV> FeatureTable,
+                             const FeatureBitArray *FeatureMasks) {
   for (const SubtargetFeatureKV &FE : FeatureTable) {
-    if (FE.Implies.getAsBitset().test(Value)) {
+    if (FeatureMasks[FE.Implies].getAsBitset().test(Value))
       Bits.reset(FE.Value);
-      ClearImpliedBits(Bits, FE.Value, FeatureTable);
-    }
   }
 }
 
 static void ApplyFeatureFlag(FeatureBitset &Bits, StringRef Feature,
-                             ArrayRef<SubtargetFeatureKV> FeatureTable) {
+                             ArrayRef<SubtargetFeatureKV> FeatureTable,
+                             const FeatureBitArray *FeatureMasks) {
   assert(SubtargetFeatures::hasFlag(Feature) &&
          "Feature flags should start with '+' or '-'");
 
@@ -80,12 +69,12 @@ static void ApplyFeatureFlag(FeatureBitset &Bits, StringRef Feature,
       Bits.set(FeatureEntry->Value);
 
       // For each feature that this implies, set it.
-      SetImpliedBits(Bits, FeatureEntry->Implies.getAsBitset(), FeatureTable);
+      Bits |= FeatureMasks[FeatureEntry->Implies].getAsBitset();
     } else {
       Bits.reset(FeatureEntry->Value);
 
       // For each feature that implies this, clear it.
-      ClearImpliedBits(Bits, FeatureEntry->Value, FeatureTable);
+      ClearImpliedBits(Bits, FeatureEntry->Value, FeatureTable, FeatureMasks);
     }
   } else {
     errs() << "'" << Feature << "' is not a recognized feature for this target"
@@ -179,7 +168,8 @@ static FeatureBitset getFeatures(MCSubtargetInfo &STI, StringRef CPU,
                                  StringRef TuneCPU, StringRef FS,
                                  ArrayRef<StringRef> ProcNames,
                                  ArrayRef<SubtargetSubTypeKV> ProcDesc,
-                                 ArrayRef<SubtargetFeatureKV> ProcFeatures) {
+                                 ArrayRef<SubtargetFeatureKV> ProcFeatures,
+                                 const FeatureBitArray *FeatureMasks) {
   SubtargetFeatures Features(FS);
 
   if (ProcDesc.empty() || ProcFeatures.empty())
@@ -201,7 +191,7 @@ static FeatureBitset getFeatures(MCSubtargetInfo &STI, StringRef CPU,
     // If there is a match
     if (CPUEntry) {
       // Set the features implied by this CPU feature, if any.
-      SetImpliedBits(Bits, CPUEntry->Implies.getAsBitset(), ProcFeatures);
+      Bits |= FeatureMasks[CPUEntry->Implies].getAsBitset();
     } else {
       errs() << "'" << CPU << "' is not a recognized processor for this target"
              << " (ignoring processor)\n";
@@ -214,7 +204,7 @@ static FeatureBitset getFeatures(MCSubtargetInfo &STI, StringRef CPU,
     // If there is a match
     if (CPUEntry) {
       // Set the features implied by this CPU feature, if any.
-      SetImpliedBits(Bits, CPUEntry->TuneImplies.getAsBitset(), ProcFeatures);
+      Bits |= FeatureMasks[CPUEntry->TuneImplies].getAsBitset();
     } else if (TuneCPU != CPU) {
       errs() << "'" << TuneCPU << "' is not a recognized processor for this "
              << "target (ignoring processor)\n";
@@ -229,7 +219,7 @@ static FeatureBitset getFeatures(MCSubtargetInfo &STI, StringRef CPU,
     else if (Feature == "+cpuhelp")
       cpuHelp(ProcNames);
     else
-      ApplyFeatureFlag(Bits, Feature, ProcFeatures);
+      ApplyFeatureFlag(Bits, Feature, ProcFeatures, FeatureMasks);
   }
 
   return Bits;
@@ -237,8 +227,8 @@ static FeatureBitset getFeatures(MCSubtargetInfo &STI, StringRef CPU,
 
 void MCSubtargetInfo::InitMCProcessorInfo(StringRef CPU, StringRef TuneCPU,
                                           StringRef FS) {
-  FeatureBits =
-      getFeatures(*this, CPU, TuneCPU, FS, ProcNames, ProcDesc, ProcFeatures);
+  FeatureBits = getFeatures(*this, CPU, TuneCPU, FS, ProcNames, ProcDesc,
+                            ProcFeatures, ProcFeatureMasks);
   FeatureString = std::string(FS);
 
   if (!TuneCPU.empty())
@@ -249,21 +239,22 @@ void MCSubtargetInfo::InitMCProcessorInfo(StringRef CPU, StringRef TuneCPU,
 
 void MCSubtargetInfo::setDefaultFeatures(StringRef CPU, StringRef TuneCPU,
                                          StringRef FS) {
-  FeatureBits =
-      getFeatures(*this, CPU, TuneCPU, FS, ProcNames, ProcDesc, ProcFeatures);
+  FeatureBits = getFeatures(*this, CPU, TuneCPU, FS, ProcNames, ProcDesc,
+                            ProcFeatures, ProcFeatureMasks);
   FeatureString = std::string(FS);
 }
 
 MCSubtargetInfo::MCSubtargetInfo(
     const Triple &TT, StringRef C, StringRef TC, StringRef FS,
     ArrayRef<StringRef> PN, ArrayRef<SubtargetFeatureKV> PF,
-    ArrayRef<SubtargetSubTypeKV> PD, const MCWriteProcResEntry *WPR,
-    const MCWriteLatencyEntry *WL, const MCReadAdvanceEntry *RA,
-    const InstrStage *IS, const unsigned *OC, const unsigned *FP)
+    ArrayRef<SubtargetSubTypeKV> PD, const FeatureBitArray *PFB,
+    const MCWriteProcResEntry *WPR, const MCWriteLatencyEntry *WL,
+    const MCReadAdvanceEntry *RA, const InstrStage *IS, const unsigned *OC,
+    const unsigned *FP)
     : TargetTriple(TT), CPU(std::string(C)), TuneCPU(std::string(TC)),
-      ProcNames(PN), ProcFeatures(PF), ProcDesc(PD), WriteProcResTable(WPR),
-      WriteLatencyTable(WL), ReadAdvanceTable(RA), Stages(IS),
-      OperandCycles(OC), ForwardingPaths(FP) {
+      ProcNames(PN), ProcFeatures(PF), ProcDesc(PD), ProcFeatureMasks(PFB),
+      WriteProcResTable(WPR), WriteLatencyTable(WL), ReadAdvanceTable(RA),
+      Stages(IS), OperandCycles(OC), ForwardingPaths(FP) {
   InitMCProcessorInfo(CPU, TuneCPU, FS);
 }
 
@@ -279,7 +270,7 @@ const FeatureBitset &MCSubtargetInfo::ToggleFeature(const FeatureBitset &FB) {
 
 const FeatureBitset &
 MCSubtargetInfo::SetFeatureBitsTransitively(const FeatureBitset &FB) {
-  SetImpliedBits(FeatureBits, FB, ProcFeatures);
+  SetImpliedBits(FeatureBits, FB, ProcFeatures, ProcFeatureMasks);
   return FeatureBits;
 }
 
@@ -288,7 +279,7 @@ MCSubtargetInfo::ClearFeatureBitsTransitively(const FeatureBitset &FB) {
   for (unsigned I = 0, E = FB.size(); I < E; I++) {
     if (FB[I]) {
       FeatureBits.reset(I);
-      ClearImpliedBits(FeatureBits, I, ProcFeatures);
+      ClearImpliedBits(FeatureBits, I, ProcFeatures, ProcFeatureMasks);
     }
   }
   return FeatureBits;
@@ -303,13 +294,13 @@ const FeatureBitset &MCSubtargetInfo::ToggleFeature(StringRef Feature) {
     if (FeatureBits.test(FeatureEntry->Value)) {
       FeatureBits.reset(FeatureEntry->Value);
       // For each feature that implies this, clear it.
-      ClearImpliedBits(FeatureBits, FeatureEntry->Value, ProcFeatures);
+      ClearImpliedBits(FeatureBits, FeatureEntry->Value, ProcFeatures,
+                       ProcFeatureMasks);
     } else {
       FeatureBits.set(FeatureEntry->Value);
 
       // For each feature that this implies, set it.
-      SetImpliedBits(FeatureBits, FeatureEntry->Implies.getAsBitset(),
-                     ProcFeatures);
+      FeatureBits |= ProcFeatureMasks[FeatureEntry->Implies].getAsBitset();
     }
   } else {
     errs() << "'" << Feature << "' is not a recognized feature for this target"
@@ -320,7 +311,7 @@ const FeatureBitset &MCSubtargetInfo::ToggleFeature(StringRef Feature) {
 }
 
 const FeatureBitset &MCSubtargetInfo::ApplyFeatureFlag(StringRef FS) {
-  ::ApplyFeatureFlag(FeatureBits, FS, ProcFeatures);
+  ::ApplyFeatureFlag(FeatureBits, FS, ProcFeatures, ProcFeatureMasks);
   return FeatureBits;
 }
 
diff --git a/llvm/lib/Target/AMDGPU/AMDGPURemoveIncompatibleFunctions.cpp b/llvm/lib/Target/AMDGPU/AMDGPURemoveIncompatibleFunctions.cpp
index 246d2a9738d88..09e32a38c8a74 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPURemoveIncompatibleFunctions.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPURemoveIncompatibleFunctions.cpp
@@ -123,15 +123,6 @@ constexpr unsigned FeaturesToCheck[] = {AMDGPU::FeatureGFX11Insts,
                                         AMDGPU::FeatureSMemTimeInst,
                                         AMDGPU::FeatureGWS};
 
-FeatureBitset expandImpliedFeatures(const FeatureBitset &Features) {
-  FeatureBitset Result = Features;
-  for (const SubtargetFeatureKV &FE : AMDGPUFeatureKV) {
-    if (Features.test(FE.Value) && FE.Implies.any())
-      Result |= expandImpliedFeatures(FE.Implies.getAsBitset());
-  }
-  return Result;
-}
-
 void reportFunctionRemoved(Function &F, unsigned Feature) {
   OptimizationRemarkEmitter ORE(&F);
   ORE.emit([&]() {
@@ -175,13 +166,11 @@ bool AMDGPURemoveIncompatibleFunctions::checkFunction(Function &F) {
   if (!GPUInfo)
     return false;
 
-  // Get all the features implied by the current GPU, and recursively expand
-  // the features that imply other features.
+  // CPU feature masks include all transitively implied features.
   //
   // e.g. GFX90A implies FeatureGFX9, and FeatureGFX9 implies a whole set of
   // other features.
-  const FeatureBitset GPUFeatureBits =
-      expandImpliedFeatures(GPUInfo->Implies.getAsBitset());
+  const FeatureBitset &GPUFeatureBits = ST->getFeatureMask(GPUInfo->Implies);
 
   // Now that the have a FeatureBitset containing all possible features for
   // the chosen GPU, check our list of "suspicious" features.
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 9362a600b12b3..bb9decd07668a 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -56,6 +56,7 @@ static cl::opt<bool> AddBuildAttributes("riscv-add-build-attributes",
 
 namespace llvm {
 extern const SubtargetFeatureKV RISCVFeatureKV[RISCV::NumSubtargetFeatures];
+extern const FeatureBitArray RISCVFeatureBitsets[];
 } // namespace llvm
 
 namespace {
@@ -3269,7 +3270,7 @@ bool RISCVAsmParser::parseDirectiveOption() {
         // TODO: Make use of RISCVISAInfo to handle this
         for (auto &Feature : RISCVFeatureKV) {
           if (getSTI().hasFeature(Feature.Value) &&
-              Feature.Implies.test(Ext->Value))
+              RISCVFeatureBitsets[Feature.Implies].test(Ext->Value))
             return Error(Loc, Twine("can't disable ") + Ext->Key +
                                   " extension; " + Feature.Key +
                                   " extension requires " + Ext->Key +
diff --git a/llvm/lib/TargetParser/PPCTargetParser.cpp b/llvm/lib/TargetParser/PPCTargetParser.cpp
index 106d07107ac8c..0e64b4cb324f1 100644
--- a/llvm/lib/TargetParser/PPCTargetParser.cpp
+++ b/llvm/lib/TargetParser/PPCTargetParser.cpp
@@ -123,8 +123,8 @@ StringRef getNormalizedPPCTuneCPU(const Triple &T, StringRef CPUName) {
 
 std::optional<StringMap<bool>> getPPCDefaultTargetFeatures(const Triple &T,
                                                            StringRef CPU) {
-  std::optional<StringMap<bool>> FeaturesOpt =
-      getCPUDefaultTargetFeatures(CPU, BasicPPCSubTypeKV, BasicPPCFeatureKV);
+  std::optional<StringMap<bool>> FeaturesOpt = getCPUDefaultTargetFeatures(
+      CPU, BasicPPCSubTypeKV, BasicPPCFeatureKV, BasicPPCFeatureBitsets);
 
   if (!FeaturesOpt.has_value())
     return std::nullopt;
diff --git a/llvm/lib/TargetParser/TargetParser.cpp b/llvm/lib/TargetParser/TargetParser.cpp
index 52c5e6d800194..4a9a39b5068bb 100644
--- a/llvm/lib/TargetParser/TargetParser.cpp
+++ b/llvm/lib/TargetParser/TargetParser.cpp
@@ -28,20 +28,10 @@ find(StringRef S, ArrayRef<BasicSubtargetSubTypeKV> A) {
   return F;
 }
 
-/// For each feature that is (transitively) implied by this feature, set it.
-static void setImpliedBits(FeatureBitset &Bits, const FeatureBitset &Implies,
-                           ArrayRef<BasicSubtargetFeatureKV> FeatureTable) {
-  // OR the Implies bits in outside the loop. This allows the Implies for CPUs
-  // which might imply features not in FeatureTable to use this.
-  Bits |= Implies;
-  for (const auto &FE : FeatureTable)
-    if (Implies.test(FE.Value))
-      setImpliedBits(Bits, FE.Implies.getAsBitset(), FeatureTable);
-}
-
 std::optional<llvm::StringMap<bool>> llvm::getCPUDefaultTargetFeatures(
     StringRef CPU, ArrayRef<BasicSubtargetSubTypeKV> ProcDesc,
-    ArrayRef<BasicSubtargetFeatureKV> ProcFeatures) {
+    ArrayRef<BasicSubtargetFeatureKV> ProcFeatures,
+    ArrayRef<FeatureBitArray> FeatureMasks) {
   if (CPU.empty())
     return std::nullopt;
 
@@ -52,7 +42,7 @@ std::optional<llvm::StringMap<bool>> llvm::getCPUDefaultTargetFeatures(
   // Set the features implied by this CPU feature if there is a match.
   FeatureBitset Bits;
   llvm::StringMap<bool> DefaultFeatures;
-  setImpliedBits(Bits, CPUEntry->Implies.getAsBitset(), ProcFeatures);
+  Bits |= FeatureMasks[CPUEntry->Implies].getAsBitset();
 
   [[maybe_unused]] unsigned BitSize = Bits.size();
   for (const BasicSubtargetFeatureKV &FE : ProcFeatures) {
diff --git a/llvm/test/TableGen/SubtargetFeatureMaskPooling.td b/llvm/test/TableGen/SubtargetFeatureMaskPooling.td
new file mode 100644
index 0000000000000..ee2d4d9632490
--- /dev/null
+++ b/llvm/test/TableGen/SubtargetFeatureMaskPooling.td
@@ -0,0 +1,60 @@
+// RUN: llvm-tblgen -gen-subtarget -I %p/../../include %s | FileCheck %s --check-prefix=SUBTARGET
+// RUN: llvm-tblgen -gen-target-features -I %p/../../include %s | FileCheck %s --check-prefix=BASIC
+
+include "llvm/Target/Target.td"
+
+def MyTarget : Target;
+
+def FeatureA : SubtargetFeature<"a", "", "", "">;
+def FeatureB : SubtargetFeature<"b", "", "", "", [FeatureA]>;
+def FeatureC : SubtargetFeature<"c", "", "", "", [FeatureA]>;
+def FeatureD : SubtargetFeature<"d", "", "", "", [FeatureB]>;
+def HiddenFeature : SubtargetFeature<"", "", "", "", [FeatureD]>;
+
+def P0 : ProcessorModel<"cpu0", NoSchedModel,
+                        /*Features=*/[FeatureA],
+                        /*TuneFeatures=*/[FeatureB]>;
+def P1 : ProcessorModel<"cpu1", NoSchedModel,
+                        /*Features=*/[FeatureA, FeatureB]>;
+def P2 : ProcessorModel<"cpu2", NoSchedModel,
+                        /*Features=*/[HiddenFeature]>;
+
+// SUBTARGET: extern const llvm::SubtargetFeatureKV MyTargetFeatureKV[] = {
+// SUBTARGET-NEXT: { "a", "", MyTarget::FeatureA, 0 },
+// SUBTARGET-NEXT: { "b", "", MyTarget::FeatureB, 1 },
+// SUBTARGET-NEXT: { "c", "", MyTarget::FeatureC, 1 },
+// SUBTARGET-NEXT: { "d", "", MyTarget::FeatureD, 2 },
+// SUBTARGET-NEXT: };
+
+// SUBTARGET: extern const llvm::SubtargetSubTypeKV MyTargetSubTypeKV[] = {
+// SUBTARGET-NEXT: { "cpu0", 1, 2, &NoSchedModel },
+// SUBTARGET-NEXT: { "cpu1", 2, 0, &NoSchedModel },
+// SUBTARGET-NEXT: { "cpu2", 3, 0, &NoSchedModel },
+// SUBTARGET-NEXT: };
+
+// SUBTARGET: extern const llvm::FeatureBitArray MyTargetFeatureBitsets[] = {
+// SUBTARGET-NEXT: { { { 0x0ULL, 0x0ULL, 0x0ULL, 0x0ULL, 0x0ULL, 0x0ULL, } } },
+// SUBTARGET-NEXT: { { { 0x1ULL, 0x0ULL, 0x0ULL, 0x0ULL, 0x0ULL, 0x0ULL, } } },
+// SUBTARGET-NEXT: { { { 0x3ULL, 0x0ULL, 0x0ULL, 0x0ULL, 0x0ULL, 0x0ULL, } } },
+// SUBTARGET-NEXT: { { { 0x10ULL, 0x0ULL, 0x0ULL, 0x0ULL, 0x0ULL, 0x0ULL, } } },
+// SUBTARGET-NEXT: };
+
+// BASIC: extern const llvm::BasicSubtargetFeatureKV BasicMyTargetFeatureKV[] = {
+// BASIC-NEXT: { "a", MyTarget::FeatureA, 0 },
+// BASIC-NEXT: { "b", MyTarget::FeatureB, 1 },
+// BASIC-NEXT: { "c", MyTarget::FeatureC, 1 },
+// BASIC-NEXT: { "d", MyTarget::FeatureD, 2 },
+// BASIC-NEXT: };
+
+// BASIC: extern const llvm::BasicSubtargetSubTypeKV BasicMyTargetSubTypeKV[] = {
+// BASIC-NEXT: { "cpu0", 1 },
+// BASIC-NEXT: { "cpu1", 2 },
+// BASIC-NEXT: { "cpu2", 3 },
+// BASIC-NEXT: };
+
+// BASIC: extern const llvm::FeatureBitArray BasicMyTargetFeatureBitsets[] = {
+// BASIC-NEXT: { { { 0x0ULL, 0x0ULL, 0x0ULL, 0x0ULL, 0x0ULL, 0x0ULL, } } },
+// BASIC-NEXT: { { { 0x1ULL, 0x0ULL, 0x0ULL, 0x0ULL, 0x0ULL, 0x0ULL, } } },
+// BASIC-NEXT: { { { 0x3ULL, 0x0ULL, 0x0ULL, 0x0ULL, 0x0ULL, 0x0ULL, } } },
+// BASIC-NEXT: { { { 0x10ULL, 0x0ULL, 0x0ULL, 0x0ULL, 0x0ULL, 0x0ULL, } } },
+// BASIC-NEXT: };
diff --git a/llvm/unittests/CodeGen/MFCommon.inc b/llvm/unittests/CodeGen/MFCommon.inc
index 6c47461629070..f9caa9b9e7fec 100644
--- a/llvm/unittests/CodeGen/MFCommon.inc
+++ b/llvm/unittests/CodeGen/MFCommon.inc
@@ -129,7 +129,7 @@ public:
     STI = std::make_unique<MCSubtargetInfo>(
         Triple(""), "", "", "", ArrayRef<StringRef>{},
         ArrayRef<SubtargetFeatureKV>{}, ArrayRef<SubtargetSubTypeKV>{}, nullptr,
-        nullptr, nullptr, nullptr, nullptr, nullptr);
+        nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
   }
 
   ~BogusTargetMachine() override = default;
diff --git a/llvm/utils/TableGen/Basic/TargetFeaturesEmitter.cpp b/llvm/utils/TableGen/Basic/TargetFeaturesEmitter.cpp
index e2b524155a72c..5b7d8cbf22e41 100644
--- a/llvm/utils/TableGen/Basic/TargetFeaturesEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/TargetFeaturesEmitter.cpp
@@ -12,10 +12,13 @@
 //===----------------------------------------------------------------------===//
 
 #include "TargetFeaturesEmitter.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/TableGen/CodeGenHelpers.h"
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/TableGenBackend.h"
 #include "llvm/TargetParser/SubtargetFeature.h"
+#include <limits>
 
 using namespace llvm;
 
@@ -64,15 +67,49 @@ FeatureMapTy TargetFeaturesEmitter::enumeration(raw_ostream &OS) {
   return FeatureMap;
 }
 
-void TargetFeaturesEmitter::printFeatureMask(
-    raw_ostream &OS, ArrayRef<const Record *> FeatureList,
-    const FeatureMapTy &FeatureMap) {
-  std::array<uint64_t, MAX_SUBTARGET_WORDS> Mask = {};
-  for (const Record *Feature : FeatureList) {
-    unsigned Bit = FeatureMap.lookup(Feature);
+TargetFeaturesEmitter::FeatureMask
+TargetFeaturesEmitter::getFeatureMask(ArrayRef<const Record *> FeatureList,
+                                      const FeatureMapTy &FeatureMap) {
+  // Match the transitive closure computed by MCSubtargetInfo. Unnamed features
+  // are not present in its runtime feature table, so their implications are not
+  // expanded.
+  FeatureMask Mask = {};
+  SmallVector<const Record *, 16> Worklist(FeatureList);
+  SmallPtrSet<const Record *, 16> Visited;
+  while (!Worklist.empty()) {
+    const Record *Feature = Worklist.pop_back_val();
+    if (!Visited.insert(Feature).second)
+      continue;
+
+    auto I = FeatureMap.find(Feature);
+    assert(I != FeatureMap.end() && "SubtargetFeature is not enumerated");
+    unsigned Bit = I->second;
     Mask[Bit / 64] |= 1ULL << (Bit % 64);
+    if (Feature->getValueAsString("Name").empty())
+      continue;
+    for (const Record *Implied : Feature->getValueAsListOfDefs("Implies"))
+      Worklist.push_back(Implied);
   }
+  return Mask;
+}
+
+unsigned
+TargetFeaturesEmitter::getFeatureMaskIndex(ArrayRef<const Record *> FeatureList,
+                                           const FeatureMapTy &FeatureMap,
+                                           FeatureMaskTable &FeatureMasks) {
+  FeatureMask Mask = getFeatureMask(FeatureList, FeatureMap);
+  auto I = llvm::find(FeatureMasks, Mask);
+  if (I != FeatureMasks.end())
+    return I - FeatureMasks.begin();
+
+  if (FeatureMasks.size() > std::numeric_limits<FeatureBitsetIndex>::max())
+    PrintFatalError("Too many unique subtarget feature masks");
+  FeatureMasks.push_back(Mask);
+  return FeatureMasks.size() - 1;
+}
 
+void TargetFeaturesEmitter::printFeatureMask(raw_ostream &OS,
+                                             const FeatureMask &Mask) {
   OS << "{ { { ";
   for (unsigned I = 0; I != Mask.size(); ++I) {
     OS << "0x";
@@ -82,8 +119,23 @@ void TargetFeaturesEmitter::printFeatureMask(
   OS << "} } }";
 }
 
+void TargetFeaturesEmitter::printFeatureMaskTable(
+    raw_ostream &OS, StringRef TableName, ArrayRef<FeatureMask> FeatureMasks) {
+  if (FeatureMasks.empty())
+    return;
+
+  OS << "extern const llvm::FeatureBitArray " << TableName << "[] = {\n";
+  for (const FeatureMask &Mask : FeatureMasks) {
+    OS << "  ";
+    printFeatureMask(OS, Mask);
+    OS << ",\n";
+  }
+  OS << "};\n";
+}
+
 void TargetFeaturesEmitter::printFeatureKeyValues(
-    raw_ostream &OS, const FeatureMapTy &FeatureMap) {
+    raw_ostream &OS, const FeatureMapTy &FeatureMap,
+    FeatureMaskTable &FeatureMasks) {
   std::vector<const Record *> FeatureList =
       Records.getAllDerivedDefinitions("SubtargetFeature");
 
@@ -111,7 +163,7 @@ void TargetFeaturesEmitter::printFeatureKeyValues(
 
     ConstRecVec ImpliesList = Feature->getValueAsListOfDefs("Implies");
 
-    printFeatureMask(OS, ImpliesList, FeatureMap);
+    OS << getFeatureMaskIndex(ImpliesList, FeatureMap, FeatureMasks);
 
     OS << " },\n";
   }
@@ -121,7 +173,8 @@ void TargetFeaturesEmitter::printFeatureKeyValues(
 }
 
 void TargetFeaturesEmitter::printCPUKeyValues(raw_ostream &OS,
-                                              const FeatureMapTy &FeatureMap) {
+                                              const FeatureMapTy &FeatureMap,
+                                              FeatureMaskTable &FeatureMasks) {
   // Gather and sort processor information
   std::vector<const Record *> ProcessorList =
       Records.getAllDerivedDefinitions("Processor");
@@ -138,7 +191,7 @@ void TargetFeaturesEmitter::printCPUKeyValues(raw_ostream &OS,
 
     OS << " { " << "\"" << Name << "\", ";
 
-    printFeatureMask(OS, FeatureList, FeatureMap);
+    OS << getFeatureMaskIndex(FeatureList, FeatureMap, FeatureMasks);
     OS << " },\n";
   }
 
@@ -159,11 +212,16 @@ void TargetFeaturesEmitter::run(raw_ostream &OS) {
   {
     IfDefEmitter IfDef(OS, "GET_SUBTARGETFEATURES_KV");
     NamespaceEmitter NS(OS, "llvm");
+    FeatureMaskTable FeatureMasks;
+
+    printFeatureKeyValues(OS, FeatureMap, FeatureMasks);
+    OS << "\n";
 
-    printFeatureKeyValues(OS, FeatureMap);
+    printCPUKeyValues(OS, FeatureMap, FeatureMasks);
     OS << "\n";
 
-    printCPUKeyValues(OS, FeatureMap);
+    printFeatureMaskTable(OS, "Basic" + Target + "FeatureBitsets",
+                          FeatureMasks);
     OS << "\n";
   }
 }
diff --git a/llvm/utils/TableGen/Basic/TargetFeaturesEmitter.h b/llvm/utils/TableGen/Basic/TargetFeaturesEmitter.h
index 412f323d04821..bf933ed5c4b0d 100644
--- a/llvm/utils/TableGen/Basic/TargetFeaturesEmitter.h
+++ b/llvm/utils/TableGen/Basic/TargetFeaturesEmitter.h
@@ -16,6 +16,10 @@
 
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/TableGen/Record.h"
+#include "llvm/TargetParser/SubtargetFeature.h"
+#include <array>
+#include <cstdint>
+#include <vector>
 
 namespace llvm {
 /// Sorting predicate to sort record pointers by their
@@ -31,17 +35,28 @@ using FeatureMapTy = DenseMap<const Record *, unsigned>;
 
 class TargetFeaturesEmitter {
 protected:
+  using FeatureMask = std::array<uint64_t, MAX_SUBTARGET_WORDS>;
+  using FeatureMaskTable = std::vector<FeatureMask>;
+
   const RecordKeeper &Records;
   std::string Target;
 
+  static FeatureMask getFeatureMask(ArrayRef<const Record *> FeatureList,
+                                    const FeatureMapTy &FeatureMap);
+  static unsigned getFeatureMaskIndex(ArrayRef<const Record *> FeatureList,
+                                      const FeatureMapTy &FeatureMap,
+                                      FeatureMaskTable &FeatureMasks);
+  static void printFeatureMask(raw_ostream &OS, const FeatureMask &Mask);
+  static void printFeatureMaskTable(raw_ostream &OS, StringRef TableName,
+                                    ArrayRef<FeatureMask> FeatureMasks);
+
 public:
   TargetFeaturesEmitter(const RecordKeeper &R);
-  static void printFeatureMask(raw_ostream &OS,
-                               ArrayRef<const Record *> FeatureList,
-                               const FeatureMapTy &FeatureMap);
   FeatureMapTy enumeration(raw_ostream &OS);
-  void printFeatureKeyValues(raw_ostream &OS, const FeatureMapTy &FeatureMap);
-  void printCPUKeyValues(raw_ostream &OS, const FeatureMapTy &FeatureMap);
+  void printFeatureKeyValues(raw_ostream &OS, const FeatureMapTy &FeatureMap,
+                             FeatureMaskTable &FeatureMasks);
+  void printCPUKeyValues(raw_ostream &OS, const FeatureMapTy &FeatureMap,
+                         FeatureMaskTable &FeatureMasks);
   virtual void run(raw_ostream &O);
   virtual ~TargetFeaturesEmitter() = default;
 };
diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp
index c3a9d69d6ec3e..6de6a4dcbda27 100644
--- a/llvm/utils/TableGen/SubtargetEmitter.cpp
+++ b/llvm/utils/TableGen/SubtargetEmitter.cpp
@@ -78,15 +78,17 @@ class SubtargetEmitter : TargetFeaturesEmitter {
 
   FeatureMapTy emitEnums(raw_ostream &OS);
   void emitSubtargetInfoMacroCalls(raw_ostream &OS);
-  std::tuple<unsigned, unsigned, unsigned>
+  std::tuple<unsigned, unsigned, unsigned, unsigned>
   emitMCDesc(raw_ostream &OS, const FeatureMapTy &FeatureMap);
   void emitTargetDesc(raw_ostream &OS);
   void emitHeader(raw_ostream &OS);
   void emitCtor(raw_ostream &OS, unsigned NumNames, unsigned NumFeatures,
-                unsigned NumProcs);
+                unsigned NumProcs, unsigned NumFeatureMasks);
 
-  unsigned featureKeyValues(raw_ostream &OS, const FeatureMapTy &FeatureMap);
-  unsigned cpuKeyValues(raw_ostream &OS, const FeatureMapTy &FeatureMap);
+  unsigned featureKeyValues(raw_ostream &OS, const FeatureMapTy &FeatureMap,
+                            FeatureMaskTable &FeatureMasks);
+  unsigned cpuKeyValues(raw_ostream &OS, const FeatureMapTy &FeatureMap,
+                        FeatureMaskTable &FeatureMasks);
   unsigned cpuNames(raw_ostream &OS);
   void formItineraryStageString(const std::string &Names,
                                 const Record *ItinData, std::string &ItinString,
@@ -185,7 +187,8 @@ void SubtargetEmitter::emitSubtargetInfoMacroCalls(raw_ostream &OS) {
 // command line.
 //
 unsigned SubtargetEmitter::featureKeyValues(raw_ostream &OS,
-                                            const FeatureMapTy &FeatureMap) {
+                                            const FeatureMapTy &FeatureMap,
+                                            FeatureMaskTable &FeatureMasks) {
   std::vector<const Record *> FeatureList =
       Records.getAllDerivedDefinitions("SubtargetFeature");
 
@@ -218,7 +221,7 @@ unsigned SubtargetEmitter::featureKeyValues(raw_ostream &OS,
 
     ConstRecVec ImpliesList = Feature->getValueAsListOfDefs("Implies");
 
-    printFeatureMask(OS, ImpliesList, FeatureMap);
+    OS << getFeatureMaskIndex(ImpliesList, FeatureMap, FeatureMasks);
 
     OS << " },\n";
   }
@@ -292,7 +295,8 @@ static void checkDuplicateCPUFeatures(StringRef CPUName,
 // line.
 //
 unsigned SubtargetEmitter::cpuKeyValues(raw_ostream &OS,
-                                        const FeatureMapTy &FeatureMap) {
+                                        const FeatureMapTy &FeatureMap,
+                                        FeatureMaskTable &FeatureMasks) {
   // Gather and sort processor information
   std::vector<const Record *> ProcessorList =
       Records.getAllDerivedDefinitions("Processor");
@@ -322,9 +326,9 @@ unsigned SubtargetEmitter::cpuKeyValues(raw_ostream &OS,
     OS << " { "
        << "\"" << Name << "\", ";
 
-    printFeatureMask(OS, FeatureList, FeatureMap);
+    OS << getFeatureMaskIndex(FeatureList, FeatureMap, FeatureMasks);
     OS << ", ";
-    printFeatureMask(OS, TuneFeatureList, FeatureMap);
+    OS << getFeatureMaskIndex(TuneFeatureList, FeatureMap, FeatureMasks);
 
     // Emit the scheduler model pointer.
     const std::string &ProcModelName =
@@ -2007,11 +2011,12 @@ void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) {
      << "    ArrayRef<StringRef> PN,\n"
      << "    ArrayRef<SubtargetFeatureKV> PF,\n"
      << "    ArrayRef<SubtargetSubTypeKV> PD,\n"
+     << "    const FeatureBitArray *PFB,\n"
      << "    const MCWriteProcResEntry *WPR,\n"
      << "    const MCWriteLatencyEntry *WL,\n"
      << "    const MCReadAdvanceEntry *RA, const InstrStage *IS,\n"
      << "    const unsigned *OC, const unsigned *FP) :\n"
-     << "      MCSubtargetInfo(TT, CPU, TuneCPU, FS, PN, PF, PD,\n"
+     << "      MCSubtargetInfo(TT, CPU, TuneCPU, FS, PN, PF, PD, PFB,\n"
      << "                      WPR, WL, RA, IS, OC, FP) { }\n\n"
      << "  unsigned resolveVariantSchedClass(unsigned SchedClass,\n"
      << "      const MCInst *MI, const MCInstrInfo *MCII,\n"
@@ -2058,18 +2063,21 @@ FeatureMapTy SubtargetEmitter::emitEnums(raw_ostream &OS) {
   return enumeration(OS);
 }
 
-std::tuple<unsigned, unsigned, unsigned>
+std::tuple<unsigned, unsigned, unsigned, unsigned>
 SubtargetEmitter::emitMCDesc(raw_ostream &OS, const FeatureMapTy &FeatureMap) {
   IfDefEmitter IfDef(OS, "GET_SUBTARGETINFO_MC_DESC");
   if (Target == "AArch64")
     OS << "#include \"llvm/TargetParser/AArch64TargetParser.h\"\n\n";
   NamespaceEmitter LlvmNS(OS, "llvm");
+  FeatureMaskTable FeatureMasks;
 
-  unsigned NumFeatures = featureKeyValues(OS, FeatureMap);
+  unsigned NumFeatures = featureKeyValues(OS, FeatureMap, FeatureMasks);
   OS << "\n";
   emitSchedModel(OS);
   OS << "\n";
-  unsigned NumProcs = cpuKeyValues(OS, FeatureMap);
+  unsigned NumProcs = cpuKeyValues(OS, FeatureMap, FeatureMasks);
+  OS << "\n";
+  printFeatureMaskTable(OS, Target + "FeatureBitsets", FeatureMasks);
   OS << "\n";
   unsigned NumNames = cpuNames(OS);
   OS << "\n";
@@ -2097,6 +2105,10 @@ SubtargetEmitter::emitMCDesc(raw_ostream &OS, const FeatureMapTy &FeatureMap) {
     OS << Target << "SubTypeKV, ";
   else
     OS << "{}, ";
+  if (!FeatureMasks.empty())
+    OS << Target << "FeatureBitsets, ";
+  else
+    OS << "nullptr, ";
   OS << '\n';
   OS.indent(22);
   OS << Target << "WriteProcResTable, " << Target << "WriteLatencyTable, "
@@ -2110,7 +2122,8 @@ SubtargetEmitter::emitMCDesc(raw_ostream &OS, const FeatureMapTy &FeatureMap) {
     OS << "nullptr, nullptr, nullptr";
   }
   OS << ");\n}\n\n";
-  return {NumNames, NumFeatures, NumProcs};
+  return {NumNames, NumFeatures, NumProcs,
+          static_cast<unsigned>(FeatureMasks.size())};
 }
 
 void SubtargetEmitter::emitTargetDesc(raw_ostream &OS) {
@@ -2185,7 +2198,8 @@ void SubtargetEmitter::emitHeader(raw_ostream &OS) {
 }
 
 void SubtargetEmitter::emitCtor(raw_ostream &OS, unsigned NumNames,
-                                unsigned NumFeatures, unsigned NumProcs) {
+                                unsigned NumFeatures, unsigned NumProcs,
+                                unsigned NumFeatureMasks) {
   IfDefEmitter IfDef(OS, "GET_SUBTARGETINFO_CTOR");
   OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n\n";
 
@@ -2193,6 +2207,8 @@ void SubtargetEmitter::emitCtor(raw_ostream &OS, unsigned NumNames,
   OS << "extern const llvm::StringRef " << Target << "Names[];\n";
   OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n";
   OS << "extern const llvm::SubtargetSubTypeKV " << Target << "SubTypeKV[];\n";
+  OS << "extern const llvm::FeatureBitArray " << Target
+     << "FeatureBitsets[];\n";
   OS << "extern const llvm::MCWriteProcResEntry " << Target
      << "WriteProcResTable[];\n";
   OS << "extern const llvm::MCWriteLatencyEntry " << Target
@@ -2227,6 +2243,10 @@ void SubtargetEmitter::emitCtor(raw_ostream &OS, unsigned NumNames,
     OS << "ArrayRef(" << Target << "SubTypeKV, " << NumProcs << "), ";
   else
     OS << "{}, ";
+  if (NumFeatureMasks)
+    OS << Target << "FeatureBitsets, ";
+  else
+    OS << "nullptr, ";
   OS << '\n';
   OS.indent(24);
   OS << Target << "WriteProcResTable, " << Target << "WriteLatencyTable, "
@@ -2254,10 +2274,11 @@ void SubtargetEmitter::run(raw_ostream &OS) {
 
   auto FeatureMap = emitEnums(OS);
   emitSubtargetInfoMacroCalls(OS);
-  auto [NumNames, NumFeatures, NumProcs] = emitMCDesc(OS, FeatureMap);
+  auto [NumNames, NumFeatures, NumProcs, NumFeatureMasks] =
+      emitMCDesc(OS, FeatureMap);
   emitTargetDesc(OS);
   emitHeader(OS);
-  emitCtor(OS, NumNames, NumFeatures, NumProcs);
+  emitCtor(OS, NumNames, NumFeatures, NumProcs, NumFeatureMasks);
   emitMcInstrAnalysisPredicateFunctions(OS);
 }
 



More information about the llvm-commits mailing list