https://github.com/jthackray updated 
https://github.com/llvm/llvm-project/pull/190959

>From 77d22642c936deb7f3e117db39190655e185d7da Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <[email protected]>
Date: Fri, 3 Apr 2026 01:14:47 +0100
Subject: [PATCH 1/2] [AArch64][clang] Use tablegen rather than hard-coded
 feature dependencies

Refactor AArch64 frontend feature handling so extension relationships come
from the TargetParser extension graph instead of hand-written dependency
code in C++. This makes `llvm::AArch64::ExtensionSet` the source of
truth for dependency expansion while still keeping the short `Has...` names
used in the frontend code.

This removes a large amount of duplicated implication logic from
`handleTargetFeatures` and related feature queries. The frontend now
rebuilds its extension state from TableGen-derived data and then derives
its cached feature state from that, rather than maintaining parallel
dependency rules in C++.

I also preserved several pieces of historical frontend behaviour that are
not represented directly in the extension graph. Explicit disables such as
`no-sme` still win after implied-feature expansion, direct `+fullfp16` and
`+jscvt` still restore the expected NEON-facing state, and SME-family
features no longer incorrectly appear to enable AdvSIMD/NEON.

Finally, I added regression coverage for the direct-feature and explicit
disable cases uncovered during review, including raw `-target-feature`
combinations and target-attribute cases such as `no-sme`.
---
 clang/lib/Basic/Targets/AArch64.cpp           | 517 ++++++++----------
 clang/lib/Basic/Targets/AArch64.h             |  80 +--
 .../Targets/AArch64TargetInfoFeatures.inc     |  69 +++
 clang/lib/Sema/SemaARM.cpp                    |   6 +-
 clang/lib/Sema/SemaChecking.cpp               |   2 +-
 .../Preprocessor/aarch64-target-features.c    |  22 +
 ...-sme-func-attrs-without-target-feature.cpp |   5 +
 7 files changed, 346 insertions(+), 355 deletions(-)
 create mode 100644 clang/lib/Basic/Targets/AArch64TargetInfoFeatures.inc

diff --git a/clang/lib/Basic/Targets/AArch64.cpp 
b/clang/lib/Basic/Targets/AArch64.cpp
index 9b951e69cce33..399d9ed5ae052 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -254,7 +254,8 @@ bool AArch64TargetInfo::validateBranchProtection(StringRef 
Spec, StringRef,
                                                  const LangOptions &LO,
                                                  StringRef &Err) const {
   llvm::ARM::ParsedBranchProtection PBP;
-  if (!llvm::ARM::parseBranchProtection(Spec, PBP, Err, HasPAuthLR))
+  if (!llvm::ARM::parseBranchProtection(
+          Spec, PBP, Err, hasExtension(llvm::AArch64::AEK_PAUTHLR)))
     return false;
 
   // GCS is currently untested with ptrauth-returns, but enabling this could be
@@ -494,6 +495,13 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions 
&Opts,
   if (FPU & SveMode)
     Builder.defineMacro("__ARM_FEATURE_SVE", "1");
 
+  const bool HasSVE = FPU & SveMode;
+  const bool HasNeon = FPU & NeonMode;
+#define AARCH64_EXTENSION_FEATURE(Name, Ext)                                   
\
+  [[maybe_unused]] const bool Name = hasExtension(llvm::AArch64::AEK_##Ext);
+#include "AArch64TargetInfoFeatures.inc"
+#undef AARCH64_EXTENSION_FEATURE
+
   if (HasSVE2)
     Builder.defineMacro("__ARM_FEATURE_SVE2", "1");
 
@@ -621,7 +629,7 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions 
&Opts,
     Builder.defineMacro("__ARM_FEATURE_SM4", "1");
   }
 
-  if (HasPAuth)
+  if (hasPAuth())
     Builder.defineMacro("__ARM_FEATURE_PAUTH", "1");
 
   if (HasPAuthLR)
@@ -633,10 +641,10 @@ void AArch64TargetInfo::getTargetDefines(const 
LangOptions &Opts,
   if (HasUnalignedAccess)
     Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1");
 
-  if ((FPU & NeonMode) && HasFullFP16)
+  if ((FPU & NeonMode) && hasFullFP16())
     Builder.defineMacro("__ARM_FEATURE_FP16_VECTOR_ARITHMETIC", "1");
-  if (HasFullFP16)
-   Builder.defineMacro("__ARM_FEATURE_FP16_SCALAR_ARITHMETIC", "1");
+  if (hasFullFP16())
+    Builder.defineMacro("__ARM_FEATURE_FP16_SCALAR_ARITHMETIC", "1");
 
   if (HasDotProd)
     Builder.defineMacro("__ARM_FEATURE_DOTPROD", "1");
@@ -644,7 +652,7 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions 
&Opts,
   if (HasMTE)
     Builder.defineMacro("__ARM_FEATURE_MEMORY_TAGGING", "1");
 
-  if (HasMatMul)
+  if (HasI8MM)
     Builder.defineMacro("__ARM_FEATURE_MATMUL_INT8", "1");
 
   if (HasLSE)
@@ -657,20 +665,20 @@ void AArch64TargetInfo::getTargetDefines(const 
LangOptions &Opts,
     Builder.defineMacro("__ARM_FEATURE_BF16_SCALAR_ARITHMETIC", "1");
   }
 
-  if ((FPU & SveMode) && HasBFloat16) {
+  if (HasSVE && HasBFloat16) {
     Builder.defineMacro("__ARM_FEATURE_SVE_BF16", "1");
   }
 
-  if ((FPU & SveMode) && HasMatmulFP64)
+  if (HasSVE && HasF64MM)
     Builder.defineMacro("__ARM_FEATURE_SVE_MATMUL_FP64", "1");
 
-  if ((FPU & SveMode) && HasMatmulFP32)
+  if (HasSVE && HasF32MM)
     Builder.defineMacro("__ARM_FEATURE_SVE_MATMUL_FP32", "1");
 
-  if ((FPU & SveMode) && HasMatMul)
+  if (HasSVE && HasI8MM)
     Builder.defineMacro("__ARM_FEATURE_SVE_MATMUL_INT8", "1");
 
-  if ((FPU & NeonMode) && HasFP16FML)
+  if (HasNeon && HasFP16FML)
     Builder.defineMacro("__ARM_FEATURE_FP16_FML", "1");
 
   if (Opts.hasSignReturnAddress()) {
@@ -869,11 +877,19 @@ struct FeatureLookupBuilder {
 };
 
 void AArch64TargetInfo::computeFeatureLookup() {
+  const bool HasFP = FPU & FPUMode;
+  const bool HasNeon = FPU & NeonMode;
+  const bool HasSVE = FPU & SveMode;
+#define AARCH64_EXTENSION_FEATURE(Name, Ext)                                   
\
+  [[maybe_unused]] const bool Name = hasExtension(llvm::AArch64::AEK_##Ext);
+#include "AArch64TargetInfoFeatures.inc"
+#undef AARCH64_EXTENSION_FEATURE
+
   FeatureLookupBuilder(HasFeatureLookup)
       .Cases({"aarch64", "arm64", "arm"}, true)
       .Case("fmv", HasFMV)
-      .Case("fp", FPU & FPUMode)
-      .Cases({"neon", "simd"}, FPU & NeonMode)
+      .Case("fp", HasFP)
+      .Cases({"neon", "simd"}, HasNeon)
       .Case("jscvt", HasJSCVT)
       .Case("fcma", HasFCMA)
       .Case("rng", HasRandGen)
@@ -889,24 +905,24 @@ void AArch64TargetInfo::computeFeatureLookup() {
       .Case("sha2", HasSHA2)
       .Case("sha3", HasSHA3)
       .Cases({"aes", "pmull"}, HasAES)
-      .Cases({"fp16", "fullfp16"}, HasFullFP16)
+      .Cases({"fp16", "fullfp16"}, hasFullFP16())
       .Case("dit", HasDIT)
       .Case("dpb", HasCCPP)
       .Case("dpb2", HasCCDP)
       .Case("rcpc", HasRCPC)
       .Case("frintts", HasFRInt3264)
-      .Case("i8mm", HasMatMul)
+      .Case("i8mm", HasI8MM)
       .Case("bf16", HasBFloat16)
-      .Case("sve", FPU & SveMode)
+      .Case("sve", HasSVE)
       .Case("sve-b16b16", HasSVEB16B16)
-      .Case("f32mm", FPU & SveMode && HasMatmulFP32)
-      .Case("f64mm", FPU & SveMode && HasMatmulFP64)
-      .Case("sve2", FPU & SveMode && HasSVE2)
+      .Case("f32mm", HasSVE && HasF32MM)
+      .Case("f64mm", HasSVE && HasF64MM)
+      .Case("sve2", HasSVE && HasSVE2)
       .Case("sve-aes", HasSVEAES)
       .Case("sve-bitperm", FPU & HasSVEBitPerm)
-      .Case("sve2-sha3", FPU & SveMode && HasSVE2SHA3)
-      .Case("sve2-sm4", FPU & SveMode && HasSVE2SM4)
-      .Case("sve2p1", FPU & SveMode && HasSVE2p1)
+      .Case("sve2-sha3", HasSVE && HasSVE2SHA3)
+      .Case("sve2-sm4", HasSVE && HasSVE2SM4)
+      .Case("sve2p1", HasSVE && HasSVE2p1)
       .Case("sme", HasSME)
       .Case("sme2", HasSME2)
       .Case("sme2p1", HasSME2p1)
@@ -939,7 +955,7 @@ void AArch64TargetInfo::computeFeatureLookup() {
       .Case("sve-bfscale", HasSVE_BFSCALE)
       .Case("sve-aes2", HasSVE_AES2)
       .Case("ssve-aes", HasSSVE_AES)
-      .Case("sve2p2", FPU & SveMode && HasSVE2p2)
+      .Case("sve2p2", HasSVE && HasSVE2p2)
       .Case("sme2p2", HasSME2p2);
 }
 
@@ -947,6 +963,142 @@ bool AArch64TargetInfo::hasFeature(StringRef Feature) 
const {
   return HasFeatureLookup.contains(Feature);
 }
 
+bool AArch64TargetInfo::hasExtension(llvm::AArch64::ArchExtKind Ext) const {
+  return EnabledExtensions.test(Ext);
+}
+
+bool AArch64TargetInfo::hasPAuth() const {
+  return hasExtension(llvm::AArch64::AEK_PAUTH) ||
+         hasExtension(llvm::AArch64::AEK_PAUTHLR);
+}
+
+bool AArch64TargetInfo::hasFullFP16() const {
+  return hasExtension(llvm::AArch64::AEK_FP16) ||
+         hasExtension(llvm::AArch64::AEK_SVEAES) ||
+         hasExtension(llvm::AArch64::AEK_SVEBITPERM);
+}
+
+// Find the most specific explicit architecture feature in a target-feature
+// list, e.g. "+v8.6a +v9.2a +sve2" would return the ArchInfo for v9.2a.
+static std::optional<llvm::AArch64::ArchInfo>
+findExplicitBaseArchForTargetFeatures(ArrayRef<std::string> Features) {
+  std::optional<llvm::AArch64::ArchInfo> BaseArch;
+  for (const std::string &Feature : Features) {
+    StringRef Name = Feature;
+    if (!Name.starts_with("+"))
+      continue;
+    if (std::optional<llvm::AArch64::ArchInfo> Candidate =
+            llvm::AArch64::ArchInfo::findBySubArch(Name.drop_front())) {
+      if (!BaseArch || Candidate->Profile != BaseArch->Profile ||
+          Candidate->Version > BaseArch->Version)
+        BaseArch = Candidate;
+    }
+  }
+  return BaseArch;
+}
+
+// Map the frontend's legacy target-feature spellings onto the backend
+// extension names before consulting the AArch64 extension graph.
+static StringRef canonicalizeExtensionLookupFeature(StringRef Feature) {
+  return llvm::StringSwitch<StringRef>(Feature)
+      .Case("+fcma", "+complxnum")
+      .Case("-fcma", "-complxnum")
+      .Case("+jscvt", "+jsconv")
+      .Case("-jscvt", "-jsconv")
+      .Default(Feature);
+}
+
+static std::optional<llvm::AArch64::ExtensionInfo>
+lookupExtensionForTargetFeature(StringRef Feature) {
+  return llvm::AArch64::targetFeatureToExtension(
+      canonicalizeExtensionLookupFeature(Feature));
+}
+
+static std::optional<llvm::AArch64::ExtensionInfo>
+lookupExtensionForFeatureName(StringRef Name) {
+  return lookupExtensionForTargetFeature(("+" + Name).str());
+}
+
+// Direct feature spellings that historically force Clang's NEON-facing FPU
+// state.
+static bool enablesNeonFPUCompat(StringRef Feature) {
+  return llvm::StringSwitch<bool>(Feature)
+      .Cases({"+neon", "+simd", "+fp-armv8", "+jscvt", "+jsconv"}, true)
+      .Cases({"+fcma", "+fullfp16", "+dotprod", "+fp16fml"}, true)
+      .Cases({"+aes", "+sha2", "+sha3", "+sm4", "+rdm"}, true)
+      .Default(false);
+}
+
+// Rebuild a temporary extension set from the frontend feature map so AArch64
+// implied-feature queries can follow the extension dependency graph.
+static llvm::AArch64::ExtensionSet
+buildExtensionSetFromFeatureMap(const llvm::StringMap<bool> &Features) {
+  llvm::AArch64::ExtensionSet FeatureBits;
+  SmallVector<llvm::AArch64::ArchInfo, 4> EnabledArchs;
+  SmallVector<llvm::AArch64::ArchExtKind, 16> ExplicitEnables;
+  SmallVector<llvm::AArch64::ArchExtKind, 16> ExplicitDisables;
+
+  for (const auto &Feature : Features) {
+    if (std::optional<llvm::AArch64::ArchInfo> AI =
+            llvm::AArch64::ArchInfo::findBySubArch(Feature.getKey())) {
+      if (Feature.getValue())
+        EnabledArchs.push_back(*AI);
+      continue;
+    }
+
+    std::string TargetFeature =
+        (Feature.getValue() ? "+" : "-") + Feature.getKey().str();
+    if (auto ExtInfo = lookupExtensionForTargetFeature(TargetFeature)) {
+      if (Feature.getValue())
+        ExplicitEnables.push_back(ExtInfo->ID);
+      else
+        ExplicitDisables.push_back(ExtInfo->ID);
+    }
+  }
+
+  for (const llvm::AArch64::ArchInfo &AI : EnabledArchs)
+    FeatureBits.addArchDefaults(AI);
+  for (llvm::AArch64::ArchExtKind Ext : ExplicitEnables)
+    FeatureBits.enable(Ext);
+  for (llvm::AArch64::ArchExtKind Ext : ExplicitDisables)
+    FeatureBits.disable(Ext);
+
+  return FeatureBits;
+}
+
+// Synchronize the frontend's cached booleans and FPU mode bits from the
+// expanded extension bitset, then reapply Clang-specific compatibility rules
+// that are not represented directly in the extension graph
+void AArch64TargetInfo::setFeatureStateFromEnabledExtensions(
+    const llvm::AArch64::ExtensionBitset &Exts) {
+
+  EnabledExtensions = Exts;
+  const bool HasSVEAES = hasExtension(llvm::AArch64::AEK_SVEAES);
+  const bool HasSVEBitPerm = hasExtension(llvm::AArch64::AEK_SVEBITPERM);
+
+  // clear the cached FPU mode bits (FPUMode, NeonMode, SveMode)
+  FPU &= ~(FPUMode | NeonMode | SveMode);
+
+  // re-enable FPUMode if the fp extension is present
+  if (EnabledExtensions.test(llvm::AArch64::AEK_FP))
+    FPU |= FPUMode;
+
+  // re-enable SveMode if the sve extension is present
+  if (EnabledExtensions.test(llvm::AArch64::AEK_SVE))
+    FPU |= SveMode;
+
+  // Frontend FPU mode historically treats SVE as also enabling AdvSIMD, even
+  // though that dependency is not modeled as an architecture extension.
+  if (FPU & SveMode)
+    FPU |= NeonMode;
+
+  // Keep the frontend's historical FPU compatibility for explicit feature
+  // strings such as +aes, +jscvt and +fullfp16 that are not pure ext-bit 
logic.
+  FPU |= ExplicitFPUCompat & (NeonMode | SveMode);
+  if (HasSVEAES || HasSVEBitPerm)
+    FPU |= NeonMode;
+}
+
 void AArch64TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
                                           StringRef Name, bool Enabled) const {
   Features[Name] = Enabled;
@@ -976,221 +1128,78 @@ void 
AArch64TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
   }
 }
 
+// Reconstruct enough of the AArch64 extension graph to answer implied-feature
+// queries without over-expanding the generic frontend feature map.
+bool AArch64TargetInfo::hasFeatureEnabled(const llvm::StringMap<bool> 
&Features,
+                                          StringRef Name) const {
+  auto QueryExt = lookupExtensionForFeatureName(Name);
+  if (!QueryExt)
+    return TargetInfo::hasFeatureEnabled(Features, Name);
+
+  llvm::AArch64::ExtensionSet FeatureBits =
+      buildExtensionSetFromFeatureMap(Features);
+  return FeatureBits.Enabled.test(QueryExt->ID);
+}
+
 bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> 
&Features,
                                              DiagnosticsEngine &Diags) {
-  for (const auto &Feature : Features) {
+  llvm::AArch64::ExtensionSet FeatureBits;
+  ExplicitFPUCompat = 0;
+  FeatureBits.enable(llvm::AArch64::AEK_FP);
+
+  if (std::optional<llvm::AArch64::ArchInfo> BaseArch =
+          findExplicitBaseArchForTargetFeatures(Features)) {
+    FeatureBits.addArchDefaults(*BaseArch);
+    if (BaseArch->DefaultExts.test(llvm::AArch64::AEK_SIMD))
+      ExplicitFPUCompat |= NeonMode;
+    if (BaseArch->DefaultExts.test(llvm::AArch64::AEK_SVE))
+      ExplicitFPUCompat |= SveMode;
+  }
+
+  std::vector<std::string> ExpandedFeatures;
+  ExpandedFeatures.reserve(Features.size());
+
+  for (const std::string &Feature : Features) {
+    if (enablesNeonFPUCompat(Feature))
+      ExplicitFPUCompat |= NeonMode;
+
+    if (auto ExtInfo = lookupExtensionForTargetFeature(Feature)) {
+      if (!Feature.empty() && Feature[0] == '+')
+        FeatureBits.enable(ExtInfo->ID);
+      else if (!Feature.empty() && Feature[0] == '-') {
+        switch (ExtInfo->ID) {
+        case llvm::AArch64::AEK_FP:
+          HasNoFP = true;
+          break;
+        case llvm::AArch64::AEK_SIMD:
+          HasNoNeon = true;
+          break;
+        case llvm::AArch64::AEK_SVE:
+          HasNoSVE = true;
+          break;
+        default:
+          break;
+        }
+        FeatureBits.disable(ExtInfo->ID);
+      }
+      continue;
+    }
+    ExpandedFeatures.push_back(Feature);
+  }
+  FeatureBits.toLLVMFeatureList(ExpandedFeatures);
+  llvm::sort(ExpandedFeatures);
+
+  for (const auto &Feature : ExpandedFeatures) {
     if (Feature == "-fp-armv8")
       HasNoFP = true;
     if (Feature == "-neon")
       HasNoNeon = true;
     if (Feature == "-sve")
       HasNoSVE = true;
-
-    if (Feature == "+neon" || Feature == "+fp-armv8")
-      FPU |= NeonMode;
-    if (Feature == "+jscvt") {
-      HasJSCVT = true;
-      FPU |= NeonMode;
-    }
-    if (Feature == "+fcma") {
-      HasFCMA = true;
-      FPU |= NeonMode;
-    }
-
-    if (Feature == "+sve") {
-      FPU |= NeonMode;
-      FPU |= SveMode;
-      HasFullFP16 = true;
-    }
-    if (Feature == "+sve2") {
-      FPU |= NeonMode;
-      FPU |= SveMode;
-      HasFullFP16 = true;
-      HasSVE2 = true;
-    }
-    if (Feature == "+sve2p1") {
-      FPU |= NeonMode;
-      FPU |= SveMode;
-      HasFullFP16 = true;
-      HasSVE2 = true;
-      HasSVE2p1 = true;
-    }
-    if (Feature == "+sve-aes") {
-      FPU |= NeonMode;
-      HasFullFP16 = true;
-      HasSVEAES = true;
-    }
-    if (Feature == "+sve2-sha3") {
-      FPU |= NeonMode;
-      FPU |= SveMode;
-      HasFullFP16 = true;
-      HasSVE2 = true;
-      HasSVE2SHA3 = true;
-    }
-    if (Feature == "+sve2-sm4") {
-      FPU |= NeonMode;
-      FPU |= SveMode;
-      HasFullFP16 = true;
-      HasSVE2 = true;
-      HasSVE2SM4 = true;
-    }
-    if (Feature == "+sve-b16b16")
-      HasSVEB16B16 = true;
-    if (Feature == "+sve-bitperm") {
-      FPU |= NeonMode;
-      HasFullFP16 = true;
-      HasSVEBitPerm = true;
-    }
-    if (Feature == "+f32mm") {
-      FPU |= NeonMode;
-      FPU |= SveMode;
-      HasFullFP16 = true;
-      HasMatmulFP32 = true;
-    }
-    if (Feature == "+f64mm") {
-      FPU |= NeonMode;
-      FPU |= SveMode;
-      HasFullFP16 = true;
-      HasMatmulFP64 = true;
-    }
-    if (Feature == "+sme") {
-      HasSME = true;
-      HasBFloat16 = true;
-      HasFullFP16 = true;
-    }
-    if (Feature == "+sme2") {
-      HasSME = true;
-      HasSME2 = true;
-      HasBFloat16 = true;
-      HasFullFP16 = true;
-    }
-    if (Feature == "+sme2p1") {
-      HasSME = true;
-      HasSME2 = true;
-      HasSME2p1 = true;
-      HasBFloat16 = true;
-      HasFullFP16 = true;
-    }
-    if (Feature == "+sme-f64f64") {
-      HasSME = true;
-      HasSMEF64F64 = true;
-      HasBFloat16 = true;
-      HasFullFP16 = true;
-    }
-    if (Feature == "+sme-i16i64") {
-      HasSME = true;
-      HasSMEI16I64 = true;
-      HasBFloat16 = true;
-      HasFullFP16 = true;
-    }
-    if (Feature == "+sme-fa64") {
-      FPU |= NeonMode;
-      FPU |= SveMode;
-      HasSME = true;
-      HasSVE2 = true;
-      HasSMEFA64 = true;
-    }
-    if (Feature == "+sme-f16f16") {
-      HasSME = true;
-      HasSME2 = true;
-      HasBFloat16 = true;
-      HasFullFP16 = true;
-      HasSMEF16F16 = true;
-    }
-    if (Feature == "+sme-b16b16") {
-      HasSME = true;
-      HasSME2 = true;
-      HasBFloat16 = true;
-      HasFullFP16 = true;
-      HasSVEB16B16 = true;
-      HasSMEB16B16 = true;
-    }
-
-    if (Feature == "+fp8")
-      HasFP8 = true;
-    if (Feature == "+fp8fma")
-      HasFP8FMA = true;
-    if (Feature == "+fp8dot2")
-      HasFP8DOT2 = true;
-    if (Feature == "+fp8dot4")
-      HasFP8DOT4 = true;
-    if (Feature == "+ssve-fp8dot2")
-      HasSSVE_FP8DOT2 = true;
-    if (Feature == "+ssve-fp8dot4")
-      HasSSVE_FP8DOT4 = true;
-    if (Feature == "+ssve-fp8fma")
-      HasSSVE_FP8FMA = true;
-    if (Feature == "+sme-f8f32")
-      HasSME_F8F32 = true;
-    if (Feature == "+sme-f8f16")
-      HasSME_F8F16 = true;
-    if (Feature == "+sb")
-      HasSB = true;
-    if (Feature == "+predres")
-      HasPredRes = true;
-    if (Feature == "+ssbs")
-      HasSSBS = true;
-    if (Feature == "+bti")
-      HasBTI = true;
-    if (Feature == "+wfxt")
-      HasWFxT = true;
     if (Feature == "-fmv")
       HasFMV = false;
-    if (Feature == "+crc")
-      HasCRC = true;
-    if (Feature == "+rcpc")
-      HasRCPC = true;
-    if (Feature == "+aes") {
-      FPU |= NeonMode;
-      HasAES = true;
-    }
-    if (Feature == "+sha2") {
-      FPU |= NeonMode;
-      HasSHA2 = true;
-    }
-    if (Feature == "+sha3") {
-      FPU |= NeonMode;
-      HasSHA2 = true;
-      HasSHA3 = true;
-    }
-    if (Feature == "+rdm") {
-      FPU |= NeonMode;
-      HasRDM = true;
-    }
-    if (Feature == "+dit")
-      HasDIT = true;
-    if (Feature == "+cccp")
-      HasCCPP = true;
-    if (Feature == "+ccdp") {
-      HasCCPP = true;
-      HasCCDP = true;
-    }
-    if (Feature == "+fptoint")
-      HasFRInt3264 = true;
-    if (Feature == "+sm4") {
-      FPU |= NeonMode;
-      HasSM4 = true;
-    }
     if (Feature == "+strict-align")
       HasUnalignedAccess = false;
-    if (Feature == "+fprcvt")
-      HasFPRCVT = true;
-    if (Feature == "+f8f16mm")
-      HasF8F16MM = true;
-    if (Feature == "+f8f32mm")
-      HasF8F32MM = true;
-    if (Feature == "+sve-f16f32mm")
-      HasSVE_F16F32MM = true;
-    if (Feature == "+sve-bfscale")
-      HasSVE_BFSCALE = true;
-    if (Feature == "+sve-aes2")
-      HasSVE_AES2 = true;
-    if (Feature == "+ssve-aes")
-      HasSSVE_AES = true;
-    if (Feature == "+sve2p2")
-      HasSVE2p2 = true;
-    if (Feature == "+sme2p2")
-      HasSME2p2 = true;
 
     // All predecessor archs are added but select the latest one for ArchKind.
     if (Feature == "+v8a" && ArchInfo->Version < llvm::AArch64::ARMV8A.Version)
@@ -1247,62 +1256,9 @@ bool 
AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
       ArchInfo = &llvm::AArch64::ARMV9_7A;
     if (Feature == "+v8r")
       ArchInfo = &llvm::AArch64::ARMV8R;
-    if (Feature == "+fullfp16") {
-      FPU |= NeonMode;
-      HasFullFP16 = true;
-    }
-    if (Feature == "+dotprod") {
-      FPU |= NeonMode;
-      HasDotProd = true;
-    }
-    if (Feature == "+fp16fml") {
-      FPU |= NeonMode;
-      HasFullFP16 = true;
-      HasFP16FML = true;
-    }
-    if (Feature == "+mte")
-      HasMTE = true;
-    if (Feature == "+pauth")
-      HasPAuth = true;
-    if (Feature == "+i8mm")
-      HasMatMul = true;
-    if (Feature == "+bf16")
-      HasBFloat16 = true;
-    if (Feature == "+lse")
-      HasLSE = true;
-    if (Feature == "+ls64")
-      HasLS64 = true;
-    if (Feature == "+rand")
-      HasRandGen = true;
-    if (Feature == "+flagm")
-      HasFlagM = true;
-    if (Feature == "+altnzcv") {
-      HasFlagM = true;
-      HasAlternativeNZCV = true;
-    }
-    if (Feature == "+mops")
-      HasMOPS = true;
-    if (Feature == "+d128")
-      HasD128 = true;
-    if (Feature == "+gcs")
-      HasGCS = true;
-    if (Feature == "+rcpc3")
-      HasRCPC3 = true;
-    if (Feature == "+pauth-lr") {
-      HasPAuthLR = true;
-      HasPAuth = true;
-    }
-    if (Feature == "+cssc")
-      HasCSSC = true;
   }
 
-  // Check features that are manually disabled by command line options.
-  // This needs to be checked after architecture-related features are handled,
-  // making sure they are properly disabled when required.
-  for (const auto &Feature : Features) {
-    if (Feature == "-d128")
-      HasD128 = false;
-  }
+  setFeatureStateFromEnabledExtensions(FeatureBits.Enabled);
 
   resetDataLayout();
 
@@ -1678,6 +1634,7 @@ bool AArch64TargetInfo::validateConstraintModifier(
     return true;
   case 'z':
   case 'r': {
+    const bool HasLS64 = hasExtension(llvm::AArch64::AEK_LS64);
     switch (Modifier) {
     case 'x':
     case 'w':
diff --git a/clang/lib/Basic/Targets/AArch64.h 
b/clang/lib/Basic/Targets/AArch64.h
index 0a29bad81939b..b0c1fcedbc183 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -69,87 +69,23 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public 
TargetInfo {
   };
 
   unsigned FPU = FPUMode;
-  bool HasCRC = false;
-  bool HasCSSC = false;
-  bool HasAES = false;
-  bool HasSHA2 = false;
-  bool HasSHA3 = false;
-  bool HasSM4 = false;
-  bool HasFullFP16 = false;
-  bool HasDotProd = false;
-  bool HasFP16FML = false;
-  bool HasMTE = false;
-  bool HasPAuth = false;
-  bool HasLS64 = false;
-  bool HasRandGen = false;
-  bool HasMatMul = false;
-  bool HasBFloat16 = false;
-  bool HasSVE2 = false;
-  bool HasSVE2p1 = false;
-  bool HasSVEAES = false;
-  bool HasSVE2SHA3 = false;
-  bool HasSVE2SM4 = false;
-  bool HasSVEB16B16 = false;
-  bool HasSVEBitPerm = false;
-  bool HasMatmulFP64 = false;
-  bool HasMatmulFP32 = false;
-  bool HasLSE = false;
-  bool HasFlagM = false;
-  bool HasAlternativeNZCV = false;
-  bool HasMOPS = false;
-  bool HasD128 = false;
-  bool HasRCPC = false;
-  bool HasRDM = false;
-  bool HasDIT = false;
-  bool HasCCPP = false;
-  bool HasCCDP = false;
-  bool HasFRInt3264 = false;
-  bool HasSME = false;
-  bool HasSME2 = false;
-  bool HasSMEF64F64 = false;
-  bool HasSMEI16I64 = false;
-  bool HasSMEF16F16 = false;
-  bool HasSMEB16B16 = false;
-  bool HasSME2p1 = false;
-  bool HasFP8 = false;
-  bool HasFP8FMA = false;
-  bool HasFP8DOT2 = false;
-  bool HasFP8DOT4 = false;
-  bool HasSSVE_FP8DOT2 = false;
-  bool HasSSVE_FP8DOT4 = false;
-  bool HasSSVE_FP8FMA = false;
-  bool HasSME_F8F32 = false;
-  bool HasSME_F8F16 = false;
-  bool HasSB = false;
-  bool HasPredRes = false;
-  bool HasSSBS = false;
-  bool HasBTI = false;
-  bool HasWFxT = false;
-  bool HasJSCVT = false;
-  bool HasFCMA = false;
+  llvm::AArch64::ExtensionBitset EnabledExtensions;
+  unsigned ExplicitFPUCompat = 0;
   bool HasNoFP = false;
   bool HasNoNeon = false;
   bool HasNoSVE = false;
   bool HasFMV = true;
-  bool HasGCS = false;
-  bool HasRCPC3 = false;
-  bool HasSMEFA64 = false;
-  bool HasPAuthLR = false;
-  bool HasFPRCVT = false;
-  bool HasF8F16MM = false;
-  bool HasF8F32MM = false;
-  bool HasSVE_F16F32MM = false;
-  bool HasSVE_BFSCALE = false;
-  bool HasSVE_AES2 = false;
-  bool HasSSVE_AES = false;
-  bool HasSVE2p2 = false;
-  bool HasSME2p2 = false;
 
   const llvm::AArch64::ArchInfo *ArchInfo = &llvm::AArch64::ARMV8A;
 
   AArch64FeatureSet HasFeatureLookup;
 
   void computeFeatureLookup();
+  bool hasExtension(llvm::AArch64::ArchExtKind Ext) const;
+  bool hasPAuth() const;
+  bool hasFullFP16() const;
+  void setFeatureStateFromEnabledExtensions(
+      const llvm::AArch64::ExtensionBitset &EnabledExtensions);
 
 protected:
   std::string ABI;
@@ -159,6 +95,8 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public 
TargetInfo {
 
   StringRef getABI() const override;
   bool setABI(const std::string &Name) override;
+  bool hasFeatureEnabled(const llvm::StringMap<bool> &Features,
+                         StringRef Name) const override;
 
   bool validateBranchProtection(StringRef Spec, StringRef Arch,
                                 BranchProtectionInfo &BPI,
diff --git a/clang/lib/Basic/Targets/AArch64TargetInfoFeatures.inc 
b/clang/lib/Basic/Targets/AArch64TargetInfoFeatures.inc
new file mode 100644
index 0000000000000..018866eafb6ef
--- /dev/null
+++ b/clang/lib/Basic/Targets/AArch64TargetInfoFeatures.inc
@@ -0,0 +1,69 @@
+AARCH64_EXTENSION_FEATURE(HasJSCVT, JSCVT)
+AARCH64_EXTENSION_FEATURE(HasFCMA, FCMA)
+AARCH64_EXTENSION_FEATURE(HasRandGen, RAND)
+AARCH64_EXTENSION_FEATURE(HasFlagM, FLAGM)
+AARCH64_EXTENSION_FEATURE(HasAlternativeNZCV, ALTERNATIVENZCV)
+AARCH64_EXTENSION_FEATURE(HasFP16FML, FP16FML)
+AARCH64_EXTENSION_FEATURE(HasDotProd, DOTPROD)
+AARCH64_EXTENSION_FEATURE(HasSM4, SM4)
+AARCH64_EXTENSION_FEATURE(HasRDM, RDM)
+AARCH64_EXTENSION_FEATURE(HasLSE, LSE)
+AARCH64_EXTENSION_FEATURE(HasCRC, CRC)
+AARCH64_EXTENSION_FEATURE(HasCSSC, CSSC)
+AARCH64_EXTENSION_FEATURE(HasSHA2, SHA2)
+AARCH64_EXTENSION_FEATURE(HasSHA3, SHA3)
+AARCH64_EXTENSION_FEATURE(HasAES, AES)
+AARCH64_EXTENSION_FEATURE(HasDIT, DIT)
+AARCH64_EXTENSION_FEATURE(HasCCPP, CCPP)
+AARCH64_EXTENSION_FEATURE(HasCCDP, CCDP)
+AARCH64_EXTENSION_FEATURE(HasRCPC, RCPC)
+AARCH64_EXTENSION_FEATURE(HasFRInt3264, FRINT3264)
+AARCH64_EXTENSION_FEATURE(HasI8MM, I8MM)
+AARCH64_EXTENSION_FEATURE(HasBFloat16, BF16)
+AARCH64_EXTENSION_FEATURE(HasSVEB16B16, SVEB16B16)
+AARCH64_EXTENSION_FEATURE(HasF32MM, F32MM)
+AARCH64_EXTENSION_FEATURE(HasF64MM, F64MM)
+AARCH64_EXTENSION_FEATURE(HasSVE2, SVE2)
+AARCH64_EXTENSION_FEATURE(HasSVEAES, SVEAES)
+AARCH64_EXTENSION_FEATURE(HasSVEBitPerm, SVEBITPERM)
+AARCH64_EXTENSION_FEATURE(HasSVE2SHA3, SVE2SHA3)
+AARCH64_EXTENSION_FEATURE(HasSVE2SM4, SVE2SM4)
+AARCH64_EXTENSION_FEATURE(HasSVE2p1, SVE2P1)
+AARCH64_EXTENSION_FEATURE(HasSME, SME)
+AARCH64_EXTENSION_FEATURE(HasSME2, SME2)
+AARCH64_EXTENSION_FEATURE(HasSME2p1, SME2P1)
+AARCH64_EXTENSION_FEATURE(HasSMEF64F64, SMEF64F64)
+AARCH64_EXTENSION_FEATURE(HasSMEI16I64, SMEI16I64)
+AARCH64_EXTENSION_FEATURE(HasSMEFA64, SMEFA64)
+AARCH64_EXTENSION_FEATURE(HasSMEF16F16, SMEF16F16)
+AARCH64_EXTENSION_FEATURE(HasSMEB16B16, SMEB16B16)
+AARCH64_EXTENSION_FEATURE(HasMTE, MTE)
+AARCH64_EXTENSION_FEATURE(HasSB, SB)
+AARCH64_EXTENSION_FEATURE(HasPredRes, PREDRES)
+AARCH64_EXTENSION_FEATURE(HasSSBS, SSBS)
+AARCH64_EXTENSION_FEATURE(HasBTI, BTI)
+AARCH64_EXTENSION_FEATURE(HasLS64, LS64)
+AARCH64_EXTENSION_FEATURE(HasWFxT, WFXT)
+AARCH64_EXTENSION_FEATURE(HasRCPC3, RCPC3)
+AARCH64_EXTENSION_FEATURE(HasFP8, FP8)
+AARCH64_EXTENSION_FEATURE(HasFP8FMA, FP8FMA)
+AARCH64_EXTENSION_FEATURE(HasFP8DOT2, FP8DOT2)
+AARCH64_EXTENSION_FEATURE(HasFP8DOT4, FP8DOT4)
+AARCH64_EXTENSION_FEATURE(HasSSVE_FP8DOT2, SSVE_FP8DOT2)
+AARCH64_EXTENSION_FEATURE(HasSSVE_FP8DOT4, SSVE_FP8DOT4)
+AARCH64_EXTENSION_FEATURE(HasSSVE_FP8FMA, SSVE_FP8FMA)
+AARCH64_EXTENSION_FEATURE(HasSME_F8F32, SMEF8F32)
+AARCH64_EXTENSION_FEATURE(HasSME_F8F16, SMEF8F16)
+AARCH64_EXTENSION_FEATURE(HasFPRCVT, FPRCVT)
+AARCH64_EXTENSION_FEATURE(HasF8F16MM, F8F16MM)
+AARCH64_EXTENSION_FEATURE(HasF8F32MM, F8F32MM)
+AARCH64_EXTENSION_FEATURE(HasSVE_F16F32MM, SVE_F16F32MM)
+AARCH64_EXTENSION_FEATURE(HasSVE_BFSCALE, SVE_BFSCALE)
+AARCH64_EXTENSION_FEATURE(HasSVE_AES2, SVE_AES2)
+AARCH64_EXTENSION_FEATURE(HasSSVE_AES, SSVE_AES)
+AARCH64_EXTENSION_FEATURE(HasSVE2p2, SVE2P2)
+AARCH64_EXTENSION_FEATURE(HasSME2p2, SME2P2)
+AARCH64_EXTENSION_FEATURE(HasPAuthLR, PAUTHLR)
+AARCH64_EXTENSION_FEATURE(HasMOPS, MOPS)
+AARCH64_EXTENSION_FEATURE(HasD128, D128)
+AARCH64_EXTENSION_FEATURE(HasGCS, GCS)
diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp
index e54c8228e5ff8..be07d2e81aa50 100644
--- a/clang/lib/Sema/SemaARM.cpp
+++ b/clang/lib/Sema/SemaARM.cpp
@@ -1571,7 +1571,7 @@ void SemaARM::CheckSMEFunctionDefAttributes(const 
FunctionDecl *FD) {
   if (UsesSM || UsesZA) {
     llvm::StringMap<bool> FeatureMap;
     Context.getFunctionFeatureMap(FeatureMap, FD);
-    if (!FeatureMap.contains("sme")) {
+    if (!Context.getTargetInfo().hasFeatureEnabled(FeatureMap, "sme")) {
       if (UsesSM)
         Diag(FD->getLocation(),
              diag::err_sme_definition_using_sm_in_non_sme_target);
@@ -1583,7 +1583,7 @@ void SemaARM::CheckSMEFunctionDefAttributes(const 
FunctionDecl *FD) {
   if (UsesZT0) {
     llvm::StringMap<bool> FeatureMap;
     Context.getFunctionFeatureMap(FeatureMap, FD);
-    if (!FeatureMap.contains("sme2")) {
+    if (!Context.getTargetInfo().hasFeatureEnabled(FeatureMap, "sme2")) {
       Diag(FD->getLocation(),
            diag::err_sme_definition_using_zt0_in_non_sme2_target);
     }
@@ -1862,7 +1862,7 @@ bool SemaARM::checkSVETypeSupport(QualType Ty, 
SourceLocation Loc,
     return false;
 
   // No SVE environment available.
-  if (!FeatureMap.lookup("sme"))
+  if (!getASTContext().getTargetInfo().hasFeatureEnabled(FeatureMap, "sme"))
     return Diag(Loc, diag::err_sve_vector_in_non_sve_target) << Ty;
 
   // SVE environment only available to streaming functions.
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index d53c3b6ab2674..12cabce5c4385 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -4265,7 +4265,7 @@ void Sema::checkCall(NamedDecl *FDecl, const 
FunctionProtoType *Proto,
       if (auto *CallerFD = dyn_cast<FunctionDecl>(CurContext)) {
         llvm::StringMap<bool> CallerFeatureMap;
         Context.getFunctionFeatureMap(CallerFeatureMap, CallerFD);
-        if (!CallerFeatureMap.contains("sme"))
+        if (!Context.getTargetInfo().hasFeatureEnabled(CallerFeatureMap, 
"sme"))
           Diag(Loc, diag::err_sme_call_in_non_sme_target);
       } else if (!Context.getTargetInfo().hasFeature("sme")) {
         Diag(Loc, diag::err_sme_call_in_non_sme_target);
diff --git a/clang/test/Preprocessor/aarch64-target-features.c 
b/clang/test/Preprocessor/aarch64-target-features.c
index 60ddaad639d48..41393e423f17f 100644
--- a/clang/test/Preprocessor/aarch64-target-features.c
+++ b/clang/test/Preprocessor/aarch64-target-features.c
@@ -235,6 +235,7 @@
 
 // RUN: %clang -target aarch64-none-linux-gnu -march=armv8-a+sve2-aes -x c -E 
-dM %s -o - | FileCheck --check-prefix=CHECK-SVE2AES %s
 // RUN: %clang -target aarch64-none-linux-gnu -march=armv8-a+sve-aes+sve2 -x c 
-E -dM %s -o - | FileCheck --check-prefix=CHECK-SVE2AES %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve2-aes -x 
c -E -dM %s -o - | FileCheck --check-prefix=CHECK-SVE2AES %s
 // CHECK-SVE2AES: __ARM_FEATURE_AES 1
 // CHECK-SVE2AES: __ARM_FEATURE_SVE2 1
 // CHECK-SVE2AES: __ARM_FEATURE_SVE2_AES 1
@@ -253,10 +254,12 @@
 
 // RUN: %clang -target aarch64-none-linux-gnu -march=armv8-a+sve2-bitperm -x c 
-E -dM %s -o - | FileCheck --check-prefix=CHECK-SVE2BITPERM %s
 // RUN: %clang -target aarch64-none-linux-gnu -march=armv8-a+sve-bitperm+sve2 
-x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-SVE2BITPERM %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature 
+sve2-bitperm -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-SVE2BITPERM 
%s
 // CHECK-SVE2BITPERM: __ARM_FEATURE_SVE2 1
 // CHECK-SVE2BITPERM: __ARM_FEATURE_SVE2_BITPERM 1
 
 // RUN: %clang -target aarch64-none-linux-gnu -march=armv9-a+sve2p1 -x c -E 
-dM %s -o - | FileCheck --check-prefix=CHECK-SVE2p1 %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve2p1 -x c 
-E -dM %s -o - | FileCheck --check-prefix=CHECK-SVE2p1 %s
 // CHECK-SVE2p1: __ARM_FEATURE_FP16_SCALAR_ARITHMETIC 1
 // CHECK-SVE2p1: __ARM_FEATURE_FP16_VECTOR_ARITHMETIC 1
 // CHECK-SVE2p1: __ARM_FEATURE_SVE2 1
@@ -271,6 +274,16 @@
 // CHECK-DOTPROD: __ARM_NEON 1
 // CHECK-DOTPROD: __ARM_NEON_FP 0xE
 
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +jscvt -x c 
-E -dM %s -o - | FileCheck --check-prefix=CHECK-JSCVT-DIRECT %s
+// CHECK-JSCVT-DIRECT: #define __ARM_NEON 1
+// CHECK-JSCVT-DIRECT: #define __ARM_NEON_FP 0xE
+
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -x c -E 
-dM %s -o - | FileCheck --check-prefix=CHECK-SME-DIRECT %s
+// CHECK-SME-DIRECT-NOT: #define __ARM_NEON 1
+// CHECK-SME-DIRECT-NOT: #define __ARM_NEON_FP 0xE
+// CHECK-SME-DIRECT: #define __ARM_FEATURE_LOCALLY_STREAMING 1
+// CHECK-SME-DIRECT: #define __ARM_FEATURE_SME
+
 // On ARMv8.2-A and above, +fp16fml implies +fp16.
 // On ARMv8.4-A and above, +fp16 implies +fp16fml.
 // RUN: %clang --target=aarch64 -march=armv8.2-a+nofp16fml+fp16 -x c -E -dM %s 
-o - | FileCheck -match-full-lines --check-prefix=CHECK-FULLFP16-NOFML 
--check-prefix=CHECK-FULLFP16-VECTOR-SCALAR %s
@@ -283,12 +296,18 @@
 // RUN: %clang --target=aarch64 -march=armv8.4-a+fp16+nofp16fml -x c -E -dM %s 
-o - | FileCheck -match-full-lines --check-prefix=CHECK-FULLFP16-NOFML 
--check-prefix=CHECK-FULLFP16-VECTOR-SCALAR %s
 // RUN: %clang --target=aarch64 -march=armv8.4-a+fp16fml -x c -E -dM %s -o - | 
FileCheck -match-full-lines --check-prefix=CHECK-FULLFP16-FML 
--check-prefix=CHECK-FULLFP16-VECTOR-SCALAR %s
 // RUN: %clang --target=aarch64 -march=armv8.4-a+fp16 -x c -E -dM %s -o - | 
FileCheck -match-full-lines --check-prefix=CHECK-FULLFP16-FML 
--check-prefix=CHECK-FULLFP16-VECTOR-SCALAR %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +fullfp16 -x 
c -E -dM %s -o - | FileCheck -match-full-lines 
--check-prefix=CHECK-FULLFP16-DIRECT %s
 // CHECK-FULLFP16-FML:           #define __ARM_FEATURE_FP16_FML 1
 // CHECK-FULLFP16-NOFML-NOT:     #define __ARM_FEATURE_FP16_FML 1
 // CHECK-FULLFP16-VECTOR-SCALAR: #define __ARM_FEATURE_FP16_SCALAR_ARITHMETIC 1
 // CHECK-FULLFP16-VECTOR-SCALAR: #define __ARM_FEATURE_FP16_VECTOR_ARITHMETIC 1
 // CHECK-FULLFP16-VECTOR-SCALAR: #define __ARM_FP 0xE
 // CHECK-FULLFP16-VECTOR-SCALAR: #define __ARM_FP16_FORMAT_IEEE 1
+// CHECK-FULLFP16-DIRECT:        #define __ARM_FEATURE_FP16_SCALAR_ARITHMETIC 1
+// CHECK-FULLFP16-DIRECT:        #define __ARM_FEATURE_FP16_VECTOR_ARITHMETIC 1
+// CHECK-FULLFP16-DIRECT:        #define __ARM_FP 0xE
+// CHECK-FULLFP16-DIRECT:        #define __ARM_FP16_FORMAT_IEEE 1
+// CHECK-FULLFP16-DIRECT:        #define __ARM_NEON 1
 
 // +fp16fml+nosimd doesn't make sense as the fp16fml instructions all require 
SIMD.
 // However, as +fp16fml implies +fp16 there is a set of defines that we would 
expect.
@@ -736,12 +755,14 @@
 // CHECK-SVEB16B16: __ARM_FEATURE_SVE_B16B16 1
 
 // RUN: %clang --target=aarch64 -march=armv9-a+sme-f16f16 -x c -E -dM %s -o - 
| FileCheck --check-prefix=CHECK-SMEF16F16 %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme-f16f16 
-x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-SMEF16F16 %s
 // CHECK-SMEF16F16: __ARM_FEATURE_LOCALLY_STREAMING 1
 // CHECK-SMEF16F16: __ARM_FEATURE_SME 1
 // CHECK-SMEF16F16: __ARM_FEATURE_SME2 1
 // CHECK-SMEF16F16: __ARM_FEATURE_SME_F16F16 1
 
 // RUN: %clang --target=aarch64 -march=armv9-a+sme-b16b16 -x c -E -dM %s -o - 
| FileCheck --check-prefix=CHECK-SMEB16B16 %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme-b16b16 
-x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-SMEB16B16 %s
 // CHECK-SMEB16B16: __ARM_FEATURE_LOCALLY_STREAMING 1
 // CHECK-SMEB16B16: __ARM_FEATURE_SME 1
 // CHECK-SMEB16B16: __ARM_FEATURE_SME2 1
@@ -818,6 +839,7 @@
 //  CHECK-SSVE-AES: __ARM_FEATURE_SVE2_AES 1
 
 // RUN: %clang -target aarch64-none-linux-gnu -march=armv9-a+sve2p2 -x c -E 
-dM %s -o - | FileCheck --check-prefix=CHECK-SVE2p2 %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve2p2 -x c 
-E -dM %s -o - | FileCheck --check-prefix=CHECK-SVE2p2 %s
 // CHECK-SVE2p2: __ARM_FEATURE_FP16_SCALAR_ARITHMETIC 1
 // CHECK-SVE2p2: __ARM_FEATURE_FP16_VECTOR_ARITHMETIC 1
 // CHECK-SVE2p2: __ARM_FEATURE_SVE2 1
diff --git a/clang/test/Sema/aarch64-sme-func-attrs-without-target-feature.cpp 
b/clang/test/Sema/aarch64-sme-func-attrs-without-target-feature.cpp
index 2ba266a93f94f..821c0082a3458 100644
--- a/clang/test/Sema/aarch64-sme-func-attrs-without-target-feature.cpp
+++ b/clang/test/Sema/aarch64-sme-func-attrs-without-target-feature.cpp
@@ -21,6 +21,11 @@ __arm_locally_streaming __attribute__((target("sme"))) void 
locally_streaming_de
 // Test that it also works with the target("sme2") attribute.
 __attribute__((target("sme2"))) void streaming_def_sme2_attr() __arm_streaming 
{ } // OK
 
+// Explicit target disables must win over arch/default SME implications.
+__attribute__((target("arch=armv9.3-a,no-sme"))) void 
streaming_def_arch_no_sme() __arm_streaming { } // expected-error {{function 
executed in streaming-SVE mode requires 'sme'}}
+__attribute__((target("sme2,no-sme"))) void streaming_def_sme2_no_sme() 
__arm_streaming { } // expected-error {{function executed in streaming-SVE mode 
requires 'sme'}}
+__attribute__((target("sme2,no-sme"))) void inout_zt0_def_sme2_no_sme() 
__arm_inout("zt0") { } // expected-error {{function using ZT0 state requires 
'sme2'}}
+
 // No code is generated for declarations, so it should be fine to declare 
using the attribute.
 void streaming_compatible_decl() __arm_streaming_compatible; // OK
 void streaming_decl() __arm_streaming; // OK

>From 82fa0a0cce4a4d53f556239f5bbb70ed55f6dd32 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <[email protected]>
Date: Wed, 8 Apr 2026 15:25:27 +0100
Subject: [PATCH 2/2] fixup! Don't checkin AArch64TargetInfoFeatures.inc but
 generate from tablegen

---
 clang/lib/Basic/Targets/AArch64.cpp           | 24 ++++---
 .../Targets/AArch64TargetInfoFeatures.inc     | 69 -------------------
 .../TableGen/Basic/ARMTargetDefEmitter.cpp    | 23 +++++++
 3 files changed, 39 insertions(+), 77 deletions(-)
 delete mode 100644 clang/lib/Basic/Targets/AArch64TargetInfoFeatures.inc

diff --git a/clang/lib/Basic/Targets/AArch64.cpp 
b/clang/lib/Basic/Targets/AArch64.cpp
index 399d9ed5ae052..0bb7b489e1d00 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -42,6 +42,20 @@ static_assert(NumBuiltins ==
               (NumNeonBuiltins + NumFp16Builtins + NumSVEBuiltins +
                NumSVENeonBridgeBuiltins + NumSMEBuiltins + 
NumAArch64Builtins));
 
+#define AARCH64_HAS_EXT(ArchExtKind) hasExtension(llvm::AArch64::ArchExtKind)
+#define EMIT_EXTENSION_FEATURE_LOCAL_DECLS
+#include "llvm/TargetParser/AArch64TargetParserDef.inc"
+#define DECLARE_AARCH64_EXTENSION_FEATURE_LOCALS()                             
\
+  AARCH64_DECLARE_EXTENSION_FEATURE_LOCALS(AARCH64_HAS_EXT)                    
\
+  [[maybe_unused]] const bool HasFCMA = HasComplxNum;                          
\
+  [[maybe_unused]] const bool HasJSCVT = HasJS;                                
\
+  [[maybe_unused]] const bool HasBFloat16 = HasBF16;                           
\
+  [[maybe_unused]] const bool HasI8MM = HasMatMulInt8;                         
\
+  [[maybe_unused]] const bool HasF32MM = HasMatMulFP32;                        
\
+  [[maybe_unused]] const bool HasF64MM = HasMatMulFP64;                        
\
+  [[maybe_unused]] const bool HasSME_F8F32 = HasSMEF8F32;                      
\
+  [[maybe_unused]] const bool HasSME_F8F16 = HasSMEF8F16;
+
 namespace clang {
 namespace AArch64 {
 #define GET_BUILTIN_STR_TABLE
@@ -497,10 +511,7 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions 
&Opts,
 
   const bool HasSVE = FPU & SveMode;
   const bool HasNeon = FPU & NeonMode;
-#define AARCH64_EXTENSION_FEATURE(Name, Ext)                                   
\
-  [[maybe_unused]] const bool Name = hasExtension(llvm::AArch64::AEK_##Ext);
-#include "AArch64TargetInfoFeatures.inc"
-#undef AARCH64_EXTENSION_FEATURE
+  DECLARE_AARCH64_EXTENSION_FEATURE_LOCALS()
 
   if (HasSVE2)
     Builder.defineMacro("__ARM_FEATURE_SVE2", "1");
@@ -880,10 +891,7 @@ void AArch64TargetInfo::computeFeatureLookup() {
   const bool HasFP = FPU & FPUMode;
   const bool HasNeon = FPU & NeonMode;
   const bool HasSVE = FPU & SveMode;
-#define AARCH64_EXTENSION_FEATURE(Name, Ext)                                   
\
-  [[maybe_unused]] const bool Name = hasExtension(llvm::AArch64::AEK_##Ext);
-#include "AArch64TargetInfoFeatures.inc"
-#undef AARCH64_EXTENSION_FEATURE
+  DECLARE_AARCH64_EXTENSION_FEATURE_LOCALS()
 
   FeatureLookupBuilder(HasFeatureLookup)
       .Cases({"aarch64", "arm64", "arm"}, true)
diff --git a/clang/lib/Basic/Targets/AArch64TargetInfoFeatures.inc 
b/clang/lib/Basic/Targets/AArch64TargetInfoFeatures.inc
deleted file mode 100644
index 018866eafb6ef..0000000000000
--- a/clang/lib/Basic/Targets/AArch64TargetInfoFeatures.inc
+++ /dev/null
@@ -1,69 +0,0 @@
-AARCH64_EXTENSION_FEATURE(HasJSCVT, JSCVT)
-AARCH64_EXTENSION_FEATURE(HasFCMA, FCMA)
-AARCH64_EXTENSION_FEATURE(HasRandGen, RAND)
-AARCH64_EXTENSION_FEATURE(HasFlagM, FLAGM)
-AARCH64_EXTENSION_FEATURE(HasAlternativeNZCV, ALTERNATIVENZCV)
-AARCH64_EXTENSION_FEATURE(HasFP16FML, FP16FML)
-AARCH64_EXTENSION_FEATURE(HasDotProd, DOTPROD)
-AARCH64_EXTENSION_FEATURE(HasSM4, SM4)
-AARCH64_EXTENSION_FEATURE(HasRDM, RDM)
-AARCH64_EXTENSION_FEATURE(HasLSE, LSE)
-AARCH64_EXTENSION_FEATURE(HasCRC, CRC)
-AARCH64_EXTENSION_FEATURE(HasCSSC, CSSC)
-AARCH64_EXTENSION_FEATURE(HasSHA2, SHA2)
-AARCH64_EXTENSION_FEATURE(HasSHA3, SHA3)
-AARCH64_EXTENSION_FEATURE(HasAES, AES)
-AARCH64_EXTENSION_FEATURE(HasDIT, DIT)
-AARCH64_EXTENSION_FEATURE(HasCCPP, CCPP)
-AARCH64_EXTENSION_FEATURE(HasCCDP, CCDP)
-AARCH64_EXTENSION_FEATURE(HasRCPC, RCPC)
-AARCH64_EXTENSION_FEATURE(HasFRInt3264, FRINT3264)
-AARCH64_EXTENSION_FEATURE(HasI8MM, I8MM)
-AARCH64_EXTENSION_FEATURE(HasBFloat16, BF16)
-AARCH64_EXTENSION_FEATURE(HasSVEB16B16, SVEB16B16)
-AARCH64_EXTENSION_FEATURE(HasF32MM, F32MM)
-AARCH64_EXTENSION_FEATURE(HasF64MM, F64MM)
-AARCH64_EXTENSION_FEATURE(HasSVE2, SVE2)
-AARCH64_EXTENSION_FEATURE(HasSVEAES, SVEAES)
-AARCH64_EXTENSION_FEATURE(HasSVEBitPerm, SVEBITPERM)
-AARCH64_EXTENSION_FEATURE(HasSVE2SHA3, SVE2SHA3)
-AARCH64_EXTENSION_FEATURE(HasSVE2SM4, SVE2SM4)
-AARCH64_EXTENSION_FEATURE(HasSVE2p1, SVE2P1)
-AARCH64_EXTENSION_FEATURE(HasSME, SME)
-AARCH64_EXTENSION_FEATURE(HasSME2, SME2)
-AARCH64_EXTENSION_FEATURE(HasSME2p1, SME2P1)
-AARCH64_EXTENSION_FEATURE(HasSMEF64F64, SMEF64F64)
-AARCH64_EXTENSION_FEATURE(HasSMEI16I64, SMEI16I64)
-AARCH64_EXTENSION_FEATURE(HasSMEFA64, SMEFA64)
-AARCH64_EXTENSION_FEATURE(HasSMEF16F16, SMEF16F16)
-AARCH64_EXTENSION_FEATURE(HasSMEB16B16, SMEB16B16)
-AARCH64_EXTENSION_FEATURE(HasMTE, MTE)
-AARCH64_EXTENSION_FEATURE(HasSB, SB)
-AARCH64_EXTENSION_FEATURE(HasPredRes, PREDRES)
-AARCH64_EXTENSION_FEATURE(HasSSBS, SSBS)
-AARCH64_EXTENSION_FEATURE(HasBTI, BTI)
-AARCH64_EXTENSION_FEATURE(HasLS64, LS64)
-AARCH64_EXTENSION_FEATURE(HasWFxT, WFXT)
-AARCH64_EXTENSION_FEATURE(HasRCPC3, RCPC3)
-AARCH64_EXTENSION_FEATURE(HasFP8, FP8)
-AARCH64_EXTENSION_FEATURE(HasFP8FMA, FP8FMA)
-AARCH64_EXTENSION_FEATURE(HasFP8DOT2, FP8DOT2)
-AARCH64_EXTENSION_FEATURE(HasFP8DOT4, FP8DOT4)
-AARCH64_EXTENSION_FEATURE(HasSSVE_FP8DOT2, SSVE_FP8DOT2)
-AARCH64_EXTENSION_FEATURE(HasSSVE_FP8DOT4, SSVE_FP8DOT4)
-AARCH64_EXTENSION_FEATURE(HasSSVE_FP8FMA, SSVE_FP8FMA)
-AARCH64_EXTENSION_FEATURE(HasSME_F8F32, SMEF8F32)
-AARCH64_EXTENSION_FEATURE(HasSME_F8F16, SMEF8F16)
-AARCH64_EXTENSION_FEATURE(HasFPRCVT, FPRCVT)
-AARCH64_EXTENSION_FEATURE(HasF8F16MM, F8F16MM)
-AARCH64_EXTENSION_FEATURE(HasF8F32MM, F8F32MM)
-AARCH64_EXTENSION_FEATURE(HasSVE_F16F32MM, SVE_F16F32MM)
-AARCH64_EXTENSION_FEATURE(HasSVE_BFSCALE, SVE_BFSCALE)
-AARCH64_EXTENSION_FEATURE(HasSVE_AES2, SVE_AES2)
-AARCH64_EXTENSION_FEATURE(HasSSVE_AES, SSVE_AES)
-AARCH64_EXTENSION_FEATURE(HasSVE2p2, SVE2P2)
-AARCH64_EXTENSION_FEATURE(HasSME2p2, SME2P2)
-AARCH64_EXTENSION_FEATURE(HasPAuthLR, PAUTHLR)
-AARCH64_EXTENSION_FEATURE(HasMOPS, MOPS)
-AARCH64_EXTENSION_FEATURE(HasD128, D128)
-AARCH64_EXTENSION_FEATURE(HasGCS, GCS)
diff --git a/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp 
b/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp
index a18fed082207f..4d62215d3d395 100644
--- a/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp
@@ -150,6 +150,29 @@ static void emitARMTargetDef(const RecordKeeper &RK, 
raw_ostream &OS) {
      << "#endif // EMIT_EXTENSIONS\n"
      << "\n";
 
+  // Emit a macro that expands to local bool declarations for each extension,
+  // parameterized by a caller-provided extension test helper.
+  OS << "#ifdef EMIT_EXTENSION_FEATURE_LOCAL_DECLS\n"
+     << "#ifndef AARCH64_DECLARE_EXTENSION_FEATURE_LOCALS\n"
+     << "#define AARCH64_DECLARE_EXTENSION_FEATURE_LOCALS(TEST_EXT) \\\n";
+  for (size_t I = 0; I < SortedExtensions.size(); ++I) {
+    const Record *Rec = SortedExtensions[I];
+    std::string FieldName(Rec->getValueAsString("FieldName"));
+    if (FieldName == "HasSVE")
+      FieldName = "HasSVEExt";
+    auto AEK = Rec->getValueAsString("ArchExtKindSpelling").upper();
+    OS << "  [[maybe_unused]] const bool " << FieldName << " = TEST_EXT(" << 
AEK
+       << ");";
+    if (I + 1 != SortedExtensions.size())
+      OS << " \\\n";
+    else
+      OS << "\n";
+  }
+  OS << "#endif\n"
+     << "#undef EMIT_EXTENSION_FEATURE_LOCAL_DECLS\n"
+     << "#endif // EMIT_EXTENSION_FEATURE_LOCAL_DECLS\n"
+     << "\n";
+
   // Emit FMV information
   auto FMVExts = RK.getAllDerivedDefinitionsIfDefined("FMVExtension");
   OS << "#ifdef EMIT_FMV_INFO\n"

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to