[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