[llvm] [AArch64][llvm] Generate asm parser extension map from TableGen (NFC) (PR #191045)
Jonathan Thackray via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 29 06:23:34 PDT 2026
https://github.com/jthackray updated https://github.com/llvm/llvm-project/pull/191045
>From 150f39fe8a38669b255da3b580bac61ea6e75141 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Fri, 3 Apr 2026 01:47:50 +0100
Subject: [PATCH 1/2] [AArch64][llvm] Generate asm parser extension map from
TableGen (NFC)
Modify ARMTargetDefEmitter to emit the assembly parser `ExtensionMap[]`
and replace the hand-written table in AArch64AsmParser.cpp with the
generated one.
Keep the assembly parser-only quirks in the emitter: the directive
denylist, the legacy primary spellings for `mte` and `compnum`, and the
extra bits needed for the `sve2-*` shorthand extensions.
This removes the duplicate manual table while preserving existing
directive parsing and required-feature diagnostics.
---
.../AArch64/AsmParser/AArch64AsmParser.cpp | 142 +-----------------
.../TableGen/Basic/ARMTargetDefEmitter.cpp | 97 ++++++++++++
2 files changed, 102 insertions(+), 137 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 6a6b73b8a4c88..dddde9a67967e 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -3827,140 +3827,8 @@ AArch64AsmParser::tryParseOptionalShiftExtend(OperandVector &Operands) {
return ParseStatus::Success;
}
-static const struct Extension {
- const char *Name;
- const FeatureBitset Features;
-} ExtensionMap[] = {
- {"crc", {AArch64::FeatureCRC}},
- {"sm4", {AArch64::FeatureSM4}},
- {"sha3", {AArch64::FeatureSHA3}},
- {"sha2", {AArch64::FeatureSHA2}},
- {"aes", {AArch64::FeatureAES}},
- {"crypto", {AArch64::FeatureCrypto}},
- {"fp", {AArch64::FeatureFPARMv8}},
- {"simd", {AArch64::FeatureNEON}},
- {"ras", {AArch64::FeatureRAS}},
- {"rasv2", {AArch64::FeatureRASv2}},
- {"lse", {AArch64::FeatureLSE}},
- {"predres", {AArch64::FeaturePredRes}},
- {"predres2", {AArch64::FeatureSPECRES2}},
- {"ccdp", {AArch64::FeatureCacheDeepPersist}},
- {"mte", {AArch64::FeatureMTE}},
- {"memtag", {AArch64::FeatureMTE}},
- {"tlb-rmi", {AArch64::FeatureTLB_RMI}},
- {"pan", {AArch64::FeaturePAN}},
- {"pan-rwv", {AArch64::FeaturePAN_RWV}},
- {"ccpp", {AArch64::FeatureCCPP}},
- {"rcpc", {AArch64::FeatureRCPC}},
- {"rng", {AArch64::FeatureRandGen}},
- {"sve", {AArch64::FeatureSVE}},
- {"sve-b16b16", {AArch64::FeatureSVEB16B16}},
- {"sve2", {AArch64::FeatureSVE2}},
- {"sve-aes", {AArch64::FeatureSVEAES}},
- {"sve2-aes", {AArch64::FeatureAliasSVE2AES, AArch64::FeatureSVEAES}},
- {"sve-sm4", {AArch64::FeatureSVESM4}},
- {"sve2-sm4", {AArch64::FeatureAliasSVE2SM4, AArch64::FeatureSVESM4}},
- {"sve-sha3", {AArch64::FeatureSVESHA3}},
- {"sve2-sha3", {AArch64::FeatureAliasSVE2SHA3, AArch64::FeatureSVESHA3}},
- {"sve-bitperm", {AArch64::FeatureSVEBitPerm}},
- {"sve2-bitperm",
- {AArch64::FeatureAliasSVE2BitPerm, AArch64::FeatureSVEBitPerm,
- AArch64::FeatureSVE2}},
- {"sve2p1", {AArch64::FeatureSVE2p1}},
- {"ls64", {AArch64::FeatureLS64}},
- {"xs", {AArch64::FeatureXS}},
- {"pauth", {AArch64::FeaturePAuth}},
- {"flagm", {AArch64::FeatureFlagM}},
- {"rme", {AArch64::FeatureRME}},
- {"sme", {AArch64::FeatureSME}},
- {"sme-f64f64", {AArch64::FeatureSMEF64F64}},
- {"sme-f16f16", {AArch64::FeatureSMEF16F16}},
- {"sme-i16i64", {AArch64::FeatureSMEI16I64}},
- {"sme2", {AArch64::FeatureSME2}},
- {"sme2p1", {AArch64::FeatureSME2p1}},
- {"sme-b16b16", {AArch64::FeatureSMEB16B16}},
- {"hbc", {AArch64::FeatureHBC}},
- {"mops", {AArch64::FeatureMOPS}},
- {"mec", {AArch64::FeatureMEC}},
- {"the", {AArch64::FeatureTHE}},
- {"d128", {AArch64::FeatureD128}},
- {"lse128", {AArch64::FeatureLSE128}},
- {"ite", {AArch64::FeatureITE}},
- {"cssc", {AArch64::FeatureCSSC}},
- {"rcpc3", {AArch64::FeatureRCPC3}},
- {"gcs", {AArch64::FeatureGCS}},
- {"bf16", {AArch64::FeatureBF16}},
- {"compnum", {AArch64::FeatureComplxNum}},
- {"dotprod", {AArch64::FeatureDotProd}},
- {"f32mm", {AArch64::FeatureMatMulFP32}},
- {"f64mm", {AArch64::FeatureMatMulFP64}},
- {"fp16", {AArch64::FeatureFullFP16}},
- {"fp16fml", {AArch64::FeatureFP16FML}},
- {"i8mm", {AArch64::FeatureMatMulInt8}},
- {"lor", {AArch64::FeatureLOR}},
- {"profile", {AArch64::FeatureSPE}},
- // "rdma" is the name documented by binutils for the feature, but
- // binutils also accepts incomplete prefixes of features, so "rdm"
- // works too. Support both spellings here.
- {"rdm", {AArch64::FeatureRDM}},
- {"rdma", {AArch64::FeatureRDM}},
- {"sb", {AArch64::FeatureSB}},
- {"ssbs", {AArch64::FeatureSSBS}},
- {"fp8", {AArch64::FeatureFP8}},
- {"faminmax", {AArch64::FeatureFAMINMAX}},
- {"fp8fma", {AArch64::FeatureFP8FMA}},
- {"ssve-fp8fma", {AArch64::FeatureSSVE_FP8FMA}},
- {"fp8dot2", {AArch64::FeatureFP8DOT2}},
- {"ssve-fp8dot2", {AArch64::FeatureSSVE_FP8DOT2}},
- {"fp8dot4", {AArch64::FeatureFP8DOT4}},
- {"ssve-fp8dot4", {AArch64::FeatureSSVE_FP8DOT4}},
- {"lut", {AArch64::FeatureLUT}},
- {"sme-lutv2", {AArch64::FeatureSME_LUTv2}},
- {"sme-f8f16", {AArch64::FeatureSMEF8F16}},
- {"sme-f8f32", {AArch64::FeatureSMEF8F32}},
- {"sme-fa64", {AArch64::FeatureSMEFA64}},
- {"cpa", {AArch64::FeatureCPA}},
- {"tlbiw", {AArch64::FeatureTLBIW}},
- {"pops", {AArch64::FeaturePoPS}},
- {"cmpbr", {AArch64::FeatureCMPBR}},
- {"f8f32mm", {AArch64::FeatureF8F32MM}},
- {"f8f16mm", {AArch64::FeatureF8F16MM}},
- {"fprcvt", {AArch64::FeatureFPRCVT}},
- {"lsfe", {AArch64::FeatureLSFE}},
- {"sme2p2", {AArch64::FeatureSME2p2}},
- {"ssve-aes", {AArch64::FeatureSSVE_AES}},
- {"sve2p2", {AArch64::FeatureSVE2p2}},
- {"sve-aes2", {AArch64::FeatureSVEAES2}},
- {"sve-bfscale", {AArch64::FeatureSVEBFSCALE}},
- {"sve-f16f32mm", {AArch64::FeatureSVE_F16F32MM}},
- {"lsui", {AArch64::FeatureLSUI}},
- {"occmo", {AArch64::FeatureOCCMO}},
- {"ssve-bitperm", {AArch64::FeatureSSVE_BitPerm}},
- {"sme-mop4", {AArch64::FeatureSME_MOP4}},
- {"sme-tmop", {AArch64::FeatureSME_TMOP}},
- {"lscp", {AArch64::FeatureLSCP}},
- {"tlbid", {AArch64::FeatureTLBID}},
- {"mtetc", {AArch64::FeatureMTETC}},
- {"gcie", {AArch64::FeatureGCIE}},
- {"sme2p3", {AArch64::FeatureSME2p3}},
- {"sve2p3", {AArch64::FeatureSVE2p3}},
- {"sve-b16mm", {AArch64::FeatureSVE_B16MM}},
- {"f16mm", {AArch64::FeatureF16MM}},
- {"f16f32dot", {AArch64::FeatureF16F32DOT}},
- {"f16f32mm", {AArch64::FeatureF16F32MM}},
- {"mops-go", {AArch64::FeatureMOPS_GO}},
- {"poe2", {AArch64::FeatureS1POE2}},
- {"tev", {AArch64::FeatureTEV}},
- {"btie", {AArch64::FeatureBTIE}},
- {"dit", {AArch64::FeatureDIT}},
- {"brbe", {AArch64::FeatureBRBE}},
- {"bti", {AArch64::FeatureBranchTargetId}},
- {"fcma", {AArch64::FeatureComplxNum}},
- {"jscvt", {AArch64::FeatureJS}},
- {"pauth-lr", {AArch64::FeaturePAuthLR}},
- {"ssve-fexpa", {AArch64::FeatureSSVE_FEXPA}},
- {"wfxt", {AArch64::FeatureWFxT}},
-};
+#define EMIT_ASM_PARSER_EXTENSIONS
+#include "llvm/TargetParser/AArch64TargetParserDef.inc"
static void setRequiredFeatureString(FeatureBitset FBS, std::string &Str) {
if (FBS[AArch64::HasV8_0aOps])
@@ -7466,7 +7334,7 @@ bool AArch64AsmParser::parseDirectiveArch(SMLoc L) {
bool EnableFeature = !Name.consume_front_insensitive("no");
auto It = llvm::find_if(ExtensionMap, [&Name](const auto &Extension) {
- return Extension.Name == Name;
+ return Extension.Name == Name && Extension.AllowInDirective;
});
if (It == std::end(ExtensionMap))
@@ -7503,7 +7371,7 @@ bool AArch64AsmParser::parseDirectiveArchExtension(SMLoc L) {
}
auto It = llvm::find_if(ExtensionMap, [&Name](const auto &Extension) {
- return Extension.Name == Name;
+ return Extension.Name == Name && Extension.AllowInDirective;
});
if (It == std::end(ExtensionMap))
@@ -7555,7 +7423,7 @@ bool AArch64AsmParser::parseDirectiveCPU(SMLoc L) {
bool EnableFeature = !Name.consume_front_insensitive("no");
auto It = llvm::find_if(ExtensionMap, [&Name](const auto &Extension) {
- return Extension.Name == Name;
+ return Extension.Name == Name && Extension.AllowInDirective;
});
if (It == std::end(ExtensionMap))
diff --git a/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp b/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp
index a18fed082207f..b361186a7e4b8 100644
--- a/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp
@@ -14,6 +14,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/TableGen/Error.h"
@@ -53,6 +54,66 @@ static void checkFeatureTree(const Record *Root) {
}
}
+static bool allowInAArch64AsmParserDirective(const Record *Rec) {
+ // The generated asm parser extension table is used for both directive lookup
+ // and required-feature diagnostics. Some extensions still need to appear in
+ // diagnostics, but must not be accepted by .arch/.arch_extension/.cpu.
+ return StringSwitch<bool>(Rec->getName())
+ .Case("FeaturePerfMon", false)
+ .Case("FeatureSpecRestrict", false)
+ .Case("FeatureVH", false)
+ .Case("FeatureEnhancedCounterVirtualization", false)
+ .Case("FeaturePsUAO", false)
+ .Case("FeatureFPAC", false)
+ .Case("FeatureCCIDX", false)
+ .Case("FeatureNV", false)
+ .Case("FeatureLSE2", false)
+ .Case("FeatureMPAM", false)
+ .Case("FeatureTRACEV8_4", false)
+ .Case("FeatureAM", false)
+ .Case("FeatureSEL2", false)
+ .Case("FeatureRCPC_IMMO", false)
+ .Case("FeatureAltFPCmp", false)
+ .Case("FeatureFRInt3264", false)
+ .Case("FeatureAMVS", false)
+ .Case("FeatureFineGrainedTraps", false)
+ .Case("FeatureHCX", false)
+ .Case("FeatureSPE_EEF", false)
+ .Case("FeatureNMI", false)
+ .Case("FeatureCLRBHB", false)
+ .Case("FeaturePRFM_SLC", false)
+ .Case("FeatureTRBE", false)
+ .Case("FeatureETE", false)
+ .Case("FeatureCHK", false)
+ .Default(true);
+}
+
+static StringRef getAArch64AsmParserPrimaryName(const Record *Rec) {
+ // Preserve legacy GNU-style spellings where the asm parser intentionally
+ // differs from the target parser's user-visible extension name.
+ return StringSwitch<StringRef>(Rec->getName())
+ .Case("FeatureComplxNum", "compnum")
+ .Case("FeatureMTE", "mte")
+ .Default("");
+}
+
+static ArrayRef<StringRef> getAArch64AsmParserExtraFeatures(const Record *Rec) {
+ // These shorthands historically toggled extra feature bits in the
+ // hand-written asm parser extension table, so keep the same behavior here.
+ static constexpr StringRef SVE2AES[] = {"FeatureSVEAES"};
+ static constexpr StringRef SVE2SM4[] = {"FeatureSVESM4"};
+ static constexpr StringRef SVE2SHA3[] = {"FeatureSVESHA3"};
+ static constexpr StringRef SVE2BitPerm[] = {"FeatureSVEBitPerm",
+ "FeatureSVE2"};
+
+ return StringSwitch<ArrayRef<StringRef>>(Rec->getName())
+ .Case("FeatureAliasSVE2AES", ArrayRef(SVE2AES))
+ .Case("FeatureAliasSVE2SM4", ArrayRef(SVE2SM4))
+ .Case("FeatureAliasSVE2SHA3", ArrayRef(SVE2SHA3))
+ .Case("FeatureAliasSVE2BitPerm", ArrayRef(SVE2BitPerm))
+ .Default({});
+}
+
static void emitARMTargetDef(const RecordKeeper &RK, raw_ostream &OS) {
OS << "// Autogenerated by ARMTargetDefEmitter.cpp\n\n";
@@ -150,6 +211,42 @@ static void emitARMTargetDef(const RecordKeeper &RK, raw_ostream &OS) {
<< "#endif // EMIT_EXTENSIONS\n"
<< "\n";
+ OS << "#ifdef EMIT_ASM_PARSER_EXTENSIONS\n"
+ << "static const struct Extension {\n"
+ << " const char *Name;\n"
+ << " const FeatureBitset Features;\n"
+ << " bool AllowInDirective;\n"
+ << "} ExtensionMap[] = {\n";
+ for (const Record *Rec : SortedExtensions) {
+ bool AllowInDirective = allowInAArch64AsmParserDirective(Rec);
+ auto EmitEntry = [&](StringRef Name) {
+ if (Name.empty())
+ return;
+ OS << " {\"" << Name << "\", {AArch64::" << Rec->getName();
+ for (StringRef Extra : getAArch64AsmParserExtraFeatures(Rec))
+ OS << ", AArch64::" << Extra;
+ OS << "}, " << (AllowInDirective ? "true" : "false") << "},\n";
+ };
+
+ StringRef PrimaryName = getAArch64AsmParserPrimaryName(Rec);
+ if (PrimaryName.empty())
+ PrimaryName = Rec->getValueAsString("UserVisibleName");
+ if (PrimaryName.empty())
+ PrimaryName = Rec->getValueAsString("Name");
+ EmitEntry(PrimaryName);
+
+ if (auto Name = Rec->getValueAsString("UserVisibleName");
+ !Name.empty() && Name != PrimaryName)
+ EmitEntry(Name);
+ if (auto Alias = Rec->getValueAsString("UserVisibleAlias");
+ !Alias.empty() && Alias != PrimaryName)
+ EmitEntry(Alias);
+ }
+ OS << "};\n"
+ << "#undef EMIT_ASM_PARSER_EXTENSIONS\n"
+ << "#endif // EMIT_ASM_PARSER_EXTENSIONS\n"
+ << "\n";
+
// Emit FMV information
auto FMVExts = RK.getAllDerivedDefinitionsIfDefined("FMVExtension");
OS << "#ifdef EMIT_FMV_INFO\n"
>From 97d6d0b1f4ac86e906eb4bc32df8a68528b895da Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Wed, 29 Apr 2026 14:10:51 +0100
Subject: [PATCH 2/2] fixup! Use SmallDenseSet<> for quick lookup
---
.../TableGen/Basic/ARMTargetDefEmitter.cpp | 58 ++++++++++---------
1 file changed, 30 insertions(+), 28 deletions(-)
diff --git a/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp b/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp
index b361186a7e4b8..1773971376c40 100644
--- a/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Format.h"
@@ -58,34 +59,35 @@ static bool allowInAArch64AsmParserDirective(const Record *Rec) {
// The generated asm parser extension table is used for both directive lookup
// and required-feature diagnostics. Some extensions still need to appear in
// diagnostics, but must not be accepted by .arch/.arch_extension/.cpu.
- return StringSwitch<bool>(Rec->getName())
- .Case("FeaturePerfMon", false)
- .Case("FeatureSpecRestrict", false)
- .Case("FeatureVH", false)
- .Case("FeatureEnhancedCounterVirtualization", false)
- .Case("FeaturePsUAO", false)
- .Case("FeatureFPAC", false)
- .Case("FeatureCCIDX", false)
- .Case("FeatureNV", false)
- .Case("FeatureLSE2", false)
- .Case("FeatureMPAM", false)
- .Case("FeatureTRACEV8_4", false)
- .Case("FeatureAM", false)
- .Case("FeatureSEL2", false)
- .Case("FeatureRCPC_IMMO", false)
- .Case("FeatureAltFPCmp", false)
- .Case("FeatureFRInt3264", false)
- .Case("FeatureAMVS", false)
- .Case("FeatureFineGrainedTraps", false)
- .Case("FeatureHCX", false)
- .Case("FeatureSPE_EEF", false)
- .Case("FeatureNMI", false)
- .Case("FeatureCLRBHB", false)
- .Case("FeaturePRFM_SLC", false)
- .Case("FeatureTRBE", false)
- .Case("FeatureETE", false)
- .Case("FeatureCHK", false)
- .Default(true);
+ static const SmallDenseSet<StringRef, 32> DisallowedExtensionNames = {
+ "FeatureAltFPCmp",
+ "FeatureAM",
+ "FeatureAMVS",
+ "FeatureCCIDX",
+ "FeatureCHK",
+ "FeatureCLRBHB",
+ "FeatureEnhancedCounterVirtualization",
+ "FeatureETE",
+ "FeatureFineGrainedTraps",
+ "FeatureFPAC",
+ "FeatureFRInt3264",
+ "FeatureHCX",
+ "FeatureLSE2",
+ "FeatureMPAM",
+ "FeatureNMI",
+ "FeatureNV",
+ "FeaturePerfMon",
+ "FeaturePRFM_SLC",
+ "FeaturePsUAO",
+ "FeatureRCPC_IMMO",
+ "FeatureSEL2",
+ "FeatureSPE_EEF",
+ "FeatureSpecRestrict",
+ "FeatureTRACEV8_4",
+ "FeatureTRBE",
+ "FeatureVH",
+ };
+ return !DisallowedExtensionNames.contains(Rec->getName());
}
static StringRef getAArch64AsmParserPrimaryName(const Record *Rec) {
More information about the llvm-commits
mailing list