Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AArch64] Merge duplicate extension information. #92319

Closed

Conversation

labrinea
Copy link
Collaborator

@labrinea labrinea commented May 15, 2024

When we moved the extension information into tablegen in #90987, some
features (FEAT_DPB, FEAT_DPB2, FEAT_FLAGM2, FEAT_FRINTTS, FEAT_RCPC2)
were defined as FMVOnlyExtension despite already having an equivalent
SubtargetFeature in place. This patch is fusing these duplications.

Moreover my reverted attempt to decouple feature dependency expansion
(see #95056) made it evident that some features are still using the FMV
dependencies in the target attribute. FEAT_PMULL and FEAT_SSBS2 are
such examples. I have rectified those to reland the mentioned patch.

@labrinea labrinea requested review from ilinpv and tmatheson-arm May 15, 2024 21:47
@tmatheson-arm
Copy link
Contributor

I should add that I have done exactly this for +wfxt and +dit, out of necessity, but I need to go back and remove them when we have a general solution to the problem.

@labrinea labrinea requested a review from momchil-velikov May 16, 2024 10:22
@labrinea labrinea force-pushed the aarch64-merge-duplicate-features branch from f9f60fb to 0c00fc2 Compare May 17, 2024 18:38
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:AArch64 clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen labels May 17, 2024
@llvmbot
Copy link
Member

llvmbot commented May 17, 2024

@llvm/pr-subscribers-clang-driver

@llvm/pr-subscribers-clang-codegen

Author: Alexandros Lamprineas (labrinea)

Changes

When we moved the extension information into tablegen in #90987, some features (FEAT_DPB, FEAT_DPB2, FEAT_FLAGM2, FEAT_FRINTTS, FEAT_RCPC2) were defined as FMVOnlyExtension despite already having an equivalent SubtargetFeature in place. This patch is fusing these duplications.


Patch is 21.98 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/92319.diff

8 Files Affected:

  • (modified) clang/lib/Basic/Targets/AArch64.cpp (+4-4)
  • (modified) clang/lib/CodeGen/CGBuiltin.cpp (+1-1)
  • (modified) clang/lib/CodeGen/Targets/AArch64.cpp (+1-1)
  • (added) clang/test/Driver/aarch64-fmv-only-feature.c (+41)
  • (modified) llvm/include/llvm/TargetParser/AArch64TargetParser.h (+12-9)
  • (modified) llvm/lib/Target/AArch64/AArch64Features.td (+82-57)
  • (modified) llvm/lib/TargetParser/AArch64TargetParser.cpp (+12-1)
  • (modified) llvm/utils/TableGen/ARMTargetDefEmitter.cpp (+6-4)
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index 5db1ce78c657f..ec9632045fa95 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -659,7 +659,7 @@ AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts) const {
 unsigned AArch64TargetInfo::multiVersionSortPriority(StringRef Name) const {
   if (Name == "default")
     return 0;
-  if (auto Ext = llvm::AArch64::parseArchExtension(Name))
+  if (auto Ext = llvm::AArch64::parseFMVExtension(Name))
     return Ext->FmvPriority;
   return 0;
 }
@@ -670,13 +670,13 @@ unsigned AArch64TargetInfo::multiVersionFeatureCost() const {
 }
 
 bool AArch64TargetInfo::doesFeatureAffectCodeGen(StringRef Name) const {
-  if (auto Ext = llvm::AArch64::parseArchExtension(Name))
+  if (auto Ext = llvm::AArch64::parseFMVExtension(Name))
     return !Ext->DependentFeatures.empty();
   return false;
 }
 
 StringRef AArch64TargetInfo::getFeatureDependencies(StringRef Name) const {
-  if (auto Ext = llvm::AArch64::parseArchExtension(Name))
+  if (auto Ext = llvm::AArch64::parseFMVExtension(Name))
     return Ext->DependentFeatures;
   return StringRef();
 }
@@ -686,7 +686,7 @@ bool AArch64TargetInfo::validateCpuSupports(StringRef FeatureStr) const {
   llvm::SmallVector<StringRef, 8> Features;
   FeatureStr.split(Features, "+");
   for (auto &Feature : Features)
-    if (!llvm::AArch64::parseArchExtension(Feature.trim()).has_value())
+    if (!llvm::AArch64::parseFMVExtension(Feature.trim()).has_value())
       return false;
   return true;
 }
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index f9ee93049b12d..ef0337d42505f 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -14259,7 +14259,7 @@ Value *CodeGenFunction::EmitAArch64CpuSupports(const CallExpr *E) {
   ArgStr.split(Features, "+");
   for (auto &Feature : Features) {
     Feature = Feature.trim();
-    if (!llvm::AArch64::parseArchExtension(Feature))
+    if (!llvm::AArch64::parseFMVExtension(Feature))
       return Builder.getFalse();
     if (Feature != "default")
       Features.push_back(Feature);
diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp
index e32b060ebeb93..dcb517e978ca9 100644
--- a/clang/lib/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CodeGen/Targets/AArch64.cpp
@@ -973,7 +973,7 @@ void AArch64ABIInfo::appendAttributeMangling(StringRef AttrStr,
 
   llvm::SmallDenseSet<StringRef, 8> UniqueFeats;
   for (auto &Feat : Features)
-    if (auto Ext = llvm::AArch64::parseArchExtension(Feat))
+    if (auto Ext = llvm::AArch64::parseFMVExtension(Feat))
       if (UniqueFeats.insert(Ext->Name).second)
         Out << 'M' << Ext->Name;
 }
diff --git a/clang/test/Driver/aarch64-fmv-only-feature.c b/clang/test/Driver/aarch64-fmv-only-feature.c
new file mode 100644
index 0000000000000..f918b3f8fb64a
--- /dev/null
+++ b/clang/test/Driver/aarch64-fmv-only-feature.c
@@ -0,0 +1,41 @@
+// Test that features which are meaningful only for Function Multiversioning are rejected from the command line.
+
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+dgh %s 2>&1 | FileCheck %s --check-prefix=DGH
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+ebf16 %s 2>&1 | FileCheck %s --check-prefix=EBF16
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+ls64_accdata %s 2>&1 | FileCheck %s --check-prefix=LS64_ACCDATA
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+ls64_v %s 2>&1 | FileCheck %s --check-prefix=LS64_V
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+memtag2 %s 2>&1 | FileCheck %s --check-prefix=MEMTAG2
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+memtag3 %s 2>&1 | FileCheck %s --check-prefix=MEMTAG3
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+pmull %s 2>&1 | FileCheck %s --check-prefix=PMULL
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+rpres %s 2>&1 | FileCheck %s --check-prefix=RPRES
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+sha1 %s 2>&1 | FileCheck %s --check-prefix=SHA1
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+ssbs2 %s 2>&1 | FileCheck %s --check-prefix=SSBS2
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+sve-bf16 %s 2>&1 | FileCheck %s --check-prefix=SVE_BF16
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+sve-ebf16 %s 2>&1 | FileCheck %s --check-prefix=SVE_EBF16
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+sve-i8mm %s 2>&1 | FileCheck %s --check-prefix=SVE_I8MM
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+sve2-pmull128 %s 2>&1 | FileCheck %s --check-prefix=SVE2_PMULL128
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+dpb %s 2>&1 | FileCheck %s --check-prefix=DPB
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+rcpc2 %s 2>&1 | FileCheck %s --check-prefix=RCPC2
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+flagm2 %s 2>&1 | FileCheck %s --check-prefix=FLAGM2
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+frintts %s 2>&1 | FileCheck %s --check-prefix=FRINTTS
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+dpb2 %s 2>&1 | FileCheck %s --check-prefix=DPB2
+
+// DGH: error: unsupported argument 'armv8-a+dgh' to option '-march='
+// EBF16: error: unsupported argument 'armv8-a+ebf16' to option '-march='
+// LS64_ACCDATA: error: unsupported argument 'armv8-a+ls64_accdata' to option '-march='
+// LS64_V: error: unsupported argument 'armv8-a+ls64_v' to option '-march='
+// MEMTAG2: error: unsupported argument 'armv8-a+memtag2' to option '-march='
+// MEMTAG3: error: unsupported argument 'armv8-a+memtag3' to option '-march='
+// PMULL: error: unsupported argument 'armv8-a+pmull' to option '-march='
+// RPRES: error: unsupported argument 'armv8-a+rpres' to option '-march='
+// SHA1: error: unsupported argument 'armv8-a+sha1' to option '-march='
+// SSBS2: error: unsupported argument 'armv8-a+ssbs2' to option '-march='
+// SVE_BF16: error: unsupported argument 'armv8-a+sve-bf16' to option '-march='
+// SVE_EBF16: error: unsupported argument 'armv8-a+sve-ebf16' to option '-march='
+// SVE_I8MM: error: unsupported argument 'armv8-a+sve-i8mm' to option '-march='
+// SVE2_PMULL128: error: unsupported argument 'armv8-a+sve2-pmull128' to option '-march='
+// DPB: error: unsupported argument 'armv8-a+dpb' to option '-march='
+// RCPC2: error: unsupported argument 'armv8-a+rcpc2' to option '-march='
+// FLAGM2: error: unsupported argument 'armv8-a+flagm2' to option '-march='
+// FRINTTS: error: unsupported argument 'armv8-a+frintts' to option '-march='
+// DPB2: error: unsupported argument 'armv8-a+dpb2' to option '-march='
diff --git a/llvm/include/llvm/TargetParser/AArch64TargetParser.h b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
index b662a74e5fc68..0aba9ac5c6891 100644
--- a/llvm/include/llvm/TargetParser/AArch64TargetParser.h
+++ b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
@@ -109,10 +109,10 @@ static_assert(FEAT_MAX < 62,
 
 using ExtensionBitset = Bitset<AEK_NUM_EXTENSIONS>;
 
-// Represents an extension that can be enabled with -march=<arch>+<extension>.
-// Typically these correspond to Arm Architecture extensions, unlike
-// SubtargetFeature which may represent either an actual extension or some
-// internal LLVM property.
+// Represents an extension that can be enabled with -march=<arch>+<extension>,
+// or via a Function Multiversion (FMV) attribute. Typically these correspond
+// to Arm Architecture extensions, unlike SubtargetFeature which may represent
+// either an actual extension or some internal LLVM property.
 struct ExtensionInfo {
   StringRef Name;                 // Human readable name, e.g. "profile".
   std::optional<StringRef> Alias; // An alias for this extension, if one exists.
@@ -120,11 +120,13 @@ struct ExtensionInfo {
                                   // extensions representation in the bitfield.
   StringRef Feature;              // -mattr enable string, e.g. "+spe"
   StringRef NegFeature;           // -mattr disable string, e.g. "-spe"
-  CPUFeatures CPUFeature;      // Function Multi Versioning (FMV) bitfield value
-                               // set in __aarch64_cpu_features
-  StringRef DependentFeatures; // FMV enabled features string,
-                               // e.g. "+dotprod,+fp-armv8,+neon"
-  unsigned FmvPriority;        // FMV feature priority
+  bool IsFMVOnly;                 // Flag indicating whether the extension is
+                                  // available on the command line or not.
+  CPUFeatures CPUFeature;         // FMV bitfield value set in
+                                  // __aarch64_cpu_features
+  StringRef DependentFeatures;    // FMV enabled features string,
+                                  // e.g. "+dotprod,+fp-armv8,+neon"
+  unsigned FmvPriority;           // FMV feature priority
   static constexpr unsigned MaxFMVPriority =
       1000; // Maximum priority for FMV feature
 };
@@ -690,6 +692,7 @@ const ArchInfo *getArchForCpu(StringRef CPU);
 // Parser
 const ArchInfo *parseArch(StringRef Arch);
 std::optional<ExtensionInfo> parseArchExtension(StringRef Extension);
+std::optional<ExtensionInfo> parseFMVExtension(StringRef Extension);
 // Given the name of a CPU or alias, return the correponding CpuInfo.
 std::optional<CpuInfo> parseCpu(StringRef Name);
 // Used by target parser tests
diff --git a/llvm/lib/Target/AArch64/AArch64Features.td b/llvm/lib/Target/AArch64/AArch64Features.td
index b9c26e99ae034..e8db78dfa6d24 100644
--- a/llvm/lib/Target/AArch64/AArch64Features.td
+++ b/llvm/lib/Target/AArch64/AArch64Features.td
@@ -9,17 +9,12 @@
 //
 //===----------------------------------------------------------------------===//
 
-// A SubtargetFeature that can be toggled from the command line, and therefore
-// has an AEK_* entry in ArmExtKind.
+// A SubtargetFeature that can be toggled from the command line, or be part of
+// a Function Multiversioning (FMV) attribute string.
 //
-// If Function MultiVersioning (FMV) properties are left at their defaults
-// (FEAT_INIT, no dependencies, priority 0) it indiates that this extension is
-// not an FMV feature, but can be enabled via the command line (-march, -mcpu,
-// etc).
-//
-// Conversely if the ArchExtKindSpelling is set to AEK_NONE, this indicates
-// that a feature is FMV-only, and can not be selected on the command line.
-// Such extensions should be added via FMVOnlyExtension.
+// If FMV properties are left at their defaults (FEAT_INIT, no dependencies,
+// priority 0) it indiates that this extension is not an FMV feature, but can
+// be enabled via the command line (-march, -mcpu, etc).
 class Extension<
   string TargetFeatureName,            // String used for -target-feature and -march, unless overridden.
   string Spelling,                     // The XYZ in HasXYZ and AEK_XYZ.
@@ -28,7 +23,8 @@ class Extension<
   // FMV properties
   string _FMVBit = "FEAT_INIT",        // FEAT_INIT is repurposed to indicate "not an FMV feature"
   string _FMVDependencies = "",
-  int _FMVPriority = 0
+  int _FMVPriority = 0,
+  string _IsFMVOnly = "false"          // Indicates if the extension is available on the command line.
 > : SubtargetFeature<TargetFeatureName, "Has" # Spelling, "true", Desc, Implies>
 {
     string ArchExtKindSpelling = "AEK_" # Spelling; // ArchExtKind enum name.
@@ -43,7 +39,7 @@ class Extension<
     // Used for correcting historical names while remaining backwards compatible.
     string MArchAlias = "";
 
-    // Function MultiVersioning (FMV) properties
+    // Function Multiversioning (FMV) properties
 
     // A C++ expression giving the number of the bit in the FMV ABI.
     // Currently this is given as a value from the enum "CPUFeatures".
@@ -56,43 +52,64 @@ class Extension<
 
     // The FMV priority
     int FMVPriority = _FMVPriority;
+
+    // Indicates if the extension is available on the command line.
+    string IsFMVOnly = _IsFMVOnly;
 }
 
 // Some extensions are available for FMV but can not be controlled via the
-// command line. These entries:
-//  - are SubtargetFeatures, so they have (unused) FieldNames on the subtarget
-//    e.g. HasFMVOnlyFEAT_XYZ
-//  - have incorrect (empty) Implies fields, because the code that handles FMV
-//    ignores these dependencies and looks only at FMVDependencies.
-//  - have no description.
-// 
-// In the generated data structures for extensions (ExtensionInfo), AEK_NONE is
-// used to indicate that a feature is FMV only. Therefore ArchExtKindSpelling is
-// manually overridden here.
-class FMVOnlyExtension<string FMVBit, string Name, string Deps, int Priority>
-  : Extension<Name, "FMVOnly"#FMVBit, "", [], FMVBit, Deps, Priority> {
-    let ArchExtKindSpelling = "AEK_NONE"; // AEK_NONE indicates FMV-only feature
-}
+// command line, neither have a TargetFeatureName. Since they have no effect
+// on their own, their description is left empty. However they can have side
+// effects by implying other Subtarget Features. These extensions are used
+// in FMV for detection purposes.
+
+let MArchName = "dgh" in
+def : Extension<"", "DGH", "", [], "FEAT_DGH", "", 260, "true">;
+
+let MArchName = "ebf16" in
+def : Extension<"", "EBF16", "", [], "FEAT_EBF16", "+bf16", 290, "true">;
+
+let MArchName = "ls64_accdata" in
+def : Extension<"", "LS64_ACCDATA", "", [], "FEAT_LS64_ACCDATA",
+  "+ls64", 540, "true">;
+
+let MArchName = "ls64_v" in
+def : Extension<"", "LS64_V", "", [], "FEAT_LS64_V", "", 530, "true">;
+
+let MArchName = "memtag2" in
+def : Extension<"", "MEMTAG2", "", [], "FEAT_MEMTAG2", "+mte", 450, "true">;
+
+let MArchName = "memtag3" in
+def : Extension<"", "MEMTAG3", "", [], "FEAT_MEMTAG3", "+mte", 460, "true">;
+
+let MArchName = "pmull" in
+def : Extension<"", "PMULL", "", [], "FEAT_PMULL",
+  "+aes,+fp-armv8,+neon", 160, "true">;
+
+let MArchName = "rpres" in
+def : Extension<"", "RPRES", "", [], "FEAT_RPRES", "", 300, "true">;
+
+let MArchName = "sha1" in
+def : Extension<"", "SHA1", "", [], "FEAT_SHA1", "+fp-armv8,+neon", 120, "true">;
+
+let MArchName = "ssbs2" in
+def : Extension<"", "SSBS2", "", [], "FEAT_SSBS2", "+ssbs", 500, "true">;
+
+let MArchName = "sve-bf16" in
+def : Extension<"", "SVE_BF16", "", [], "FEAT_SVE_BF16",
+  "+sve,+bf16,+fullfp16,+fp-armv8,+neon", 320, "true">;
+
+let MArchName = "sve-ebf16" in
+def : Extension<"", "SVE_EBF16", "", [], "FEAT_SVE_EBF16",
+  "+sve,+bf16,+fullfp16,+fp-armv8,+neon", 330, "true">;
+
+let MArchName = "sve-i8mm" in
+def : Extension<"", "SVE_I8MM", "", [], "FEAT_SVE_I8MM",
+  "+sve,+i8mm,+fullfp16,+fp-armv8,+neon", 340, "true">;
 
-def : FMVOnlyExtension<"FEAT_DGH", "dgh", "", 260>;
-def : FMVOnlyExtension<"FEAT_DPB", "dpb", "+ccpp", 190>;
-def : FMVOnlyExtension<"FEAT_DPB2", "dpb2", "+ccpp,+ccdp", 200>;
-def : FMVOnlyExtension<"FEAT_EBF16", "ebf16", "+bf16", 290>;
-def : FMVOnlyExtension<"FEAT_FLAGM2", "flagm2", "+flagm,+altnzcv", 30>;
-def : FMVOnlyExtension<"FEAT_FRINTTS", "frintts", "+fptoint", 250>;
-def : FMVOnlyExtension<"FEAT_LS64_ACCDATA", "ls64_accdata", "+ls64", 540>;
-def : FMVOnlyExtension<"FEAT_LS64_V", "ls64_v", "", 530>;
-def : FMVOnlyExtension<"FEAT_MEMTAG2", "memtag2", "+mte", 450>;
-def : FMVOnlyExtension<"FEAT_MEMTAG3", "memtag3", "+mte", 460>;
-def : FMVOnlyExtension<"FEAT_PMULL", "pmull", "+aes,+fp-armv8,+neon", 160>;
-def : FMVOnlyExtension<"FEAT_RCPC2", "rcpc2", "+rcpc", 240>;
-def : FMVOnlyExtension<"FEAT_RPRES", "rpres", "", 300>;
-def : FMVOnlyExtension<"FEAT_SHA1", "sha1", "+fp-armv8,+neon", 120>;
-def : FMVOnlyExtension<"FEAT_SSBS2", "ssbs2", "+ssbs", 500>;
-def : FMVOnlyExtension<"FEAT_SVE_BF16", "sve-bf16", "+sve,+bf16,+fullfp16,+fp-armv8,+neon", 320>;
-def : FMVOnlyExtension<"FEAT_SVE_EBF16", "sve-ebf16", "+sve,+bf16,+fullfp16,+fp-armv8,+neon", 330>;
-def : FMVOnlyExtension<"FEAT_SVE_I8MM", "sve-i8mm", "+sve,+i8mm,+fullfp16,+fp-armv8,+neon", 340>;
-def : FMVOnlyExtension<"FEAT_SVE_PMULL128", "sve2-pmull128", "+sve2,+sve,+sve2-aes,+fullfp16,+fp-armv8,+neon", 390>;
+let MArchName = "sve2-pmull128" in
+def : Extension<"", "SVE_PMULL128", "", [], "FEAT_SVE_PMULL128",
+  "+sve2,+sve,+sve2-aes,+fullfp16,+fp-armv8,+neon", 390, "true">;
 
 
 // Each SubtargetFeature which corresponds to an Arm Architecture feature should
@@ -216,8 +233,10 @@ def FeaturePAN_RWV : SubtargetFeature<
 def FeaturePsUAO : SubtargetFeature< "uaops", "HasPsUAO", "true",
     "Enable v8.2 UAO PState (FEAT_UAO)">;
 
-def FeatureCCPP : SubtargetFeature<"ccpp", "HasCCPP",
-    "true", "Enable v8.2 data Cache Clean to Point of Persistence (FEAT_DPB)" >;
+let MArchName = "dpb" in
+def FeatureCCPP : Extension<"ccpp", "CCPP",
+    "Enable v8.2 data Cache Clean to Point of Persistence (FEAT_DPB)", [],
+    "FEAT_DPB", "+ccpp", 190, "true">;
 
 def FeatureSVE : Extension<"sve", "SVE",
   "Enable Scalable Vector Extension (SVE) instructions (FEAT_SVE)", [FeatureFullFP16],
@@ -491,9 +510,10 @@ def FeatureFlagM : Extension<
     "FEAT_FLAGM", "+flagm", 20>;
 
 // 8.4 RCPC enchancements: LDAPR & STLR instructions with Immediate Offset
-def FeatureRCPC_IMMO : SubtargetFeature<"rcpc-immo", "HasRCPC_IMMO", "true",
+let MArchName = "rcpc2" in
+def FeatureRCPC_IMMO : Extension<"rcpc-immo", "RCPC_IMMO",
     "Enable v8.4-A RCPC instructions with Immediate Offsets (FEAT_LRCPC2)",
-    [FeatureRCPC]>;
+    [FeatureRCPC], "FEAT_RCPC2", "+rcpc", 240, "true">;
 
 def FeatureNoNegativeImmediates : SubtargetFeature<"no-neg-immediates",
                                         "NegativeImmediates", "false",
@@ -525,12 +545,16 @@ def FeatureAggressiveFMA :
                    "true",
                    "Enable Aggressive FMA for floating-point.">;
 
-def FeatureAltFPCmp : SubtargetFeature<"altnzcv", "HasAlternativeNZCV", "true",
-  "Enable alternative NZCV format for floating point comparisons (FEAT_FlagM2)">;
+let MArchName = "flagm2" in
+def FeatureAltFPCmp : Extension<"altnzcv", "AlternativeNZCV",
+  "Enable alternative NZCV format for floating point comparisons (FEAT_FlagM2)",
+  [], "FEAT_FLAGM2", "+flagm,+altnzcv", 30, "true">;
 
-def FeatureFRInt3264 : SubtargetFeature<"fptoint", "HasFRInt3264", "true",
+let MArchName = "frintts" in
+def FeatureFRInt3264 : Extension<"fptoint", "FRInt3264",
   "Enable FRInt[32|64][Z|X] instructions that round a floating-point number to "
-  "an integer (in FP format) forcing it to fit into a 32- or 64-bit int (FEAT_FRINTTS)" >;
+  "an integer (in FP format) forcing it to fit into a 32- or 64-bit int (FEAT_FRINTTS)",
+  [], "FEAT_FRINTTS", "+fptoint", 250, "true">;
 
 def FeatureSpecRestrict : SubtargetFeature<"specrestrict", "HasSpecRestrict",
   "true", "Enable architectural speculation restriction (FEAT_CSV2_2)">;
@@ -547,13 +571,14 @@ def FeaturePredRes : Extension<"predres", "PredRes",
   "Enable v8.5a execution and data prediction invalidation instructions (FEAT_SPECRES)", [],
   "FEAT_PREDRES", "+predres", 480>;
 
-def FeatureCacheDeepPersist : SubtargetFeature<"ccdp", "CCDP", "true",
-    "Enable v8.5 Cache Clean to Point of Deep Persistence (FEAT_DPB2)" >;
+let MArchName = "dpb2" in
+def FeatureCacheDeepPersist : Extension<"ccdp", "CCDP",
+  "Enable v8.5 Cache Clean to Point of Deep Persistence (FEAT_DPB2)", [],
+  "FEAT_DPB2", "+ccpp,+ccdp", 200, "true">;
 
-let ArchExtKindSpelling = "AEK_NONE" in
 def FeatureBranchTargetId : Extension<"bti", "BTI",
     "Enable Branch Target Identification (FEAT_BTI)", [],
-    "FEAT_BTI", "+bti", 510>;
+    "FEAT_BTI", "+bti", 510, "true">;
 
 let ArchExtKindSpelling = "AEK_RAND", MArchName = "rng" in
 def FeatureRandGen : Extension<"rand", "RandGen",
diff --git a/llvm/lib/TargetParser/AArch64TargetParser.cpp b/llvm/lib/TargetParser/AArch64TargetParser.cpp
index c10b4be4eded9..a8fb63e37d96c 100644
--- a/llvm/lib/TargetParser/AArch64TargetParser.cpp
+++ b/llvm/lib/TargetParser/AArch64TargetParser.cpp
@@ -50,7 +50,7 @@ std::optional<AArch64::ArchInfo> AArch64::ArchInfo::findBySubArch(StringRef SubA
 uint64_t AArch64::getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs) {
   uint64_t FeaturesMask = 0;
   for (const StringRef &FeatureStr : FeatureStrs) {
-    if (auto Ext = parseArchExtension(FeatureStr))
+    if (auto Ext = parseFMVExtension(FeatureStr))
       FeaturesMask |= (1ULL << Ext->CPUFeature);
   }
   return FeaturesMask;
@@ -116,12 +116,23 @@ const AArch64::ArchInfo *AArch64::parseArch(Stri...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented May 17, 2024

@llvm/pr-subscribers-backend-aarch64

Author: Alexandros Lamprineas (labrinea)

Changes

When we moved the extension information into tablegen in #90987, some features (FEAT_DPB, FEAT_DPB2, FEAT_FLAGM2, FEAT_FRINTTS, FEAT_RCPC2) were defined as FMVOnlyExtension despite already having an equivalent SubtargetFeature in place. This patch is fusing these duplications.


Patch is 21.98 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/92319.diff

8 Files Affected:

  • (modified) clang/lib/Basic/Targets/AArch64.cpp (+4-4)
  • (modified) clang/lib/CodeGen/CGBuiltin.cpp (+1-1)
  • (modified) clang/lib/CodeGen/Targets/AArch64.cpp (+1-1)
  • (added) clang/test/Driver/aarch64-fmv-only-feature.c (+41)
  • (modified) llvm/include/llvm/TargetParser/AArch64TargetParser.h (+12-9)
  • (modified) llvm/lib/Target/AArch64/AArch64Features.td (+82-57)
  • (modified) llvm/lib/TargetParser/AArch64TargetParser.cpp (+12-1)
  • (modified) llvm/utils/TableGen/ARMTargetDefEmitter.cpp (+6-4)
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index 5db1ce78c657f..ec9632045fa95 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -659,7 +659,7 @@ AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts) const {
 unsigned AArch64TargetInfo::multiVersionSortPriority(StringRef Name) const {
   if (Name == "default")
     return 0;
-  if (auto Ext = llvm::AArch64::parseArchExtension(Name))
+  if (auto Ext = llvm::AArch64::parseFMVExtension(Name))
     return Ext->FmvPriority;
   return 0;
 }
@@ -670,13 +670,13 @@ unsigned AArch64TargetInfo::multiVersionFeatureCost() const {
 }
 
 bool AArch64TargetInfo::doesFeatureAffectCodeGen(StringRef Name) const {
-  if (auto Ext = llvm::AArch64::parseArchExtension(Name))
+  if (auto Ext = llvm::AArch64::parseFMVExtension(Name))
     return !Ext->DependentFeatures.empty();
   return false;
 }
 
 StringRef AArch64TargetInfo::getFeatureDependencies(StringRef Name) const {
-  if (auto Ext = llvm::AArch64::parseArchExtension(Name))
+  if (auto Ext = llvm::AArch64::parseFMVExtension(Name))
     return Ext->DependentFeatures;
   return StringRef();
 }
@@ -686,7 +686,7 @@ bool AArch64TargetInfo::validateCpuSupports(StringRef FeatureStr) const {
   llvm::SmallVector<StringRef, 8> Features;
   FeatureStr.split(Features, "+");
   for (auto &Feature : Features)
-    if (!llvm::AArch64::parseArchExtension(Feature.trim()).has_value())
+    if (!llvm::AArch64::parseFMVExtension(Feature.trim()).has_value())
       return false;
   return true;
 }
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index f9ee93049b12d..ef0337d42505f 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -14259,7 +14259,7 @@ Value *CodeGenFunction::EmitAArch64CpuSupports(const CallExpr *E) {
   ArgStr.split(Features, "+");
   for (auto &Feature : Features) {
     Feature = Feature.trim();
-    if (!llvm::AArch64::parseArchExtension(Feature))
+    if (!llvm::AArch64::parseFMVExtension(Feature))
       return Builder.getFalse();
     if (Feature != "default")
       Features.push_back(Feature);
diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp
index e32b060ebeb93..dcb517e978ca9 100644
--- a/clang/lib/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CodeGen/Targets/AArch64.cpp
@@ -973,7 +973,7 @@ void AArch64ABIInfo::appendAttributeMangling(StringRef AttrStr,
 
   llvm::SmallDenseSet<StringRef, 8> UniqueFeats;
   for (auto &Feat : Features)
-    if (auto Ext = llvm::AArch64::parseArchExtension(Feat))
+    if (auto Ext = llvm::AArch64::parseFMVExtension(Feat))
       if (UniqueFeats.insert(Ext->Name).second)
         Out << 'M' << Ext->Name;
 }
diff --git a/clang/test/Driver/aarch64-fmv-only-feature.c b/clang/test/Driver/aarch64-fmv-only-feature.c
new file mode 100644
index 0000000000000..f918b3f8fb64a
--- /dev/null
+++ b/clang/test/Driver/aarch64-fmv-only-feature.c
@@ -0,0 +1,41 @@
+// Test that features which are meaningful only for Function Multiversioning are rejected from the command line.
+
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+dgh %s 2>&1 | FileCheck %s --check-prefix=DGH
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+ebf16 %s 2>&1 | FileCheck %s --check-prefix=EBF16
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+ls64_accdata %s 2>&1 | FileCheck %s --check-prefix=LS64_ACCDATA
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+ls64_v %s 2>&1 | FileCheck %s --check-prefix=LS64_V
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+memtag2 %s 2>&1 | FileCheck %s --check-prefix=MEMTAG2
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+memtag3 %s 2>&1 | FileCheck %s --check-prefix=MEMTAG3
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+pmull %s 2>&1 | FileCheck %s --check-prefix=PMULL
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+rpres %s 2>&1 | FileCheck %s --check-prefix=RPRES
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+sha1 %s 2>&1 | FileCheck %s --check-prefix=SHA1
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+ssbs2 %s 2>&1 | FileCheck %s --check-prefix=SSBS2
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+sve-bf16 %s 2>&1 | FileCheck %s --check-prefix=SVE_BF16
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+sve-ebf16 %s 2>&1 | FileCheck %s --check-prefix=SVE_EBF16
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+sve-i8mm %s 2>&1 | FileCheck %s --check-prefix=SVE_I8MM
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+sve2-pmull128 %s 2>&1 | FileCheck %s --check-prefix=SVE2_PMULL128
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+dpb %s 2>&1 | FileCheck %s --check-prefix=DPB
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+rcpc2 %s 2>&1 | FileCheck %s --check-prefix=RCPC2
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+flagm2 %s 2>&1 | FileCheck %s --check-prefix=FLAGM2
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+frintts %s 2>&1 | FileCheck %s --check-prefix=FRINTTS
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+dpb2 %s 2>&1 | FileCheck %s --check-prefix=DPB2
+
+// DGH: error: unsupported argument 'armv8-a+dgh' to option '-march='
+// EBF16: error: unsupported argument 'armv8-a+ebf16' to option '-march='
+// LS64_ACCDATA: error: unsupported argument 'armv8-a+ls64_accdata' to option '-march='
+// LS64_V: error: unsupported argument 'armv8-a+ls64_v' to option '-march='
+// MEMTAG2: error: unsupported argument 'armv8-a+memtag2' to option '-march='
+// MEMTAG3: error: unsupported argument 'armv8-a+memtag3' to option '-march='
+// PMULL: error: unsupported argument 'armv8-a+pmull' to option '-march='
+// RPRES: error: unsupported argument 'armv8-a+rpres' to option '-march='
+// SHA1: error: unsupported argument 'armv8-a+sha1' to option '-march='
+// SSBS2: error: unsupported argument 'armv8-a+ssbs2' to option '-march='
+// SVE_BF16: error: unsupported argument 'armv8-a+sve-bf16' to option '-march='
+// SVE_EBF16: error: unsupported argument 'armv8-a+sve-ebf16' to option '-march='
+// SVE_I8MM: error: unsupported argument 'armv8-a+sve-i8mm' to option '-march='
+// SVE2_PMULL128: error: unsupported argument 'armv8-a+sve2-pmull128' to option '-march='
+// DPB: error: unsupported argument 'armv8-a+dpb' to option '-march='
+// RCPC2: error: unsupported argument 'armv8-a+rcpc2' to option '-march='
+// FLAGM2: error: unsupported argument 'armv8-a+flagm2' to option '-march='
+// FRINTTS: error: unsupported argument 'armv8-a+frintts' to option '-march='
+// DPB2: error: unsupported argument 'armv8-a+dpb2' to option '-march='
diff --git a/llvm/include/llvm/TargetParser/AArch64TargetParser.h b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
index b662a74e5fc68..0aba9ac5c6891 100644
--- a/llvm/include/llvm/TargetParser/AArch64TargetParser.h
+++ b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
@@ -109,10 +109,10 @@ static_assert(FEAT_MAX < 62,
 
 using ExtensionBitset = Bitset<AEK_NUM_EXTENSIONS>;
 
-// Represents an extension that can be enabled with -march=<arch>+<extension>.
-// Typically these correspond to Arm Architecture extensions, unlike
-// SubtargetFeature which may represent either an actual extension or some
-// internal LLVM property.
+// Represents an extension that can be enabled with -march=<arch>+<extension>,
+// or via a Function Multiversion (FMV) attribute. Typically these correspond
+// to Arm Architecture extensions, unlike SubtargetFeature which may represent
+// either an actual extension or some internal LLVM property.
 struct ExtensionInfo {
   StringRef Name;                 // Human readable name, e.g. "profile".
   std::optional<StringRef> Alias; // An alias for this extension, if one exists.
@@ -120,11 +120,13 @@ struct ExtensionInfo {
                                   // extensions representation in the bitfield.
   StringRef Feature;              // -mattr enable string, e.g. "+spe"
   StringRef NegFeature;           // -mattr disable string, e.g. "-spe"
-  CPUFeatures CPUFeature;      // Function Multi Versioning (FMV) bitfield value
-                               // set in __aarch64_cpu_features
-  StringRef DependentFeatures; // FMV enabled features string,
-                               // e.g. "+dotprod,+fp-armv8,+neon"
-  unsigned FmvPriority;        // FMV feature priority
+  bool IsFMVOnly;                 // Flag indicating whether the extension is
+                                  // available on the command line or not.
+  CPUFeatures CPUFeature;         // FMV bitfield value set in
+                                  // __aarch64_cpu_features
+  StringRef DependentFeatures;    // FMV enabled features string,
+                                  // e.g. "+dotprod,+fp-armv8,+neon"
+  unsigned FmvPriority;           // FMV feature priority
   static constexpr unsigned MaxFMVPriority =
       1000; // Maximum priority for FMV feature
 };
@@ -690,6 +692,7 @@ const ArchInfo *getArchForCpu(StringRef CPU);
 // Parser
 const ArchInfo *parseArch(StringRef Arch);
 std::optional<ExtensionInfo> parseArchExtension(StringRef Extension);
+std::optional<ExtensionInfo> parseFMVExtension(StringRef Extension);
 // Given the name of a CPU or alias, return the correponding CpuInfo.
 std::optional<CpuInfo> parseCpu(StringRef Name);
 // Used by target parser tests
diff --git a/llvm/lib/Target/AArch64/AArch64Features.td b/llvm/lib/Target/AArch64/AArch64Features.td
index b9c26e99ae034..e8db78dfa6d24 100644
--- a/llvm/lib/Target/AArch64/AArch64Features.td
+++ b/llvm/lib/Target/AArch64/AArch64Features.td
@@ -9,17 +9,12 @@
 //
 //===----------------------------------------------------------------------===//
 
-// A SubtargetFeature that can be toggled from the command line, and therefore
-// has an AEK_* entry in ArmExtKind.
+// A SubtargetFeature that can be toggled from the command line, or be part of
+// a Function Multiversioning (FMV) attribute string.
 //
-// If Function MultiVersioning (FMV) properties are left at their defaults
-// (FEAT_INIT, no dependencies, priority 0) it indiates that this extension is
-// not an FMV feature, but can be enabled via the command line (-march, -mcpu,
-// etc).
-//
-// Conversely if the ArchExtKindSpelling is set to AEK_NONE, this indicates
-// that a feature is FMV-only, and can not be selected on the command line.
-// Such extensions should be added via FMVOnlyExtension.
+// If FMV properties are left at their defaults (FEAT_INIT, no dependencies,
+// priority 0) it indiates that this extension is not an FMV feature, but can
+// be enabled via the command line (-march, -mcpu, etc).
 class Extension<
   string TargetFeatureName,            // String used for -target-feature and -march, unless overridden.
   string Spelling,                     // The XYZ in HasXYZ and AEK_XYZ.
@@ -28,7 +23,8 @@ class Extension<
   // FMV properties
   string _FMVBit = "FEAT_INIT",        // FEAT_INIT is repurposed to indicate "not an FMV feature"
   string _FMVDependencies = "",
-  int _FMVPriority = 0
+  int _FMVPriority = 0,
+  string _IsFMVOnly = "false"          // Indicates if the extension is available on the command line.
 > : SubtargetFeature<TargetFeatureName, "Has" # Spelling, "true", Desc, Implies>
 {
     string ArchExtKindSpelling = "AEK_" # Spelling; // ArchExtKind enum name.
@@ -43,7 +39,7 @@ class Extension<
     // Used for correcting historical names while remaining backwards compatible.
     string MArchAlias = "";
 
-    // Function MultiVersioning (FMV) properties
+    // Function Multiversioning (FMV) properties
 
     // A C++ expression giving the number of the bit in the FMV ABI.
     // Currently this is given as a value from the enum "CPUFeatures".
@@ -56,43 +52,64 @@ class Extension<
 
     // The FMV priority
     int FMVPriority = _FMVPriority;
+
+    // Indicates if the extension is available on the command line.
+    string IsFMVOnly = _IsFMVOnly;
 }
 
 // Some extensions are available for FMV but can not be controlled via the
-// command line. These entries:
-//  - are SubtargetFeatures, so they have (unused) FieldNames on the subtarget
-//    e.g. HasFMVOnlyFEAT_XYZ
-//  - have incorrect (empty) Implies fields, because the code that handles FMV
-//    ignores these dependencies and looks only at FMVDependencies.
-//  - have no description.
-// 
-// In the generated data structures for extensions (ExtensionInfo), AEK_NONE is
-// used to indicate that a feature is FMV only. Therefore ArchExtKindSpelling is
-// manually overridden here.
-class FMVOnlyExtension<string FMVBit, string Name, string Deps, int Priority>
-  : Extension<Name, "FMVOnly"#FMVBit, "", [], FMVBit, Deps, Priority> {
-    let ArchExtKindSpelling = "AEK_NONE"; // AEK_NONE indicates FMV-only feature
-}
+// command line, neither have a TargetFeatureName. Since they have no effect
+// on their own, their description is left empty. However they can have side
+// effects by implying other Subtarget Features. These extensions are used
+// in FMV for detection purposes.
+
+let MArchName = "dgh" in
+def : Extension<"", "DGH", "", [], "FEAT_DGH", "", 260, "true">;
+
+let MArchName = "ebf16" in
+def : Extension<"", "EBF16", "", [], "FEAT_EBF16", "+bf16", 290, "true">;
+
+let MArchName = "ls64_accdata" in
+def : Extension<"", "LS64_ACCDATA", "", [], "FEAT_LS64_ACCDATA",
+  "+ls64", 540, "true">;
+
+let MArchName = "ls64_v" in
+def : Extension<"", "LS64_V", "", [], "FEAT_LS64_V", "", 530, "true">;
+
+let MArchName = "memtag2" in
+def : Extension<"", "MEMTAG2", "", [], "FEAT_MEMTAG2", "+mte", 450, "true">;
+
+let MArchName = "memtag3" in
+def : Extension<"", "MEMTAG3", "", [], "FEAT_MEMTAG3", "+mte", 460, "true">;
+
+let MArchName = "pmull" in
+def : Extension<"", "PMULL", "", [], "FEAT_PMULL",
+  "+aes,+fp-armv8,+neon", 160, "true">;
+
+let MArchName = "rpres" in
+def : Extension<"", "RPRES", "", [], "FEAT_RPRES", "", 300, "true">;
+
+let MArchName = "sha1" in
+def : Extension<"", "SHA1", "", [], "FEAT_SHA1", "+fp-armv8,+neon", 120, "true">;
+
+let MArchName = "ssbs2" in
+def : Extension<"", "SSBS2", "", [], "FEAT_SSBS2", "+ssbs", 500, "true">;
+
+let MArchName = "sve-bf16" in
+def : Extension<"", "SVE_BF16", "", [], "FEAT_SVE_BF16",
+  "+sve,+bf16,+fullfp16,+fp-armv8,+neon", 320, "true">;
+
+let MArchName = "sve-ebf16" in
+def : Extension<"", "SVE_EBF16", "", [], "FEAT_SVE_EBF16",
+  "+sve,+bf16,+fullfp16,+fp-armv8,+neon", 330, "true">;
+
+let MArchName = "sve-i8mm" in
+def : Extension<"", "SVE_I8MM", "", [], "FEAT_SVE_I8MM",
+  "+sve,+i8mm,+fullfp16,+fp-armv8,+neon", 340, "true">;
 
-def : FMVOnlyExtension<"FEAT_DGH", "dgh", "", 260>;
-def : FMVOnlyExtension<"FEAT_DPB", "dpb", "+ccpp", 190>;
-def : FMVOnlyExtension<"FEAT_DPB2", "dpb2", "+ccpp,+ccdp", 200>;
-def : FMVOnlyExtension<"FEAT_EBF16", "ebf16", "+bf16", 290>;
-def : FMVOnlyExtension<"FEAT_FLAGM2", "flagm2", "+flagm,+altnzcv", 30>;
-def : FMVOnlyExtension<"FEAT_FRINTTS", "frintts", "+fptoint", 250>;
-def : FMVOnlyExtension<"FEAT_LS64_ACCDATA", "ls64_accdata", "+ls64", 540>;
-def : FMVOnlyExtension<"FEAT_LS64_V", "ls64_v", "", 530>;
-def : FMVOnlyExtension<"FEAT_MEMTAG2", "memtag2", "+mte", 450>;
-def : FMVOnlyExtension<"FEAT_MEMTAG3", "memtag3", "+mte", 460>;
-def : FMVOnlyExtension<"FEAT_PMULL", "pmull", "+aes,+fp-armv8,+neon", 160>;
-def : FMVOnlyExtension<"FEAT_RCPC2", "rcpc2", "+rcpc", 240>;
-def : FMVOnlyExtension<"FEAT_RPRES", "rpres", "", 300>;
-def : FMVOnlyExtension<"FEAT_SHA1", "sha1", "+fp-armv8,+neon", 120>;
-def : FMVOnlyExtension<"FEAT_SSBS2", "ssbs2", "+ssbs", 500>;
-def : FMVOnlyExtension<"FEAT_SVE_BF16", "sve-bf16", "+sve,+bf16,+fullfp16,+fp-armv8,+neon", 320>;
-def : FMVOnlyExtension<"FEAT_SVE_EBF16", "sve-ebf16", "+sve,+bf16,+fullfp16,+fp-armv8,+neon", 330>;
-def : FMVOnlyExtension<"FEAT_SVE_I8MM", "sve-i8mm", "+sve,+i8mm,+fullfp16,+fp-armv8,+neon", 340>;
-def : FMVOnlyExtension<"FEAT_SVE_PMULL128", "sve2-pmull128", "+sve2,+sve,+sve2-aes,+fullfp16,+fp-armv8,+neon", 390>;
+let MArchName = "sve2-pmull128" in
+def : Extension<"", "SVE_PMULL128", "", [], "FEAT_SVE_PMULL128",
+  "+sve2,+sve,+sve2-aes,+fullfp16,+fp-armv8,+neon", 390, "true">;
 
 
 // Each SubtargetFeature which corresponds to an Arm Architecture feature should
@@ -216,8 +233,10 @@ def FeaturePAN_RWV : SubtargetFeature<
 def FeaturePsUAO : SubtargetFeature< "uaops", "HasPsUAO", "true",
     "Enable v8.2 UAO PState (FEAT_UAO)">;
 
-def FeatureCCPP : SubtargetFeature<"ccpp", "HasCCPP",
-    "true", "Enable v8.2 data Cache Clean to Point of Persistence (FEAT_DPB)" >;
+let MArchName = "dpb" in
+def FeatureCCPP : Extension<"ccpp", "CCPP",
+    "Enable v8.2 data Cache Clean to Point of Persistence (FEAT_DPB)", [],
+    "FEAT_DPB", "+ccpp", 190, "true">;
 
 def FeatureSVE : Extension<"sve", "SVE",
   "Enable Scalable Vector Extension (SVE) instructions (FEAT_SVE)", [FeatureFullFP16],
@@ -491,9 +510,10 @@ def FeatureFlagM : Extension<
     "FEAT_FLAGM", "+flagm", 20>;
 
 // 8.4 RCPC enchancements: LDAPR & STLR instructions with Immediate Offset
-def FeatureRCPC_IMMO : SubtargetFeature<"rcpc-immo", "HasRCPC_IMMO", "true",
+let MArchName = "rcpc2" in
+def FeatureRCPC_IMMO : Extension<"rcpc-immo", "RCPC_IMMO",
     "Enable v8.4-A RCPC instructions with Immediate Offsets (FEAT_LRCPC2)",
-    [FeatureRCPC]>;
+    [FeatureRCPC], "FEAT_RCPC2", "+rcpc", 240, "true">;
 
 def FeatureNoNegativeImmediates : SubtargetFeature<"no-neg-immediates",
                                         "NegativeImmediates", "false",
@@ -525,12 +545,16 @@ def FeatureAggressiveFMA :
                    "true",
                    "Enable Aggressive FMA for floating-point.">;
 
-def FeatureAltFPCmp : SubtargetFeature<"altnzcv", "HasAlternativeNZCV", "true",
-  "Enable alternative NZCV format for floating point comparisons (FEAT_FlagM2)">;
+let MArchName = "flagm2" in
+def FeatureAltFPCmp : Extension<"altnzcv", "AlternativeNZCV",
+  "Enable alternative NZCV format for floating point comparisons (FEAT_FlagM2)",
+  [], "FEAT_FLAGM2", "+flagm,+altnzcv", 30, "true">;
 
-def FeatureFRInt3264 : SubtargetFeature<"fptoint", "HasFRInt3264", "true",
+let MArchName = "frintts" in
+def FeatureFRInt3264 : Extension<"fptoint", "FRInt3264",
   "Enable FRInt[32|64][Z|X] instructions that round a floating-point number to "
-  "an integer (in FP format) forcing it to fit into a 32- or 64-bit int (FEAT_FRINTTS)" >;
+  "an integer (in FP format) forcing it to fit into a 32- or 64-bit int (FEAT_FRINTTS)",
+  [], "FEAT_FRINTTS", "+fptoint", 250, "true">;
 
 def FeatureSpecRestrict : SubtargetFeature<"specrestrict", "HasSpecRestrict",
   "true", "Enable architectural speculation restriction (FEAT_CSV2_2)">;
@@ -547,13 +571,14 @@ def FeaturePredRes : Extension<"predres", "PredRes",
   "Enable v8.5a execution and data prediction invalidation instructions (FEAT_SPECRES)", [],
   "FEAT_PREDRES", "+predres", 480>;
 
-def FeatureCacheDeepPersist : SubtargetFeature<"ccdp", "CCDP", "true",
-    "Enable v8.5 Cache Clean to Point of Deep Persistence (FEAT_DPB2)" >;
+let MArchName = "dpb2" in
+def FeatureCacheDeepPersist : Extension<"ccdp", "CCDP",
+  "Enable v8.5 Cache Clean to Point of Deep Persistence (FEAT_DPB2)", [],
+  "FEAT_DPB2", "+ccpp,+ccdp", 200, "true">;
 
-let ArchExtKindSpelling = "AEK_NONE" in
 def FeatureBranchTargetId : Extension<"bti", "BTI",
     "Enable Branch Target Identification (FEAT_BTI)", [],
-    "FEAT_BTI", "+bti", 510>;
+    "FEAT_BTI", "+bti", 510, "true">;
 
 let ArchExtKindSpelling = "AEK_RAND", MArchName = "rng" in
 def FeatureRandGen : Extension<"rand", "RandGen",
diff --git a/llvm/lib/TargetParser/AArch64TargetParser.cpp b/llvm/lib/TargetParser/AArch64TargetParser.cpp
index c10b4be4eded9..a8fb63e37d96c 100644
--- a/llvm/lib/TargetParser/AArch64TargetParser.cpp
+++ b/llvm/lib/TargetParser/AArch64TargetParser.cpp
@@ -50,7 +50,7 @@ std::optional<AArch64::ArchInfo> AArch64::ArchInfo::findBySubArch(StringRef SubA
 uint64_t AArch64::getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs) {
   uint64_t FeaturesMask = 0;
   for (const StringRef &FeatureStr : FeatureStrs) {
-    if (auto Ext = parseArchExtension(FeatureStr))
+    if (auto Ext = parseFMVExtension(FeatureStr))
       FeaturesMask |= (1ULL << Ext->CPUFeature);
   }
   return FeaturesMask;
@@ -116,12 +116,23 @@ const AArch64::ArchInfo *AArch64::parseArch(Stri...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented May 17, 2024

@llvm/pr-subscribers-clang

Author: Alexandros Lamprineas (labrinea)

Changes

When we moved the extension information into tablegen in #90987, some features (FEAT_DPB, FEAT_DPB2, FEAT_FLAGM2, FEAT_FRINTTS, FEAT_RCPC2) were defined as FMVOnlyExtension despite already having an equivalent SubtargetFeature in place. This patch is fusing these duplications.


Patch is 21.98 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/92319.diff

8 Files Affected:

  • (modified) clang/lib/Basic/Targets/AArch64.cpp (+4-4)
  • (modified) clang/lib/CodeGen/CGBuiltin.cpp (+1-1)
  • (modified) clang/lib/CodeGen/Targets/AArch64.cpp (+1-1)
  • (added) clang/test/Driver/aarch64-fmv-only-feature.c (+41)
  • (modified) llvm/include/llvm/TargetParser/AArch64TargetParser.h (+12-9)
  • (modified) llvm/lib/Target/AArch64/AArch64Features.td (+82-57)
  • (modified) llvm/lib/TargetParser/AArch64TargetParser.cpp (+12-1)
  • (modified) llvm/utils/TableGen/ARMTargetDefEmitter.cpp (+6-4)
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index 5db1ce78c657f..ec9632045fa95 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -659,7 +659,7 @@ AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts) const {
 unsigned AArch64TargetInfo::multiVersionSortPriority(StringRef Name) const {
   if (Name == "default")
     return 0;
-  if (auto Ext = llvm::AArch64::parseArchExtension(Name))
+  if (auto Ext = llvm::AArch64::parseFMVExtension(Name))
     return Ext->FmvPriority;
   return 0;
 }
@@ -670,13 +670,13 @@ unsigned AArch64TargetInfo::multiVersionFeatureCost() const {
 }
 
 bool AArch64TargetInfo::doesFeatureAffectCodeGen(StringRef Name) const {
-  if (auto Ext = llvm::AArch64::parseArchExtension(Name))
+  if (auto Ext = llvm::AArch64::parseFMVExtension(Name))
     return !Ext->DependentFeatures.empty();
   return false;
 }
 
 StringRef AArch64TargetInfo::getFeatureDependencies(StringRef Name) const {
-  if (auto Ext = llvm::AArch64::parseArchExtension(Name))
+  if (auto Ext = llvm::AArch64::parseFMVExtension(Name))
     return Ext->DependentFeatures;
   return StringRef();
 }
@@ -686,7 +686,7 @@ bool AArch64TargetInfo::validateCpuSupports(StringRef FeatureStr) const {
   llvm::SmallVector<StringRef, 8> Features;
   FeatureStr.split(Features, "+");
   for (auto &Feature : Features)
-    if (!llvm::AArch64::parseArchExtension(Feature.trim()).has_value())
+    if (!llvm::AArch64::parseFMVExtension(Feature.trim()).has_value())
       return false;
   return true;
 }
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index f9ee93049b12d..ef0337d42505f 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -14259,7 +14259,7 @@ Value *CodeGenFunction::EmitAArch64CpuSupports(const CallExpr *E) {
   ArgStr.split(Features, "+");
   for (auto &Feature : Features) {
     Feature = Feature.trim();
-    if (!llvm::AArch64::parseArchExtension(Feature))
+    if (!llvm::AArch64::parseFMVExtension(Feature))
       return Builder.getFalse();
     if (Feature != "default")
       Features.push_back(Feature);
diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp
index e32b060ebeb93..dcb517e978ca9 100644
--- a/clang/lib/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CodeGen/Targets/AArch64.cpp
@@ -973,7 +973,7 @@ void AArch64ABIInfo::appendAttributeMangling(StringRef AttrStr,
 
   llvm::SmallDenseSet<StringRef, 8> UniqueFeats;
   for (auto &Feat : Features)
-    if (auto Ext = llvm::AArch64::parseArchExtension(Feat))
+    if (auto Ext = llvm::AArch64::parseFMVExtension(Feat))
       if (UniqueFeats.insert(Ext->Name).second)
         Out << 'M' << Ext->Name;
 }
diff --git a/clang/test/Driver/aarch64-fmv-only-feature.c b/clang/test/Driver/aarch64-fmv-only-feature.c
new file mode 100644
index 0000000000000..f918b3f8fb64a
--- /dev/null
+++ b/clang/test/Driver/aarch64-fmv-only-feature.c
@@ -0,0 +1,41 @@
+// Test that features which are meaningful only for Function Multiversioning are rejected from the command line.
+
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+dgh %s 2>&1 | FileCheck %s --check-prefix=DGH
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+ebf16 %s 2>&1 | FileCheck %s --check-prefix=EBF16
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+ls64_accdata %s 2>&1 | FileCheck %s --check-prefix=LS64_ACCDATA
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+ls64_v %s 2>&1 | FileCheck %s --check-prefix=LS64_V
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+memtag2 %s 2>&1 | FileCheck %s --check-prefix=MEMTAG2
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+memtag3 %s 2>&1 | FileCheck %s --check-prefix=MEMTAG3
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+pmull %s 2>&1 | FileCheck %s --check-prefix=PMULL
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+rpres %s 2>&1 | FileCheck %s --check-prefix=RPRES
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+sha1 %s 2>&1 | FileCheck %s --check-prefix=SHA1
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+ssbs2 %s 2>&1 | FileCheck %s --check-prefix=SSBS2
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+sve-bf16 %s 2>&1 | FileCheck %s --check-prefix=SVE_BF16
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+sve-ebf16 %s 2>&1 | FileCheck %s --check-prefix=SVE_EBF16
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+sve-i8mm %s 2>&1 | FileCheck %s --check-prefix=SVE_I8MM
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+sve2-pmull128 %s 2>&1 | FileCheck %s --check-prefix=SVE2_PMULL128
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+dpb %s 2>&1 | FileCheck %s --check-prefix=DPB
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+rcpc2 %s 2>&1 | FileCheck %s --check-prefix=RCPC2
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+flagm2 %s 2>&1 | FileCheck %s --check-prefix=FLAGM2
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+frintts %s 2>&1 | FileCheck %s --check-prefix=FRINTTS
+// RUN: not %clang --target=aarch64-linux-gnu -march=armv8-a+dpb2 %s 2>&1 | FileCheck %s --check-prefix=DPB2
+
+// DGH: error: unsupported argument 'armv8-a+dgh' to option '-march='
+// EBF16: error: unsupported argument 'armv8-a+ebf16' to option '-march='
+// LS64_ACCDATA: error: unsupported argument 'armv8-a+ls64_accdata' to option '-march='
+// LS64_V: error: unsupported argument 'armv8-a+ls64_v' to option '-march='
+// MEMTAG2: error: unsupported argument 'armv8-a+memtag2' to option '-march='
+// MEMTAG3: error: unsupported argument 'armv8-a+memtag3' to option '-march='
+// PMULL: error: unsupported argument 'armv8-a+pmull' to option '-march='
+// RPRES: error: unsupported argument 'armv8-a+rpres' to option '-march='
+// SHA1: error: unsupported argument 'armv8-a+sha1' to option '-march='
+// SSBS2: error: unsupported argument 'armv8-a+ssbs2' to option '-march='
+// SVE_BF16: error: unsupported argument 'armv8-a+sve-bf16' to option '-march='
+// SVE_EBF16: error: unsupported argument 'armv8-a+sve-ebf16' to option '-march='
+// SVE_I8MM: error: unsupported argument 'armv8-a+sve-i8mm' to option '-march='
+// SVE2_PMULL128: error: unsupported argument 'armv8-a+sve2-pmull128' to option '-march='
+// DPB: error: unsupported argument 'armv8-a+dpb' to option '-march='
+// RCPC2: error: unsupported argument 'armv8-a+rcpc2' to option '-march='
+// FLAGM2: error: unsupported argument 'armv8-a+flagm2' to option '-march='
+// FRINTTS: error: unsupported argument 'armv8-a+frintts' to option '-march='
+// DPB2: error: unsupported argument 'armv8-a+dpb2' to option '-march='
diff --git a/llvm/include/llvm/TargetParser/AArch64TargetParser.h b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
index b662a74e5fc68..0aba9ac5c6891 100644
--- a/llvm/include/llvm/TargetParser/AArch64TargetParser.h
+++ b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
@@ -109,10 +109,10 @@ static_assert(FEAT_MAX < 62,
 
 using ExtensionBitset = Bitset<AEK_NUM_EXTENSIONS>;
 
-// Represents an extension that can be enabled with -march=<arch>+<extension>.
-// Typically these correspond to Arm Architecture extensions, unlike
-// SubtargetFeature which may represent either an actual extension or some
-// internal LLVM property.
+// Represents an extension that can be enabled with -march=<arch>+<extension>,
+// or via a Function Multiversion (FMV) attribute. Typically these correspond
+// to Arm Architecture extensions, unlike SubtargetFeature which may represent
+// either an actual extension or some internal LLVM property.
 struct ExtensionInfo {
   StringRef Name;                 // Human readable name, e.g. "profile".
   std::optional<StringRef> Alias; // An alias for this extension, if one exists.
@@ -120,11 +120,13 @@ struct ExtensionInfo {
                                   // extensions representation in the bitfield.
   StringRef Feature;              // -mattr enable string, e.g. "+spe"
   StringRef NegFeature;           // -mattr disable string, e.g. "-spe"
-  CPUFeatures CPUFeature;      // Function Multi Versioning (FMV) bitfield value
-                               // set in __aarch64_cpu_features
-  StringRef DependentFeatures; // FMV enabled features string,
-                               // e.g. "+dotprod,+fp-armv8,+neon"
-  unsigned FmvPriority;        // FMV feature priority
+  bool IsFMVOnly;                 // Flag indicating whether the extension is
+                                  // available on the command line or not.
+  CPUFeatures CPUFeature;         // FMV bitfield value set in
+                                  // __aarch64_cpu_features
+  StringRef DependentFeatures;    // FMV enabled features string,
+                                  // e.g. "+dotprod,+fp-armv8,+neon"
+  unsigned FmvPriority;           // FMV feature priority
   static constexpr unsigned MaxFMVPriority =
       1000; // Maximum priority for FMV feature
 };
@@ -690,6 +692,7 @@ const ArchInfo *getArchForCpu(StringRef CPU);
 // Parser
 const ArchInfo *parseArch(StringRef Arch);
 std::optional<ExtensionInfo> parseArchExtension(StringRef Extension);
+std::optional<ExtensionInfo> parseFMVExtension(StringRef Extension);
 // Given the name of a CPU or alias, return the correponding CpuInfo.
 std::optional<CpuInfo> parseCpu(StringRef Name);
 // Used by target parser tests
diff --git a/llvm/lib/Target/AArch64/AArch64Features.td b/llvm/lib/Target/AArch64/AArch64Features.td
index b9c26e99ae034..e8db78dfa6d24 100644
--- a/llvm/lib/Target/AArch64/AArch64Features.td
+++ b/llvm/lib/Target/AArch64/AArch64Features.td
@@ -9,17 +9,12 @@
 //
 //===----------------------------------------------------------------------===//
 
-// A SubtargetFeature that can be toggled from the command line, and therefore
-// has an AEK_* entry in ArmExtKind.
+// A SubtargetFeature that can be toggled from the command line, or be part of
+// a Function Multiversioning (FMV) attribute string.
 //
-// If Function MultiVersioning (FMV) properties are left at their defaults
-// (FEAT_INIT, no dependencies, priority 0) it indiates that this extension is
-// not an FMV feature, but can be enabled via the command line (-march, -mcpu,
-// etc).
-//
-// Conversely if the ArchExtKindSpelling is set to AEK_NONE, this indicates
-// that a feature is FMV-only, and can not be selected on the command line.
-// Such extensions should be added via FMVOnlyExtension.
+// If FMV properties are left at their defaults (FEAT_INIT, no dependencies,
+// priority 0) it indiates that this extension is not an FMV feature, but can
+// be enabled via the command line (-march, -mcpu, etc).
 class Extension<
   string TargetFeatureName,            // String used for -target-feature and -march, unless overridden.
   string Spelling,                     // The XYZ in HasXYZ and AEK_XYZ.
@@ -28,7 +23,8 @@ class Extension<
   // FMV properties
   string _FMVBit = "FEAT_INIT",        // FEAT_INIT is repurposed to indicate "not an FMV feature"
   string _FMVDependencies = "",
-  int _FMVPriority = 0
+  int _FMVPriority = 0,
+  string _IsFMVOnly = "false"          // Indicates if the extension is available on the command line.
 > : SubtargetFeature<TargetFeatureName, "Has" # Spelling, "true", Desc, Implies>
 {
     string ArchExtKindSpelling = "AEK_" # Spelling; // ArchExtKind enum name.
@@ -43,7 +39,7 @@ class Extension<
     // Used for correcting historical names while remaining backwards compatible.
     string MArchAlias = "";
 
-    // Function MultiVersioning (FMV) properties
+    // Function Multiversioning (FMV) properties
 
     // A C++ expression giving the number of the bit in the FMV ABI.
     // Currently this is given as a value from the enum "CPUFeatures".
@@ -56,43 +52,64 @@ class Extension<
 
     // The FMV priority
     int FMVPriority = _FMVPriority;
+
+    // Indicates if the extension is available on the command line.
+    string IsFMVOnly = _IsFMVOnly;
 }
 
 // Some extensions are available for FMV but can not be controlled via the
-// command line. These entries:
-//  - are SubtargetFeatures, so they have (unused) FieldNames on the subtarget
-//    e.g. HasFMVOnlyFEAT_XYZ
-//  - have incorrect (empty) Implies fields, because the code that handles FMV
-//    ignores these dependencies and looks only at FMVDependencies.
-//  - have no description.
-// 
-// In the generated data structures for extensions (ExtensionInfo), AEK_NONE is
-// used to indicate that a feature is FMV only. Therefore ArchExtKindSpelling is
-// manually overridden here.
-class FMVOnlyExtension<string FMVBit, string Name, string Deps, int Priority>
-  : Extension<Name, "FMVOnly"#FMVBit, "", [], FMVBit, Deps, Priority> {
-    let ArchExtKindSpelling = "AEK_NONE"; // AEK_NONE indicates FMV-only feature
-}
+// command line, neither have a TargetFeatureName. Since they have no effect
+// on their own, their description is left empty. However they can have side
+// effects by implying other Subtarget Features. These extensions are used
+// in FMV for detection purposes.
+
+let MArchName = "dgh" in
+def : Extension<"", "DGH", "", [], "FEAT_DGH", "", 260, "true">;
+
+let MArchName = "ebf16" in
+def : Extension<"", "EBF16", "", [], "FEAT_EBF16", "+bf16", 290, "true">;
+
+let MArchName = "ls64_accdata" in
+def : Extension<"", "LS64_ACCDATA", "", [], "FEAT_LS64_ACCDATA",
+  "+ls64", 540, "true">;
+
+let MArchName = "ls64_v" in
+def : Extension<"", "LS64_V", "", [], "FEAT_LS64_V", "", 530, "true">;
+
+let MArchName = "memtag2" in
+def : Extension<"", "MEMTAG2", "", [], "FEAT_MEMTAG2", "+mte", 450, "true">;
+
+let MArchName = "memtag3" in
+def : Extension<"", "MEMTAG3", "", [], "FEAT_MEMTAG3", "+mte", 460, "true">;
+
+let MArchName = "pmull" in
+def : Extension<"", "PMULL", "", [], "FEAT_PMULL",
+  "+aes,+fp-armv8,+neon", 160, "true">;
+
+let MArchName = "rpres" in
+def : Extension<"", "RPRES", "", [], "FEAT_RPRES", "", 300, "true">;
+
+let MArchName = "sha1" in
+def : Extension<"", "SHA1", "", [], "FEAT_SHA1", "+fp-armv8,+neon", 120, "true">;
+
+let MArchName = "ssbs2" in
+def : Extension<"", "SSBS2", "", [], "FEAT_SSBS2", "+ssbs", 500, "true">;
+
+let MArchName = "sve-bf16" in
+def : Extension<"", "SVE_BF16", "", [], "FEAT_SVE_BF16",
+  "+sve,+bf16,+fullfp16,+fp-armv8,+neon", 320, "true">;
+
+let MArchName = "sve-ebf16" in
+def : Extension<"", "SVE_EBF16", "", [], "FEAT_SVE_EBF16",
+  "+sve,+bf16,+fullfp16,+fp-armv8,+neon", 330, "true">;
+
+let MArchName = "sve-i8mm" in
+def : Extension<"", "SVE_I8MM", "", [], "FEAT_SVE_I8MM",
+  "+sve,+i8mm,+fullfp16,+fp-armv8,+neon", 340, "true">;
 
-def : FMVOnlyExtension<"FEAT_DGH", "dgh", "", 260>;
-def : FMVOnlyExtension<"FEAT_DPB", "dpb", "+ccpp", 190>;
-def : FMVOnlyExtension<"FEAT_DPB2", "dpb2", "+ccpp,+ccdp", 200>;
-def : FMVOnlyExtension<"FEAT_EBF16", "ebf16", "+bf16", 290>;
-def : FMVOnlyExtension<"FEAT_FLAGM2", "flagm2", "+flagm,+altnzcv", 30>;
-def : FMVOnlyExtension<"FEAT_FRINTTS", "frintts", "+fptoint", 250>;
-def : FMVOnlyExtension<"FEAT_LS64_ACCDATA", "ls64_accdata", "+ls64", 540>;
-def : FMVOnlyExtension<"FEAT_LS64_V", "ls64_v", "", 530>;
-def : FMVOnlyExtension<"FEAT_MEMTAG2", "memtag2", "+mte", 450>;
-def : FMVOnlyExtension<"FEAT_MEMTAG3", "memtag3", "+mte", 460>;
-def : FMVOnlyExtension<"FEAT_PMULL", "pmull", "+aes,+fp-armv8,+neon", 160>;
-def : FMVOnlyExtension<"FEAT_RCPC2", "rcpc2", "+rcpc", 240>;
-def : FMVOnlyExtension<"FEAT_RPRES", "rpres", "", 300>;
-def : FMVOnlyExtension<"FEAT_SHA1", "sha1", "+fp-armv8,+neon", 120>;
-def : FMVOnlyExtension<"FEAT_SSBS2", "ssbs2", "+ssbs", 500>;
-def : FMVOnlyExtension<"FEAT_SVE_BF16", "sve-bf16", "+sve,+bf16,+fullfp16,+fp-armv8,+neon", 320>;
-def : FMVOnlyExtension<"FEAT_SVE_EBF16", "sve-ebf16", "+sve,+bf16,+fullfp16,+fp-armv8,+neon", 330>;
-def : FMVOnlyExtension<"FEAT_SVE_I8MM", "sve-i8mm", "+sve,+i8mm,+fullfp16,+fp-armv8,+neon", 340>;
-def : FMVOnlyExtension<"FEAT_SVE_PMULL128", "sve2-pmull128", "+sve2,+sve,+sve2-aes,+fullfp16,+fp-armv8,+neon", 390>;
+let MArchName = "sve2-pmull128" in
+def : Extension<"", "SVE_PMULL128", "", [], "FEAT_SVE_PMULL128",
+  "+sve2,+sve,+sve2-aes,+fullfp16,+fp-armv8,+neon", 390, "true">;
 
 
 // Each SubtargetFeature which corresponds to an Arm Architecture feature should
@@ -216,8 +233,10 @@ def FeaturePAN_RWV : SubtargetFeature<
 def FeaturePsUAO : SubtargetFeature< "uaops", "HasPsUAO", "true",
     "Enable v8.2 UAO PState (FEAT_UAO)">;
 
-def FeatureCCPP : SubtargetFeature<"ccpp", "HasCCPP",
-    "true", "Enable v8.2 data Cache Clean to Point of Persistence (FEAT_DPB)" >;
+let MArchName = "dpb" in
+def FeatureCCPP : Extension<"ccpp", "CCPP",
+    "Enable v8.2 data Cache Clean to Point of Persistence (FEAT_DPB)", [],
+    "FEAT_DPB", "+ccpp", 190, "true">;
 
 def FeatureSVE : Extension<"sve", "SVE",
   "Enable Scalable Vector Extension (SVE) instructions (FEAT_SVE)", [FeatureFullFP16],
@@ -491,9 +510,10 @@ def FeatureFlagM : Extension<
     "FEAT_FLAGM", "+flagm", 20>;
 
 // 8.4 RCPC enchancements: LDAPR & STLR instructions with Immediate Offset
-def FeatureRCPC_IMMO : SubtargetFeature<"rcpc-immo", "HasRCPC_IMMO", "true",
+let MArchName = "rcpc2" in
+def FeatureRCPC_IMMO : Extension<"rcpc-immo", "RCPC_IMMO",
     "Enable v8.4-A RCPC instructions with Immediate Offsets (FEAT_LRCPC2)",
-    [FeatureRCPC]>;
+    [FeatureRCPC], "FEAT_RCPC2", "+rcpc", 240, "true">;
 
 def FeatureNoNegativeImmediates : SubtargetFeature<"no-neg-immediates",
                                         "NegativeImmediates", "false",
@@ -525,12 +545,16 @@ def FeatureAggressiveFMA :
                    "true",
                    "Enable Aggressive FMA for floating-point.">;
 
-def FeatureAltFPCmp : SubtargetFeature<"altnzcv", "HasAlternativeNZCV", "true",
-  "Enable alternative NZCV format for floating point comparisons (FEAT_FlagM2)">;
+let MArchName = "flagm2" in
+def FeatureAltFPCmp : Extension<"altnzcv", "AlternativeNZCV",
+  "Enable alternative NZCV format for floating point comparisons (FEAT_FlagM2)",
+  [], "FEAT_FLAGM2", "+flagm,+altnzcv", 30, "true">;
 
-def FeatureFRInt3264 : SubtargetFeature<"fptoint", "HasFRInt3264", "true",
+let MArchName = "frintts" in
+def FeatureFRInt3264 : Extension<"fptoint", "FRInt3264",
   "Enable FRInt[32|64][Z|X] instructions that round a floating-point number to "
-  "an integer (in FP format) forcing it to fit into a 32- or 64-bit int (FEAT_FRINTTS)" >;
+  "an integer (in FP format) forcing it to fit into a 32- or 64-bit int (FEAT_FRINTTS)",
+  [], "FEAT_FRINTTS", "+fptoint", 250, "true">;
 
 def FeatureSpecRestrict : SubtargetFeature<"specrestrict", "HasSpecRestrict",
   "true", "Enable architectural speculation restriction (FEAT_CSV2_2)">;
@@ -547,13 +571,14 @@ def FeaturePredRes : Extension<"predres", "PredRes",
   "Enable v8.5a execution and data prediction invalidation instructions (FEAT_SPECRES)", [],
   "FEAT_PREDRES", "+predres", 480>;
 
-def FeatureCacheDeepPersist : SubtargetFeature<"ccdp", "CCDP", "true",
-    "Enable v8.5 Cache Clean to Point of Deep Persistence (FEAT_DPB2)" >;
+let MArchName = "dpb2" in
+def FeatureCacheDeepPersist : Extension<"ccdp", "CCDP",
+  "Enable v8.5 Cache Clean to Point of Deep Persistence (FEAT_DPB2)", [],
+  "FEAT_DPB2", "+ccpp,+ccdp", 200, "true">;
 
-let ArchExtKindSpelling = "AEK_NONE" in
 def FeatureBranchTargetId : Extension<"bti", "BTI",
     "Enable Branch Target Identification (FEAT_BTI)", [],
-    "FEAT_BTI", "+bti", 510>;
+    "FEAT_BTI", "+bti", 510, "true">;
 
 let ArchExtKindSpelling = "AEK_RAND", MArchName = "rng" in
 def FeatureRandGen : Extension<"rand", "RandGen",
diff --git a/llvm/lib/TargetParser/AArch64TargetParser.cpp b/llvm/lib/TargetParser/AArch64TargetParser.cpp
index c10b4be4eded9..a8fb63e37d96c 100644
--- a/llvm/lib/TargetParser/AArch64TargetParser.cpp
+++ b/llvm/lib/TargetParser/AArch64TargetParser.cpp
@@ -50,7 +50,7 @@ std::optional<AArch64::ArchInfo> AArch64::ArchInfo::findBySubArch(StringRef SubA
 uint64_t AArch64::getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs) {
   uint64_t FeaturesMask = 0;
   for (const StringRef &FeatureStr : FeatureStrs) {
-    if (auto Ext = parseArchExtension(FeatureStr))
+    if (auto Ext = parseFMVExtension(FeatureStr))
       FeaturesMask |= (1ULL << Ext->CPUFeature);
   }
   return FeaturesMask;
@@ -116,12 +116,23 @@ const AArch64::ArchInfo *AArch64::parseArch(Stri...
[truncated]

llvm/lib/Target/AArch64/AArch64Features.td Outdated Show resolved Hide resolved
llvm/utils/TableGen/ARMTargetDefEmitter.cpp Outdated Show resolved Hide resolved
llvm/lib/Target/AArch64/AArch64Features.td Outdated Show resolved Hide resolved
When we moved the extension information into tablegen in llvm#90987, some
features (FEAT_DPB, FEAT_DPB2, FEAT_FLAGM2, FEAT_FRINTTS, FEAT_RCPC2)
were defined as FMVOnlyExtension despite already having an equivalent
SubtargetFeature in place. This patch is fusing these duplications.

Moreover my reverted attempt to decouple feature dependency expansion
(see llvm#95056) made it evident that some features are still using the FMV
dependencies in the target attribute. FEAT_PMULL and FEAT_SSBS2 are
such examples. I have rectified those to reland the mentioned patch.
@labrinea
Copy link
Collaborator Author

closing in favor of #92882

@labrinea labrinea closed this Jun 20, 2024
@labrinea labrinea deleted the aarch64-merge-duplicate-features branch June 20, 2024 15:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:AArch64 clang:codegen clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants