[llvm-branch-commits] [llvm] TableGen: Use a compact table for CPU aliases (PR #211952)
Matt Arsenault via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Jul 24 23:26:03 PDT 2026
https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/211952
>From 38f619ca4ed84729524ed3993dd1a6c4bc70ff15 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Fri, 24 Jul 2026 18:44:04 +0200
Subject: [PATCH 1/2] TableGen: Use a compact table for CPU aliases
Previously each ProcessorAlias was emitted as a full SubtargetSubTypeKV
entry in the processor subtype table, duplicating the canonical
processor's feature masks and scheduling model index. At 104 bytes per
entry: AArch64's 18 aliases added ~1.8KB, and X86 will add more as aliases
are introduced.
Emit aliases into a separate SubtargetSubTypeAliasKV table instead. Each
alias is just a name string offset plus the index of the canonical
processor it resolves to.
Co-authored-by: Claude (Claude-Opus-4.8) <noreply at anthropic.com>
---
.../llvm/CodeGen/TargetSubtargetInfo.h | 5 +-
llvm/include/llvm/MC/MCSubtargetInfo.h | 35 ++++-
llvm/lib/CodeGen/TargetSubtargetInfo.cpp | 12 +-
llvm/lib/MC/MCSubtargetInfo.cpp | 30 ++--
llvm/test/TableGen/ProcessorAlias.td | 29 ++--
llvm/unittests/CodeGen/MFCommon.inc | 6 +-
llvm/unittests/CodeGen/MachineInstrTest.cpp | 4 +-
llvm/unittests/CodeGen/MachineOperandTest.cpp | 2 +-
.../Target/AArch64/AArch64InstPrinterTest.cpp | 2 +-
llvm/utils/TableGen/SubtargetEmitter.cpp | 138 ++++++++++++------
10 files changed, 174 insertions(+), 89 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
index db73a9675b71d..a50f7f804b03d 100644
--- a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
@@ -72,8 +72,9 @@ class LLVM_ABI TargetSubtargetInfo : public MCSubtargetInfo {
TargetSubtargetInfo(const Triple &TT, StringRef CPU, StringRef TuneCPU,
StringRef FS, StringTable PN,
ArrayRef<SubtargetFeatureKV> PF,
- ArrayRef<SubtargetSubTypeKV> PD, const MCSchedModel *PSM,
- const MCWriteProcResEntry *WPR,
+ ArrayRef<SubtargetSubTypeKV> PD,
+ ArrayRef<SubtargetSubTypeAliasKV> PA,
+ const MCSchedModel *PSM, const MCWriteProcResEntry *WPR,
const MCWriteLatencyEntry *WL,
const MCReadAdvanceEntry *RA, const InstrStage *IS,
const unsigned *OC, const unsigned *FP);
diff --git a/llvm/include/llvm/MC/MCSubtargetInfo.h b/llvm/include/llvm/MC/MCSubtargetInfo.h
index e8de24cee5831..ce12169a1a891 100644
--- a/llvm/include/llvm/MC/MCSubtargetInfo.h
+++ b/llvm/include/llvm/MC/MCSubtargetInfo.h
@@ -22,6 +22,7 @@
#include "llvm/Support/Compiler.h"
#include "llvm/TargetParser/SubtargetFeature.h"
#include "llvm/TargetParser/Triple.h"
+#include <array>
#include <cassert>
#include <cstdint>
#include <optional>
@@ -104,9 +105,28 @@ struct SubtargetSubTypeKV {
}
};
-template <size_t NumSubTypes, size_t SubTypeStrTabSize>
+/// Maps a CPU alias name to the index of the processor it resolves to.
+struct SubtargetSubTypeAliasKV {
+ uint16_t KeyStrOff; ///< Relative offset to the alias name.
+ uint16_t SubTypeIdx; ///< Index into the SubtargetSubTypeKV array.
+
+ constexpr SubtargetSubTypeAliasKV(uint16_t KeyStrOff, uint16_t SubTypeIdx)
+ : KeyStrOff(KeyStrOff), SubTypeIdx(SubTypeIdx) {}
+
+ SubtargetSubTypeAliasKV(const SubtargetSubTypeAliasKV &) = delete;
+ SubtargetSubTypeAliasKV &operator=(const SubtargetSubTypeAliasKV &) = delete;
+
+ const char *key() const {
+ return reinterpret_cast<const char *>(this) + KeyStrOff;
+ }
+
+ bool operator<(StringRef S) const { return StringRef(key()) < S; }
+};
+
+template <size_t NumSubTypes, size_t NumAliases, size_t SubTypeStrTabSize>
struct SubtargetSubTypeKVStorage {
SubtargetSubTypeKV SubTypes[NumSubTypes];
+ std::array<SubtargetSubTypeAliasKV, NumAliases> Aliases;
char Strings[SubTypeStrTabSize];
};
@@ -121,6 +141,7 @@ class LLVM_ABI MCSubtargetInfo {
StringTable ProcNames; // Processor list, including aliases
ArrayRef<SubtargetFeatureKV> ProcFeatures; // Processor feature list
ArrayRef<SubtargetSubTypeKV> ProcDesc; // Processor descriptions
+ ArrayRef<SubtargetSubTypeAliasKV> ProcAliases; // CPU alias -> processor map
const MCSchedModel *ProcSchedModels; ///< Processor scheduling models.
// Scheduler machine model
@@ -139,7 +160,8 @@ class LLVM_ABI MCSubtargetInfo {
MCSubtargetInfo(const MCSubtargetInfo &) = default;
MCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef TuneCPU,
StringRef FS, StringTable PN, ArrayRef<SubtargetFeatureKV> PF,
- ArrayRef<SubtargetSubTypeKV> PD, const MCSchedModel *PSM,
+ ArrayRef<SubtargetSubTypeKV> PD,
+ ArrayRef<SubtargetSubTypeAliasKV> PA, const MCSchedModel *PSM,
const MCWriteProcResEntry *WPR, const MCWriteLatencyEntry *WL,
const MCReadAdvanceEntry *RA, const InstrStage *IS,
const unsigned *OC, const unsigned *FP);
@@ -273,11 +295,12 @@ class LLVM_ABI MCSubtargetInfo {
return 0;
}
+ /// Look up the processor entry for a CPU name, resolving aliases. Returns
+ /// nullptr if the name matches neither a processor nor an alias.
+ const SubtargetSubTypeKV *resolveCPU(StringRef CPU) const;
+
/// Check whether the CPU string is valid.
- bool isCPUStringValid(StringRef CPU) const {
- auto Found = llvm::lower_bound(ProcDesc, CPU);
- return Found != ProcDesc.end() && StringRef(Found->key()) == CPU;
- }
+ bool isCPUStringValid(StringRef CPU) const { return resolveCPU(CPU); }
/// Return processor descriptions.
ArrayRef<SubtargetSubTypeKV> getAllProcessorDescriptions() const {
diff --git a/llvm/lib/CodeGen/TargetSubtargetInfo.cpp b/llvm/lib/CodeGen/TargetSubtargetInfo.cpp
index 727eff7ddce58..b5d51525710c9 100644
--- a/llvm/lib/CodeGen/TargetSubtargetInfo.cpp
+++ b/llvm/lib/CodeGen/TargetSubtargetInfo.cpp
@@ -18,12 +18,12 @@ using namespace llvm;
TargetSubtargetInfo::TargetSubtargetInfo(
const Triple &TT, StringRef CPU, StringRef TuneCPU, StringRef FS,
StringTable PN, ArrayRef<SubtargetFeatureKV> PF,
- ArrayRef<SubtargetSubTypeKV> PD, const MCSchedModel *PSM,
- 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, PSM, WPR, WL, RA, IS,
- OC, FP) {}
+ ArrayRef<SubtargetSubTypeKV> PD, ArrayRef<SubtargetSubTypeAliasKV> PA,
+ const MCSchedModel *PSM, 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, PA, PSM, WPR, WL, RA,
+ IS, OC, FP) {}
TargetSubtargetInfo::~TargetSubtargetInfo() = default;
diff --git a/llvm/lib/MC/MCSubtargetInfo.cpp b/llvm/lib/MC/MCSubtargetInfo.cpp
index 7a962052f211c..45059ba8fe01d 100644
--- a/llvm/lib/MC/MCSubtargetInfo.cpp
+++ b/llvm/lib/MC/MCSubtargetInfo.cpp
@@ -197,7 +197,7 @@ static FeatureBitset getFeatures(MCSubtargetInfo &STI, StringRef CPU,
// Find CPU entry if CPU name is specified.
else if (!CPU.empty()) {
- const SubtargetSubTypeKV *CPUEntry = Find(CPU, ProcDesc);
+ const SubtargetSubTypeKV *CPUEntry = STI.resolveCPU(CPU);
// If there is a match
if (CPUEntry) {
@@ -210,7 +210,7 @@ static FeatureBitset getFeatures(MCSubtargetInfo &STI, StringRef CPU,
}
if (!TuneCPU.empty()) {
- const SubtargetSubTypeKV *CPUEntry = Find(TuneCPU, ProcDesc);
+ const SubtargetSubTypeKV *CPUEntry = STI.resolveCPU(TuneCPU);
// If there is a match
if (CPUEntry) {
@@ -258,13 +258,14 @@ void MCSubtargetInfo::setDefaultFeatures(StringRef CPU, StringRef TuneCPU,
MCSubtargetInfo::MCSubtargetInfo(
const Triple &TT, StringRef C, StringRef TC, StringRef FS, StringTable PN,
ArrayRef<SubtargetFeatureKV> PF, ArrayRef<SubtargetSubTypeKV> PD,
- const MCSchedModel *PSM, const MCWriteProcResEntry *WPR,
- const MCWriteLatencyEntry *WL, const MCReadAdvanceEntry *RA,
- const InstrStage *IS, const unsigned *OC, const unsigned *FP)
+ ArrayRef<SubtargetSubTypeAliasKV> PA, const MCSchedModel *PSM,
+ 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), ProcSchedModels(PSM),
- WriteProcResTable(WPR), WriteLatencyTable(WL), ReadAdvanceTable(RA),
- Stages(IS), OperandCycles(OC), ForwardingPaths(FP) {
+ ProcNames(PN), ProcFeatures(PF), ProcDesc(PD), ProcAliases(PA),
+ ProcSchedModels(PSM), WriteProcResTable(WPR), WriteLatencyTable(WL),
+ ReadAdvanceTable(RA), Stages(IS), OperandCycles(OC), ForwardingPaths(FP) {
InitMCProcessorInfo(CPU, TuneCPU, FS);
}
@@ -434,12 +435,23 @@ bool MCSubtargetInfo::checkFeatureExpression(StringRef FeatureExpr) const {
return Parser.parse();
}
+const SubtargetSubTypeKV *MCSubtargetInfo::resolveCPU(StringRef CPU) const {
+ if (const SubtargetSubTypeKV *CPUEntry = Find(CPU, ProcDesc))
+ return CPUEntry;
+
+ // Not a canonical processor name; check whether it is a known alias.
+ if (const SubtargetSubTypeAliasKV *Alias = Find(CPU, ProcAliases))
+ return &ProcDesc[Alias->SubTypeIdx];
+
+ return nullptr;
+}
+
const MCSchedModel &MCSubtargetInfo::getSchedModelForCPU(StringRef CPU) const {
assert(llvm::is_sorted(ProcDesc) &&
"Processor machine model table is not sorted");
// Find entry
- const SubtargetSubTypeKV *CPUEntry = Find(CPU, ProcDesc);
+ const SubtargetSubTypeKV *CPUEntry = resolveCPU(CPU);
if (!CPUEntry) {
if (CPU != "help") // Don't error if the user asked for help.
diff --git a/llvm/test/TableGen/ProcessorAlias.td b/llvm/test/TableGen/ProcessorAlias.td
index c70c7dd58f8e4..6e3f970f0d425 100644
--- a/llvm/test/TableGen/ProcessorAlias.td
+++ b/llvm/test/TableGen/ProcessorAlias.td
@@ -1,7 +1,7 @@
// RUN: llvm-tblgen -gen-subtarget -I %p/../../include %s 2>&1 | FileCheck %s
-// Verify that ProcessorAlias entries are emitted into the CPU subtype table
-// alongside real processors, resolving to their canonical processor's
-// features and scheduling model, and that the table stays sorted by key.
+// Verify that ProcessorAlias entries are emitted into a separate, compact alias
+// table (mapping alias name -> canonical processor index) rather than as full
+// SubtargetSubTypeKV entries, and that both tables stay sorted by key.
include "llvm/Target/Target.td"
@@ -12,13 +12,20 @@ def FeatureA : SubtargetFeature<"feature-a", "HasA", "true", "">;
def ProcA : ProcessorModel<"cpu-a", NoSchedModel, [FeatureA]>;
def ProcB : ProcessorModel<"cpu-b", NoSchedModel, []>;
-// An alias resolves to an existing processor and is emitted as its own entry.
+// Two aliases pointing at cpu-a (index 0). One sorts before its canonical name,
+// the other after, so the alias table order is independent of cpu-a's position.
def : ProcessorAlias<"alias-of-a", "cpu-a">;
+def : ProcessorAlias<"zzz-of-a", "cpu-a">;
-// The subtype table has 3 entries (2 processors + 1 alias) sorted by key:
-// alias-of-a, cpu-a, cpu-b. The alias carries cpu-a's feature mask (bit 0 set).
-// CHECK: extern const llvm::SubtargetSubTypeKVStorage< 3,
-// CHECK: { sizeof(SubtargetSubTypeKV) * 3 + {{[0-9]+}}, { { { 0x1ULL,{{.*}} }, {{.*}}, 0 },
-// CHECK-NEXT: { sizeof(SubtargetSubTypeKV) * 2 + {{[0-9]+}}, { { { 0x1ULL,{{.*}} }, {{.*}}, 0 },
-// CHECK-NEXT: { sizeof(SubtargetSubTypeKV) * 1 + {{[0-9]+}}, { { { 0x0ULL,{{.*}} }, {{.*}}, 0 },
-// CHECK: "\000alias-of-a\000cpu-a\000cpu-b\000"
+// The subtype table holds only the 2 real processors; the storage template
+// records 2 subtypes and 2 aliases.
+// CHECK: static constexpr size_t MyTargetCPUAliasArraySize = sizeof(std::array<SubtargetSubTypeAliasKV, 2>);
+// CHECK: extern const llvm::SubtargetSubTypeKVStorage< 2, 2, {{[0-9]+}}> MyTargetSubTypeKVStorage
+// CHECK: { sizeof(SubtargetSubTypeKV) * 2 + MyTargetCPUAliasArraySize + {{[0-9]+}}, { { { 0x1ULL,{{.*}} }, {{.*}}, 0 },
+// CHECK-NEXT: { sizeof(SubtargetSubTypeKV) * 1 + MyTargetCPUAliasArraySize + {{[0-9]+}}, { { { 0x0ULL,{{.*}} }, {{.*}}, 0 },
+
+// The alias table is sorted by alias name (alias-of-a, zzz-of-a); both resolve
+// to subtype index 0 (cpu-a).
+// CHECK: { sizeof(SubtargetSubTypeAliasKV) * 2 + {{[0-9]+}}, 0 },
+// CHECK-NEXT: { sizeof(SubtargetSubTypeAliasKV) * 1 + {{[0-9]+}}, 0 },
+// CHECK: "\000cpu-a\000cpu-b\000alias-of-a\000zzz-of-a\000"
diff --git a/llvm/unittests/CodeGen/MFCommon.inc b/llvm/unittests/CodeGen/MFCommon.inc
index 5a09e62cc99c5..35b5351d6f364 100644
--- a/llvm/unittests/CodeGen/MFCommon.inc
+++ b/llvm/unittests/CodeGen/MFCommon.inc
@@ -92,7 +92,7 @@ public:
class BogusSubtarget : public TargetSubtargetInfo {
public:
BogusSubtarget(TargetMachine &TM)
- : TargetSubtargetInfo(Triple(""), "", "", "", "", {}, {}, nullptr,
+ : TargetSubtargetInfo(Triple(""), "", "", "", "", {}, {}, {}, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr),
FL(), TL(TM, *this) {}
@@ -148,8 +148,8 @@ public:
MRI = std::make_unique<MCRegisterInfo>();
STI = std::make_unique<MCSubtargetInfo>(
Triple(""), "", "", "", StringTable{""}, ArrayRef<SubtargetFeatureKV>{},
- ArrayRef<SubtargetSubTypeKV>{}, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr);
+ ArrayRef<SubtargetSubTypeKV>{}, ArrayRef<SubtargetSubTypeAliasKV>{},
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
}
~BogusTargetMachine() override = default;
diff --git a/llvm/unittests/CodeGen/MachineInstrTest.cpp b/llvm/unittests/CodeGen/MachineInstrTest.cpp
index 0ec589c45af08..03f4077ea55ac 100644
--- a/llvm/unittests/CodeGen/MachineInstrTest.cpp
+++ b/llvm/unittests/CodeGen/MachineInstrTest.cpp
@@ -43,9 +43,9 @@ std::unique_ptr<MCContext> createMCContext(const MCAsmInfo &AsmInfo) {
Triple TheTriple(/*ArchStr=*/"", /*VendorStr=*/"", /*OSStr=*/"",
/*EnvironmentStr=*/"elf");
static MCRegisterInfo MRI;
- static const MCSubtargetInfo STI(TheTriple, "", "", "", "", {}, {}, nullptr,
+ static const MCSubtargetInfo STI(TheTriple, "", "", "", "", {}, {}, {},
nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr);
+ nullptr, nullptr);
return std::make_unique<MCContext>(TheTriple, AsmInfo, MRI, STI, nullptr,
false);
}
diff --git a/llvm/unittests/CodeGen/MachineOperandTest.cpp b/llvm/unittests/CodeGen/MachineOperandTest.cpp
index 21254599a227c..f5bcb5332d64e 100644
--- a/llvm/unittests/CodeGen/MachineOperandTest.cpp
+++ b/llvm/unittests/CodeGen/MachineOperandTest.cpp
@@ -353,7 +353,7 @@ TEST(MachineOperandTest, PrintMCSymbol) {
MCAsmInfo MAI(MCOptions);
MCRegisterInfo MRI;
Triple T = Triple("unknown-unknown-unknown");
- MCSubtargetInfo STI(T, "", "", "", "", {}, {}, nullptr, nullptr, nullptr,
+ MCSubtargetInfo STI(T, "", "", "", "", {}, {}, {}, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr);
MCContext Ctx(T, MAI, MRI, STI);
MCSymbol *Sym = Ctx.getOrCreateSymbol("foo");
diff --git a/llvm/unittests/Target/AArch64/AArch64InstPrinterTest.cpp b/llvm/unittests/Target/AArch64/AArch64InstPrinterTest.cpp
index f922d7c7b9a15..b336eb80a2a18 100644
--- a/llvm/unittests/Target/AArch64/AArch64InstPrinterTest.cpp
+++ b/llvm/unittests/Target/AArch64/AArch64InstPrinterTest.cpp
@@ -38,7 +38,7 @@ static std::string AArch64InstPrinterTestPrintAlignedLabel(uint64_t value) {
MCAsmInfo MAI(MCOptions);
MCInstrInfo MII;
MCRegisterInfo MRI;
- MCSubtargetInfo STI(Triple(""), "", "", "", "", {}, {}, nullptr, nullptr,
+ MCSubtargetInfo STI(Triple(""), "", "", "", "", {}, {}, {}, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr);
MCContext Ctx(Triple(""), MAI, MRI, STI);
MCInst MI;
diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp
index ff7eaa1c55b4b..93b5eb2b3d985 100644
--- a/llvm/utils/TableGen/SubtargetEmitter.cpp
+++ b/llvm/utils/TableGen/SubtargetEmitter.cpp
@@ -22,6 +22,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/MC/MCInstrItineraries.h"
#include "llvm/MC/MCSchedule.h"
#include "llvm/Support/Debug.h"
@@ -85,6 +86,7 @@ class SubtargetEmitter : TargetFeaturesEmitter {
unsigned NumFeatures;
unsigned FeatureStrTabSize;
unsigned NumProcs;
+ unsigned NumAliases;
unsigned SubTypeStrTabSize;
};
MCDescInfo emitMCDesc(raw_ostream &OS, const FeatureMapTy &FeatureMap);
@@ -92,10 +94,15 @@ class SubtargetEmitter : TargetFeaturesEmitter {
void emitHeader(raw_ostream &OS);
void emitCtor(raw_ostream &OS, MCDescInfo DescInfo);
+ struct CPUKeyValuesInfo {
+ unsigned NumProcs;
+ unsigned NumAliases;
+ unsigned SubTypeStrTabSize;
+ };
std::pair<unsigned, unsigned>
featureKeyValues(raw_ostream &OS, const FeatureMapTy &FeatureMap);
- std::pair<unsigned, unsigned> cpuKeyValues(raw_ostream &OS,
- const FeatureMapTy &FeatureMap);
+ CPUKeyValuesInfo cpuKeyValues(raw_ostream &OS,
+ const FeatureMapTy &FeatureMap);
void formItineraryStageString(const std::string &Names,
const Record *ItinData, std::string &ItinString,
unsigned &NStages);
@@ -283,73 +290,92 @@ static void checkDuplicateCPUFeatures(StringRef CPUName,
// CPUKeyValues - Emit data of all the subtarget processors. Used by command
// line.
//
-std::pair<unsigned, unsigned>
+SubtargetEmitter::CPUKeyValuesInfo
SubtargetEmitter::cpuKeyValues(raw_ostream &OS,
const FeatureMapTy &FeatureMap) {
+ // Gather and sort the processors. Only real processors go in the subtype
+ // table; aliases are stored in a separate, more compact table.
std::vector<const Record *> ProcessorList =
Records.getAllDerivedDefinitions("Processor");
-
- StringMap<const Record *> ProcessorMap;
- for (const Record *Processor : ProcessorList)
- ProcessorMap[Processor->getValueAsString("Name")] = Processor;
-
- // Maps each emitted CPU name (processor or alias) to the processor record it
- // resolves to. Keying by name detects duplicates on insertion.
- StringMap<const Record *> SubTypeEntries;
- for (const Record *Processor : ProcessorList)
- SubTypeEntries[Processor->getValueAsString("Name")] = Processor;
-
+ llvm::sort(ProcessorList, LessRecordFieldName());
+
+ // Map from processor name to its index in the sorted subtype table, so that
+ // aliases can point at the canonical processor entry.
+ StringMap<unsigned> ProcessorIndex;
+ for (const auto &[Idx, Processor] : enumerate(ProcessorList))
+ ProcessorIndex[Processor->getValueAsString("Name")] = Idx;
+
+ // Validate and resolve each alias to the index of its canonical processor.
+ struct AliasEntry {
+ StringRef Name;
+ unsigned SubTypeIdx;
+ };
+ std::vector<AliasEntry> AliasEntries;
std::vector<const Record *> ProcessorAliasList =
Records.getAllDerivedDefinitionsIfDefined("ProcessorAlias");
+ AliasEntries.reserve(ProcessorAliasList.size());
+
+ StringSet<> AliasNames;
for (const Record *Rec : ProcessorAliasList) {
StringRef Name = Rec->getValueAsString("Name");
StringRef Alias = Rec->getValueAsString("Alias");
- auto It = ProcessorMap.find(Alias);
- if (It == ProcessorMap.end())
+ auto It = ProcessorIndex.find(Alias);
+ if (It == ProcessorIndex.end())
PrintFatalError(Rec, "Alias '" + Name +
"' references a non-existent Processor '" +
Alias + "'");
- if (!SubTypeEntries.try_emplace(Name, It->second).second)
- PrintFatalError(
- Rec, "Alias '" + Name + "' duplicates an existing " +
- (ProcessorMap.contains(Name) ? "Processor" : "alias"));
+ if (ProcessorIndex.contains(Name))
+ PrintFatalError(Rec,
+ "Alias '" + Name + "' duplicates an existing Processor");
+ if (!AliasNames.insert(Name).second)
+ PrintFatalError(Rec, "Alias '" + Name + "' duplicates an existing alias");
+ AliasEntries.push_back({Name, It->second});
}
- // The table must stay sorted by key for the binary search in the lookups.
- std::vector<std::pair<StringRef, const Record *>> SortedEntries;
- SortedEntries.reserve(SubTypeEntries.size());
- for (const auto &Entry : SubTypeEntries)
- SortedEntries.emplace_back(Entry.getKey(), Entry.getValue());
- llvm::sort(SortedEntries, llvm::less_first());
+ // The alias table must be sorted by key for the binary search in the lookups.
+ llvm::sort(AliasEntries, [](const AliasEntry &LHS, const AliasEntry &RHS) {
+ return LHS.Name < RHS.Name;
+ });
StringToOffsetTable StrTab;
- for (const auto &[Name, Proc] : SortedEntries)
- StrTab.GetOrAddStringOffset(Name);
+ for (const Record *Processor : ProcessorList)
+ StrTab.GetOrAddStringOffset(Processor->getValueAsString("Name"));
+ for (const AliasEntry &Entry : AliasEntries)
+ StrTab.GetOrAddStringOffset(Entry.Name);
// Note that unlike `FeatureKeyValues`, here we do not need to check for
// duplicate processors, since that is already done when the SubtargetEmitter
// constructor calls `getSchedModels` to build a `CodeGenSchedModels` object,
// which does the duplicate processor check.
- unsigned Total = SortedEntries.size();
+ unsigned NumProcs = ProcessorList.size();
+ unsigned NumAliases = AliasEntries.size();
+
+ // The alias array's byte size, used to reach the string blob from a subtype
+ // entry.
+ OS << "static constexpr size_t " << Target
+ << "CPUAliasArraySize = sizeof(std::array<SubtargetSubTypeAliasKV, "
+ << NumAliases << ">);\n";
// Begin processor table.
OS << "// Sorted (by key) array of values for CPU subtype.\n"
- << "extern const llvm::SubtargetSubTypeKVStorage< " << Total << ", "
- << (StrTab.size() + 1) << "> " << Target << "SubTypeKVStorage = {\n {\n";
+ << "extern const llvm::SubtargetSubTypeKVStorage< " << NumProcs << ", "
+ << NumAliases << ", " << (StrTab.size() + 1) << "> " << Target
+ << "SubTypeKVStorage = {\n {\n";
- for (const auto &[Idx, Entry] : enumerate(SortedEntries)) {
- const auto &[Name, Processor] = Entry;
+ for (const auto &[Idx, Processor] : enumerate(ProcessorList)) {
+ StringRef Name = Processor->getValueAsString("Name");
ConstRecVec FeatureList = Processor->getValueAsListOfDefs("Features");
ConstRecVec TuneFeatureList =
Processor->getValueAsListOfDefs("TuneFeatures");
- // Aliases share the canonical processor's already-checked feature lists.
- if (Name == Processor->getValueAsString("Name"))
- checkDuplicateCPUFeatures(Name, FeatureList, TuneFeatureList);
+ // Warn the user if there are duplicate processor features or tune features.
+ checkDuplicateCPUFeatures(Name, FeatureList, TuneFeatureList);
- OS << " { sizeof(SubtargetSubTypeKV) * " << (Total - Idx) << " + "
- << StrTab.GetOrAddStringOffset(Name) << ", ";
+ // The string blob follows the subtype and alias arrays, so skip both.
+ OS << " { sizeof(SubtargetSubTypeKV) * " << (NumProcs - Idx) << " + "
+ << Target << "CPUAliasArraySize + " << StrTab.GetOrAddStringOffset(Name)
+ << ", ";
printFeatureMask(OS, FeatureList, FeatureMap);
OS << ", ";
@@ -360,12 +386,23 @@ SubtargetEmitter::cpuKeyValues(raw_ostream &OS,
}
OS << " },\n";
+
+ // Begin alias table. The extra brace layer is std::array's wrapped C array.
+ OS << " { {\n";
+ for (const auto &[Idx, Entry] : enumerate(AliasEntries)) {
+ // The string blob immediately follows the alias array.
+ OS << " { sizeof(SubtargetSubTypeAliasKV) * " << (NumAliases - Idx)
+ << " + " << StrTab.GetOrAddStringOffset(Entry.Name) << ", "
+ << Entry.SubTypeIdx << " },\n";
+ }
+ OS << " } },\n";
+
StrTab.EmitString(OS);
// End processor table.
OS << "};\n";
- return {Total, StrTab.size() + 1};
+ return {NumProcs, NumAliases, unsigned(StrTab.size() + 1)};
}
//
@@ -2067,12 +2104,13 @@ void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) {
<< " StringTable PN,\n"
<< " ArrayRef<SubtargetFeatureKV> PF,\n"
<< " ArrayRef<SubtargetSubTypeKV> PD,\n"
+ << " ArrayRef<SubtargetSubTypeAliasKV> PA,\n"
<< " const MCSchedModel *PSM,\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, PSM,\n"
+ << " MCSubtargetInfo(TT, CPU, TuneCPU, FS, PN, PF, PD, PA, PSM,\n"
<< " WPR, WL, RA, IS, OC, FP) { }\n\n"
<< " unsigned resolveVariantSchedClass(unsigned SchedClass,\n"
<< " const MCInst *MI, const MCInstrInfo *MCII,\n"
@@ -2126,8 +2164,9 @@ SubtargetEmitter::emitMCDesc(raw_ostream &OS, const FeatureMapTy &FeatureMap) {
OS << "\n";
emitSchedModel(OS);
OS << "\n";
- auto [NumProcs, SubTypeStrTabSize] = cpuKeyValues(OS, FeatureMap);
+ auto [NumProcs, NumAliases, SubTypeStrTabSize] = cpuKeyValues(OS, FeatureMap);
Res.NumProcs = NumProcs;
+ Res.NumAliases = NumAliases;
Res.SubTypeStrTabSize = SubTypeStrTabSize;
OS << "\n";
@@ -2145,9 +2184,11 @@ SubtargetEmitter::emitMCDesc(raw_ostream &OS, const FeatureMapTy &FeatureMap) {
else
OS << "{}, ";
if (Res.NumProcs)
- OS << Target << "SubTypeKVStorage.SubTypes, " << Target << "SchedModels, ";
+ OS << Target << "SubTypeKVStorage.SubTypes, "
+ << "ArrayRef(" << Target << "SubTypeKVStorage.Aliases).take_front("
+ << Res.NumAliases << "), " << Target << "SchedModels, ";
else
- OS << "{}, nullptr, ";
+ OS << "{}, {}, nullptr, ";
OS << '\n';
OS.indent(22);
OS << Target << "WriteProcResTable, " << Target << "WriteLatencyTable, "
@@ -2249,8 +2290,8 @@ void SubtargetEmitter::emitCtor(raw_ostream &OS, MCDescInfo DescInfo) {
<< Target << "FeatureKVStorage;\n";
}
OS << "extern const llvm::SubtargetSubTypeKVStorage<" << DescInfo.NumProcs
- << ", " << DescInfo.SubTypeStrTabSize << "> " << Target
- << "SubTypeKVStorage;\n";
+ << ", " << DescInfo.NumAliases << ", " << DescInfo.SubTypeStrTabSize
+ << "> " << Target << "SubTypeKVStorage;\n";
OS << "extern const llvm::MCSchedModel " << Target << "SchedModels[];\n";
OS << "extern const llvm::MCWriteProcResEntry " << Target
<< "WriteProcResTable[];\n";
@@ -2276,10 +2317,11 @@ void SubtargetEmitter::emitCtor(raw_ostream &OS, MCDescInfo DescInfo) {
else
OS << "{}, ";
if (DescInfo.NumProcs) {
- OS << "ArrayRef(" << Target << "SubTypeKVStorage.SubTypes), " << Target
- << "SchedModels, ";
+ OS << "ArrayRef(" << Target << "SubTypeKVStorage.SubTypes), "
+ << "ArrayRef(" << Target << "SubTypeKVStorage.Aliases).take_front("
+ << DescInfo.NumAliases << "), " << Target << "SchedModels, ";
} else {
- OS << "{}, nullptr, ";
+ OS << "{}, {}, nullptr, ";
}
OS << '\n';
OS.indent(24);
>From a6d9e7e1c861ffb7655e27f0bba9c309597c2431 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Sat, 25 Jul 2026 08:25:26 +0200
Subject: [PATCH 2/2] sort
---
llvm/test/TableGen/ProcessorAlias.td | 3 ++-
llvm/utils/TableGen/SubtargetEmitter.cpp | 13 ++++++++++---
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/llvm/test/TableGen/ProcessorAlias.td b/llvm/test/TableGen/ProcessorAlias.td
index 6e3f970f0d425..bfcff64dfde95 100644
--- a/llvm/test/TableGen/ProcessorAlias.td
+++ b/llvm/test/TableGen/ProcessorAlias.td
@@ -28,4 +28,5 @@ def : ProcessorAlias<"zzz-of-a", "cpu-a">;
// to subtype index 0 (cpu-a).
// CHECK: { sizeof(SubtargetSubTypeAliasKV) * 2 + {{[0-9]+}}, 0 },
// CHECK-NEXT: { sizeof(SubtargetSubTypeAliasKV) * 1 + {{[0-9]+}}, 0 },
-// CHECK: "\000cpu-a\000cpu-b\000alias-of-a\000zzz-of-a\000"
+// The string blob is sorted, independent of either table's order.
+// CHECK: "\000alias-of-a\000cpu-a\000cpu-b\000zzz-of-a\000"
diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp
index 93b5eb2b3d985..226f8068626da 100644
--- a/llvm/utils/TableGen/SubtargetEmitter.cpp
+++ b/llvm/utils/TableGen/SubtargetEmitter.cpp
@@ -337,11 +337,18 @@ SubtargetEmitter::cpuKeyValues(raw_ostream &OS,
return LHS.Name < RHS.Name;
});
- StringToOffsetTable StrTab;
+ // Sort all names together so the emitted string blob is sorted.
+ SmallVector<StringRef> Names;
+ Names.reserve(ProcessorList.size() + AliasEntries.size());
for (const Record *Processor : ProcessorList)
- StrTab.GetOrAddStringOffset(Processor->getValueAsString("Name"));
+ Names.push_back(Processor->getValueAsString("Name"));
for (const AliasEntry &Entry : AliasEntries)
- StrTab.GetOrAddStringOffset(Entry.Name);
+ Names.push_back(Entry.Name);
+ llvm::sort(Names);
+
+ StringToOffsetTable StrTab;
+ for (StringRef Name : Names)
+ StrTab.GetOrAddStringOffset(Name);
// Note that unlike `FeatureKeyValues`, here we do not need to check for
// duplicate processors, since that is already done when the SubtargetEmitter
More information about the llvm-branch-commits
mailing list