[llvm] 5d13ff1 - [MC] Generate FeatureKV with compact string table (#206331)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Jul 5 00:42:26 PDT 2026
Author: Alexis Engelke
Date: 2026-07-05T07:42:22Z
New Revision: 5d13ff1e940b93d820928d078f994a3c376f54e6
URL: https://github.com/llvm/llvm-project/commit/5d13ff1e940b93d820928d078f994a3c376f54e6
DIFF: https://github.com/llvm/llvm-project/commit/5d13ff1e940b93d820928d078f994a3c376f54e6.diff
LOG: [MC] Generate FeatureKV with compact string table (#206331)
FeatureKV is responsible for a fair amount of .data.rel.ro size and
relocations; in an all-target build, this amounts to ~139 kiB that need
to be touched on every startup. Therefore, store strings adjacent to the
SubtargetFeatureKV in memory and reference the strings via relative
offsets to avoid dynamic relocations.
Added:
Modified:
llvm/include/llvm/MC/MCSubtargetInfo.h
llvm/test/TableGen/MacroFusion.td
llvm/utils/TableGen/SubtargetEmitter.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/MC/MCSubtargetInfo.h b/llvm/include/llvm/MC/MCSubtargetInfo.h
index 7f55ab7cd9d89..652dca7e68a17 100644
--- a/llvm/include/llvm/MC/MCSubtargetInfo.h
+++ b/llvm/include/llvm/MC/MCSubtargetInfo.h
@@ -34,24 +34,27 @@ class MCInst;
/// Used to provide key value pairs for feature and CPU bit flags.
struct SubtargetFeatureKV {
-private:
- const char *Key; ///< K-V key string
- const char *Desc; ///< Help descriptor
-
-public:
+ uint16_t KeyStrOff;
+ uint16_t DescStrOff;
unsigned Value; ///< K-V integer value
FeatureBitArray Implies; ///< K-V bit mask
- constexpr SubtargetFeatureKV(const char *Key, const char *Desc,
+ constexpr SubtargetFeatureKV(uint16_t KeyStrOff, uint16_t DescStrOff,
unsigned Value, FeatureBitArray Implies)
- : Key(Key), Desc(Desc), Value(Value), Implies(Implies) {}
+ : KeyStrOff(KeyStrOff), DescStrOff(DescStrOff), Value(Value),
+ Implies(Implies) {}
// Because of relative string offsets, this type is not copyable.
SubtargetFeatureKV(const SubtargetFeatureKV &) = delete;
SubtargetFeatureKV &operator=(const SubtargetFeatureKV &) = delete;
- const char *key() const { return Key; }
- const char *desc() const { return Desc; }
+ const char *key() const {
+ return reinterpret_cast<const char *>(this) + KeyStrOff;
+ }
+
+ const char *desc() const {
+ return reinterpret_cast<const char *>(this) + DescStrOff;
+ }
/// Compare routine for std::lower_bound
bool operator<(StringRef S) const { return StringRef(key()) < S; }
@@ -62,6 +65,12 @@ struct SubtargetFeatureKV {
}
};
+template <size_t NumFeatures, size_t FeatureStrTabSize>
+struct SubtargetFeatureKVStorage {
+ SubtargetFeatureKV Features[NumFeatures];
+ char Strings[FeatureStrTabSize];
+};
+
//===----------------------------------------------------------------------===//
/// Used to provide key value pairs for feature and CPU bit flags.
diff --git a/llvm/test/TableGen/MacroFusion.td b/llvm/test/TableGen/MacroFusion.td
index fd6e902c24dad..8fd823184a2b1 100644
--- a/llvm/test/TableGen/MacroFusion.td
+++ b/llvm/test/TableGen/MacroFusion.td
@@ -264,13 +264,6 @@ def TestFirstSameRegFusion: Fusion<"test-first-same-reg", "HasTestFirstSameRegFu
// CHECK-PREDICATOR-EMPTY:
// CHECK-PREDICATOR-NEXT: #endif // GET_Test_MACRO_FUSION_PRED_IMPL
-// Check that we have generated target subfeature.
-// CHECK-SUBTARGET: { "fusion-test", "Test Fusion", Test::TestFusion,
-// CHECK-SUBTARGET: { "fusion-test-both-fusion-predicate", "Test BothFusionPredicate", Test::TestBothFusionPredicate,
-// CHECK-SUBTARGET: { "fusion-test-commutable", "Test Commutable Fusion", Test::TestCommutableFusion,
-// CHECK-SUBTARGET: { "fusion-test-first-same-reg", "Test FirstSameReg", Test::TestFirstSameRegFusion,
-// CHECK-SUBTARGET: { "fusion-test-single", "Test SingleFusion", Test::TestSingleFusion,
-
// Check that we have generated `getMacroFusions()` function.
// CHECK-SUBTARGET: std::vector<MacroFusionPredTy> getMacroFusions() const final;
diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp
index bede5ebc44007..312148cb6ba8a 100644
--- a/llvm/utils/TableGen/SubtargetEmitter.cpp
+++ b/llvm/utils/TableGen/SubtargetEmitter.cpp
@@ -78,14 +78,20 @@ class SubtargetEmitter : TargetFeaturesEmitter {
FeatureMapTy emitEnums(raw_ostream &OS);
void emitSubtargetInfoMacroCalls(raw_ostream &OS);
- std::tuple<unsigned, unsigned, unsigned>
- emitMCDesc(raw_ostream &OS, const FeatureMapTy &FeatureMap);
+
+ struct MCDescInfo {
+ unsigned NumFeatures;
+ unsigned FeatureStrTabSize;
+ unsigned NumNames;
+ unsigned NumProcs;
+ };
+ MCDescInfo 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);
+ void emitCtor(raw_ostream &OS, MCDescInfo DescInfo);
- unsigned featureKeyValues(raw_ostream &OS, const FeatureMapTy &FeatureMap);
+ std::pair<unsigned, unsigned>
+ featureKeyValues(raw_ostream &OS, const FeatureMapTy &FeatureMap);
unsigned cpuKeyValues(raw_ostream &OS, const FeatureMapTy &FeatureMap);
unsigned cpuNames(raw_ostream &OS);
void formItineraryStageString(const std::string &Names,
@@ -186,8 +192,9 @@ void SubtargetEmitter::emitSubtargetInfoMacroCalls(raw_ostream &OS) {
// FeatureKeyValues - Emit data of all the subtarget features. Used by the
// command line.
//
-unsigned SubtargetEmitter::featureKeyValues(raw_ostream &OS,
- const FeatureMapTy &FeatureMap) {
+std::pair<unsigned, unsigned>
+SubtargetEmitter::featureKeyValues(raw_ostream &OS,
+ const FeatureMapTy &FeatureMap) {
std::vector<const Record *> FeatureList =
Records.getAllDerivedDefinitions("SubtargetFeature");
@@ -196,39 +203,54 @@ unsigned SubtargetEmitter::featureKeyValues(raw_ostream &OS,
return Rec->getValueAsString("Name").empty();
});
if (FeatureList.empty())
- return 0;
+ return {0, 0};
// Sort and check duplicate Feature name.
sortAndReportDuplicates(FeatureList, "Feature");
+ StringToOffsetTable StrTab;
+ // Offsets of CommandLineName and Desc in StrTab.
+ SmallVector<std::pair<unsigned, unsigned>> StrOffs;
+ for (const Record *Feature : FeatureList) {
+ unsigned NameOff =
+ StrTab.GetOrAddStringOffset(Feature->getValueAsString("Name"));
+ unsigned DescOff =
+ StrTab.GetOrAddStringOffset(Feature->getValueAsString("Desc"));
+ StrOffs.emplace_back(NameOff, DescOff);
+ }
+
// Begin feature table.
OS << "// Sorted (by key) array of values for CPU features.\n"
- << "extern const llvm::SubtargetFeatureKV " << Target
- << "FeatureKV[] = {\n";
+ << "extern const llvm::SubtargetFeatureKVStorage< " << FeatureList.size()
+ << ", " << (StrTab.size() + 1) << "> " << Target
+ << "FeatureKVStorage = {\n {\n";
- for (const Record *Feature : FeatureList) {
+ for (auto [Idx, Feature] : enumerate(FeatureList)) {
// Next feature
StringRef Name = Feature->getName();
- StringRef CommandLineName = Feature->getValueAsString("Name");
- StringRef Desc = Feature->getValueAsString("Desc");
// Emit as { "feature", "description", { featureEnum }, { i1 , i2 , ... , in
// } }
- OS << " { "
- << "\"" << CommandLineName << "\", "
- << "\"" << Desc << "\", " << Target << "::" << Name << ", ";
+ auto StrOff =
+ "sizeof(SubtargetFeatureKV) * " + Twine(FeatureList.size() - Idx);
+ OS << " { " << StrOff << " + " << StrOffs[Idx].first << ", " << StrOff
+ << " + " << StrOffs[Idx].second << ", " << Target << "::" << Name
+ << ", ";
ConstRecVec ImpliesList = Feature->getValueAsListOfDefs("Implies");
printFeatureMask(OS, ImpliesList, FeatureMap);
- OS << " },\n";
+ OS << " },\n";
}
+ OS << " },\n";
+ StrTab.EmitString(OS);
+
// End feature table.
OS << "};\n";
- return FeatureList.size();
+ return {FeatureList.size(), StrTab.size() + 1};
}
unsigned SubtargetEmitter::cpuNames(raw_ostream &OS) {
@@ -2079,20 +2101,23 @@ FeatureMapTy SubtargetEmitter::emitEnums(raw_ostream &OS) {
return enumeration(OS);
}
-std::tuple<unsigned, unsigned, unsigned>
+SubtargetEmitter::MCDescInfo
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");
- unsigned NumFeatures = featureKeyValues(OS, FeatureMap);
+ MCDescInfo Res;
+ auto [NumFeatures, FeatureStrTabSize] = featureKeyValues(OS, FeatureMap);
+ Res.NumFeatures = NumFeatures;
+ Res.FeatureStrTabSize = FeatureStrTabSize;
OS << "\n";
emitSchedModel(OS);
OS << "\n";
- unsigned NumProcs = cpuKeyValues(OS, FeatureMap);
+ Res.NumProcs = cpuKeyValues(OS, FeatureMap);
OS << "\n";
- unsigned NumNames = cpuNames(OS);
+ Res.NumNames = cpuNames(OS);
OS << "\n";
// MCInstrInfo initialization routine.
@@ -2106,15 +2131,15 @@ SubtargetEmitter::emitMCDesc(raw_ostream &OS, const FeatureMapTy &FeatureMap) {
<< " TuneCPU = AArch64::resolveCPUAlias(TuneCPU);\n";
OS << " return new " << Target
<< "GenMCSubtargetInfo(TT, CPU, TuneCPU, FS, ";
- if (NumNames)
+ if (Res.NumNames)
OS << Target << "Names, ";
else
OS << "{}, ";
- if (NumFeatures)
- OS << Target << "FeatureKV, ";
+ if (Res.NumFeatures)
+ OS << Target << "FeatureKVStorage.Features, ";
else
OS << "{}, ";
- if (NumProcs)
+ if (Res.NumProcs)
OS << Target << "SubTypeKV, ";
else
OS << "{}, ";
@@ -2131,7 +2156,7 @@ SubtargetEmitter::emitMCDesc(raw_ostream &OS, const FeatureMapTy &FeatureMap) {
OS << "nullptr, nullptr, nullptr";
}
OS << ");\n}\n\n";
- return {NumNames, NumFeatures, NumProcs};
+ return Res;
}
void SubtargetEmitter::emitTargetDesc(raw_ostream &OS) {
@@ -2209,14 +2234,17 @@ void SubtargetEmitter::emitHeader(raw_ostream &OS) {
OS << "};\n";
}
-void SubtargetEmitter::emitCtor(raw_ostream &OS, unsigned NumNames,
- unsigned NumFeatures, unsigned NumProcs) {
+void SubtargetEmitter::emitCtor(raw_ostream &OS, MCDescInfo DescInfo) {
IfDefEmitter IfDef(OS, "GET_SUBTARGETINFO_CTOR");
OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n\n";
NamespaceEmitter LLVMNS(OS, "llvm");
OS << "extern const llvm::StringRef " << Target << "Names[];\n";
- OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n";
+ if (DescInfo.NumFeatures) {
+ OS << "extern const llvm::SubtargetFeatureKVStorage<"
+ << DescInfo.NumFeatures << ", " << DescInfo.FeatureStrTabSize << "> "
+ << Target << "FeatureKVStorage;\n";
+ }
OS << "extern const llvm::SubtargetSubTypeKV " << Target << "SubTypeKV[];\n";
OS << "extern const llvm::MCWriteProcResEntry " << Target
<< "WriteProcResTable[];\n";
@@ -2240,16 +2268,16 @@ void SubtargetEmitter::emitCtor(raw_ostream &OS, unsigned NumNames,
<< " AArch64::resolveCPUAlias(TuneCPU), FS, ";
else
OS << " : TargetSubtargetInfo(TT, CPU, TuneCPU, FS, ";
- if (NumNames)
- OS << "ArrayRef(" << Target << "Names, " << NumNames << "), ";
+ if (DescInfo.NumNames)
+ OS << "ArrayRef(" << Target << "Names, " << DescInfo.NumNames << "), ";
else
OS << "{}, ";
- if (NumFeatures)
- OS << "ArrayRef(" << Target << "FeatureKV, " << NumFeatures << "), ";
+ if (DescInfo.NumFeatures)
+ OS << "ArrayRef(" << Target << "FeatureKVStorage.Features), ";
else
OS << "{}, ";
- if (NumProcs)
- OS << "ArrayRef(" << Target << "SubTypeKV, " << NumProcs << "), ";
+ if (DescInfo.NumProcs)
+ OS << "ArrayRef(" << Target << "SubTypeKV, " << DescInfo.NumProcs << "), ";
else
OS << "{}, ";
OS << '\n';
@@ -2282,10 +2310,10 @@ void SubtargetEmitter::run(raw_ostream &OS) {
auto FeatureMap = emitEnums(OS);
emitSubtargetInfoMacroCalls(OS);
- auto [NumNames, NumFeatures, NumProcs] = emitMCDesc(OS, FeatureMap);
+ MCDescInfo DescInfo = emitMCDesc(OS, FeatureMap);
emitTargetDesc(OS);
emitHeader(OS);
- emitCtor(OS, NumNames, NumFeatures, NumProcs);
+ emitCtor(OS, DescInfo);
emitMcInstrAnalysisPredicateFunctions(OS);
}
More information about the llvm-commits
mailing list