[llvm] TableGen: Add first class support for processor aliases (PR #211775)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 24 05:03:22 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-mc
Author: Matt Arsenault (arsenm)
<details>
<summary>Changes</summary>
Previously isCPUStringValid was virtual so TableGen could emit an
AArch64 specific hack for recognizing cpu aliases. Teach tablegen
about aliases, and insert each alias into the CPU subtype table as its
own entry (sorted by name, carrying the canonical processor's features
and scheduling model).
There is further opportunity for code sharing improvements. AArch64's
aliases are consumed by ARMTargetDefEmitter to emit a custom inc file
in TargetParser which should be universalized.
Co-authored-by: Claude (Claude-Opus-4.8) <noreply@<!-- -->anthropic.com>
---
Full diff: https://github.com/llvm/llvm-project/pull/211775.diff
6 Files Affected:
- (modified) llvm/include/llvm/MC/MCSubtargetInfo.h (+1-1)
- (modified) llvm/include/llvm/Target/Target.td (+7)
- (modified) llvm/lib/Target/AArch64/AArch64Processors.td (-6)
- (added) llvm/test/TableGen/ProcessorAlias.td (+24)
- (added) llvm/test/TableGen/ProcessorAliasErrors.td (+34)
- (modified) llvm/utils/TableGen/SubtargetEmitter.cpp (+54-43)
``````````diff
diff --git a/llvm/include/llvm/MC/MCSubtargetInfo.h b/llvm/include/llvm/MC/MCSubtargetInfo.h
index 2d1053b2113c0..e8de24cee5831 100644
--- a/llvm/include/llvm/MC/MCSubtargetInfo.h
+++ b/llvm/include/llvm/MC/MCSubtargetInfo.h
@@ -274,7 +274,7 @@ class LLVM_ABI MCSubtargetInfo {
}
/// Check whether the CPU string is valid.
- virtual bool isCPUStringValid(StringRef CPU) const {
+ bool isCPUStringValid(StringRef CPU) const {
auto Found = llvm::lower_bound(ProcDesc, CPU);
return Found != ProcDesc.end() && StringRef(Found->key()) == CPU;
}
diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index cb97ab5d1bae4..a8f3ec628121e 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -2136,6 +2136,13 @@ class ProcessorModel<string n, SchedMachineModel m, list<SubtargetFeature> f,
let SchedModel = m;
}
+// ProcessorAlias - Defines an alternate name 'n' for the processor 'alias',
+// resolving to the same subtarget features and scheduling model.
+class ProcessorAlias<string n, string alias> {
+ string Name = n;
+ string Alias = alias;
+}
+
//===----------------------------------------------------------------------===//
// InstrMapping - This class is used to create mapping tables to relate
// instructions with each other based on the values specified in RowFields,
diff --git a/llvm/lib/Target/AArch64/AArch64Processors.td b/llvm/lib/Target/AArch64/AArch64Processors.td
index 550c72d2b1ad9..c96ef7381cb6f 100644
--- a/llvm/lib/Target/AArch64/AArch64Processors.td
+++ b/llvm/lib/Target/AArch64/AArch64Processors.td
@@ -1274,12 +1274,6 @@ def ProcessorFeatures {
list<SubtargetFeature> Generic = [FeatureFPARMv8, FeatureNEON, FeatureETE];
}
-// Define an alternative name for a given Processor.
-class ProcessorAlias<string n, string alias> {
- string Name = n;
- string Alias = alias;
-}
-
// A note on scheduling models - we do not have exact models for each core and
// attempt to use the "best equivalent" that we have for those that are
// missing. -mcpu=generic uses a cortex-a510 model to get good scheduling
diff --git a/llvm/test/TableGen/ProcessorAlias.td b/llvm/test/TableGen/ProcessorAlias.td
new file mode 100644
index 0000000000000..c70c7dd58f8e4
--- /dev/null
+++ b/llvm/test/TableGen/ProcessorAlias.td
@@ -0,0 +1,24 @@
+// 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.
+
+include "llvm/Target/Target.td"
+
+def MyTarget : Target;
+
+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.
+def : ProcessorAlias<"alias-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"
diff --git a/llvm/test/TableGen/ProcessorAliasErrors.td b/llvm/test/TableGen/ProcessorAliasErrors.td
new file mode 100644
index 0000000000000..356c1419640a4
--- /dev/null
+++ b/llvm/test/TableGen/ProcessorAliasErrors.td
@@ -0,0 +1,34 @@
+// RUN: rm -rf %t && split-file %s %t
+// RUN: not llvm-tblgen -gen-subtarget -I %p/../../include %t/non-existent.td 2>&1 \
+// RUN: | FileCheck %t/non-existent.td -DFILE=%t/non-existent.td --implicit-check-not="error:"
+// RUN: not llvm-tblgen -gen-subtarget -I %p/../../include %t/dup-processor.td 2>&1 \
+// RUN: | FileCheck %t/dup-processor.td -DFILE=%t/dup-processor.td --implicit-check-not="error:"
+// RUN: not llvm-tblgen -gen-subtarget -I %p/../../include %t/dup-alias.td 2>&1 \
+// RUN: | FileCheck %t/dup-alias.td -DFILE=%t/dup-alias.td --implicit-check-not="error:"
+
+// Verify the ProcessorAlias validation performed by the subtarget emitter.
+
+//--- non-existent.td
+include "llvm/Target/Target.td"
+def MyTarget : Target;
+def ProcA : ProcessorModel<"cpu-a", NoSchedModel, []>;
+// An alias must resolve to an existing processor.
+// CHECK: [[FILE]]:[[#@LINE+1]]:1: error: Alias 'bad-alias' references a non-existent Processor 'cpu-missing'
+def : ProcessorAlias<"bad-alias", "cpu-missing">;
+
+//--- dup-processor.td
+include "llvm/Target/Target.td"
+def MyTarget : Target;
+def ProcA : ProcessorModel<"cpu-a", NoSchedModel, []>;
+// An alias name must not collide with a real processor.
+// CHECK: [[FILE]]:[[#@LINE+1]]:1: error: Alias 'cpu-a' duplicates an existing Processor
+def : ProcessorAlias<"cpu-a", "cpu-a">;
+
+//--- dup-alias.td
+include "llvm/Target/Target.td"
+def MyTarget : Target;
+def ProcA : ProcessorModel<"cpu-a", NoSchedModel, []>;
+def DupA : ProcessorAlias<"dup", "cpu-a">;
+// Two aliases must not share the same name.
+// CHECK: [[FILE]]:[[#@LINE+1]]:5: error: Alias 'dup' duplicates an existing alias
+def DupB : ProcessorAlias<"dup", "cpu-a">;
diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp
index ae41feda46d65..6b8fa4039cd65 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"
@@ -286,49 +287,79 @@ static void checkDuplicateCPUFeatures(StringRef CPUName,
std::pair<unsigned, unsigned>
SubtargetEmitter::cpuKeyValues(raw_ostream &OS,
const FeatureMapTy &FeatureMap) {
- // Gather and sort processor information
std::vector<const Record *> ProcessorList =
Records.getAllDerivedDefinitions("Processor");
- llvm::sort(ProcessorList, LessRecordFieldName());
- // In the string table, include the aliases as well.
+ StringMap<const Record *> ProcessorMap;
+ for (const Record *Processor : ProcessorList)
+ ProcessorMap[Processor->getValueAsString("Name")] = Processor;
+
+ // Each alias is emitted as an entry pointing at its canonical processor, so
+ // generic CPU-string handling (e.g. `isCPUStringValid`) accepts alias names.
+ struct SubTypeEntry {
+ StringRef Name;
+ const Record *Proc;
+ };
+ std::vector<SubTypeEntry> SubTypeEntries;
+
std::vector<const Record *> ProcessorAliasList =
Records.getAllDerivedDefinitionsIfDefined("ProcessorAlias");
- SmallVector<StringRef> Names;
- Names.reserve(ProcessorList.size() + ProcessorAliasList.size());
+ SubTypeEntries.reserve(ProcessorList.size() + ProcessorAliasList.size());
+
for (const Record *Processor : ProcessorList)
- Names.push_back(Processor->getValueAsString("Name"));
- for (const Record *Rec : ProcessorAliasList)
- Names.push_back(Rec->getValueAsString("Name"));
- llvm::sort(Names);
+ SubTypeEntries.push_back({Processor->getValueAsString("Name"), Processor});
+
+ 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())
+ PrintFatalError(Rec, "Alias '" + Name +
+ "' references a non-existent Processor '" +
+ Alias + "'");
+ if (ProcessorMap.contains(Name))
+ PrintFatalError(Rec,
+ "Alias '" + Name + "' duplicates an existing Processor");
+ if (!AliasNames.insert(Name).second)
+ PrintFatalError(Rec, "Alias '" + Name + "' duplicates an existing alias");
+ SubTypeEntries.push_back({Name, It->second});
+ }
+
+ // The table must stay sorted by key for the binary search in the lookups.
+ llvm::sort(SubTypeEntries,
+ [](const SubTypeEntry &LHS, const SubTypeEntry &RHS) {
+ return LHS.Name < RHS.Name;
+ });
StringToOffsetTable StrTab;
- for (StringRef Name : Names)
- StrTab.GetOrAddStringOffset(Name);
+ for (const SubTypeEntry &Entry : SubTypeEntries)
+ 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 = SubTypeEntries.size();
+
// Begin processor table.
OS << "// Sorted (by key) array of values for CPU subtype.\n"
- << "extern const llvm::SubtargetSubTypeKVStorage< " << ProcessorList.size()
- << ", " << (StrTab.size() + 1) << "> " << Target
- << "SubTypeKVStorage = {\n {\n";
+ << "extern const llvm::SubtargetSubTypeKVStorage< " << Total << ", "
+ << (StrTab.size() + 1) << "> " << Target << "SubTypeKVStorage = {\n {\n";
- for (const auto &[Idx, Processor] : enumerate(ProcessorList)) {
- StringRef Name = Processor->getValueAsString("Name");
+ for (const auto &[Idx, Entry] : enumerate(SubTypeEntries)) {
+ const Record *Processor = Entry.Proc;
ConstRecVec FeatureList = Processor->getValueAsListOfDefs("Features");
ConstRecVec TuneFeatureList =
Processor->getValueAsListOfDefs("TuneFeatures");
- // Warn the user if there are duplicate processor features or tune
- // features.
- checkDuplicateCPUFeatures(Name, FeatureList, TuneFeatureList);
+ // Aliases share the canonical processor's already-checked feature lists.
+ if (Entry.Name == Processor->getValueAsString("Name"))
+ checkDuplicateCPUFeatures(Entry.Name, FeatureList, TuneFeatureList);
- OS << " { sizeof(SubtargetSubTypeKV) * " << (ProcessorList.size() - Idx)
- << " + " << StrTab.GetOrAddStringOffset(Name) << ", ";
+ OS << " { sizeof(SubtargetSubTypeKV) * " << (Total - Idx) << " + "
+ << StrTab.GetOrAddStringOffset(Entry.Name) << ", ";
printFeatureMask(OS, FeatureList, FeatureMap);
OS << ", ";
@@ -344,7 +375,7 @@ SubtargetEmitter::cpuKeyValues(raw_ostream &OS,
// End processor table.
OS << "};\n";
- return {ProcessorList.size(), StrTab.size() + 1};
+ return {Total, StrTab.size() + 1};
}
//
@@ -1990,10 +2021,6 @@ void SubtargetEmitter::parseFeaturesFunction(raw_ostream &OS) {
return;
}
- if (Target == "AArch64")
- OS << " CPU = AArch64::resolveCPUAlias(CPU);\n"
- << " TuneCPU = AArch64::resolveCPUAlias(TuneCPU);\n";
-
OS << " InitMCProcessorInfo(CPU, TuneCPU, FS);\n"
<< " const FeatureBitset &Bits = getFeatureBits();\n";
@@ -2068,11 +2095,6 @@ void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) {
OS << " unsigned getHwMode(enum HwModeType type = HwMode_Default) const "
"final;\n";
}
- if (Target == "AArch64")
- OS << " bool isCPUStringValid(StringRef CPU) const final {\n"
- << " CPU = AArch64::resolveCPUAlias(CPU);\n"
- << " return MCSubtargetInfo::isCPUStringValid(CPU);\n"
- << " }\n";
OS << "};\n";
emitHwModeCheck(Target + "GenMCSubtargetInfo", OS, /*IsMC=*/true);
}
@@ -2105,8 +2127,6 @@ FeatureMapTy SubtargetEmitter::emitEnums(raw_ostream &OS) {
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");
MCDescInfo Res;
@@ -2127,9 +2147,6 @@ SubtargetEmitter::emitMCDesc(raw_ostream &OS, const FeatureMapTy &FeatureMap) {
OS << "\nstatic inline MCSubtargetInfo *create" << Target
<< "MCSubtargetInfoImpl("
<< "const Triple &TT, StringRef CPU, StringRef TuneCPU, StringRef FS) {\n";
- if (Target == "AArch64")
- OS << " CPU = AArch64::resolveCPUAlias(CPU);\n"
- << " TuneCPU = AArch64::resolveCPUAlias(TuneCPU);\n";
OS << " return new " << Target
<< "GenMCSubtargetInfo(TT, CPU, TuneCPU, FS, ";
OS << "StringTable(" << Target << "SubTypeKVStorage.Strings), ";
@@ -2163,8 +2180,6 @@ void SubtargetEmitter::emitTargetDesc(raw_ostream &OS) {
OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n";
OS << "#include \"llvm/Support/Debug.h\"\n";
OS << "#include \"llvm/Support/raw_ostream.h\"\n\n";
- if (Target == "AArch64")
- OS << "#include \"llvm/TargetParser/AArch64TargetParser.h\"\n\n";
parseFeaturesFunction(OS);
}
@@ -2264,11 +2279,7 @@ void SubtargetEmitter::emitCtor(raw_ostream &OS, MCDescInfo DescInfo) {
OS << ClassName << "::" << ClassName << "(const Triple &TT, StringRef CPU, "
<< "StringRef TuneCPU, StringRef FS)\n";
- if (Target == "AArch64")
- OS << " : TargetSubtargetInfo(TT, AArch64::resolveCPUAlias(CPU),\n"
- << " AArch64::resolveCPUAlias(TuneCPU), FS, ";
- else
- OS << " : TargetSubtargetInfo(TT, CPU, TuneCPU, FS, ";
+ OS << " : TargetSubtargetInfo(TT, CPU, TuneCPU, FS, ";
OS << "StringTable(" << Target << "SubTypeKVStorage.Strings), ";
if (DescInfo.NumFeatures)
OS << "ArrayRef(" << Target << "FeatureKVStorage.Features), ";
``````````
</details>
https://github.com/llvm/llvm-project/pull/211775
More information about the llvm-commits
mailing list