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

>From 6251ce1e069f2982a4b6b885c1b8e77d182854eb Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <[email protected]>
Date: Fri, 3 Apr 2026 01:14:47 +0100
Subject: [PATCH 1/5] [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 9afe6cb10729d..9a664dac21a12 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 f57c9c8b87cd5..0576c53c50516 100644
--- a/clang/lib/Sema/SemaARM.cpp
+++ b/clang/lib/Sema/SemaARM.cpp
@@ -1476,7 +1476,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);
@@ -1488,7 +1488,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);
     }
@@ -1765,7 +1765,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 2309196ee1696..8f36799e57ea3 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -4347,7 +4347,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 1075d490a3618304f11c37dd572ff38f7352261d Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <[email protected]>
Date: Wed, 8 Apr 2026 15:25:27 +0100
Subject: [PATCH 2/5] fixup! Don't checkin AArch64TargetInfoFeatures.inc but
 generate from tablegen

---
 clang/lib/Basic/Targets/AArch64.cpp           | 24 ++++---
 .../Targets/AArch64TargetInfoFeatures.inc     | 69 -------------------
 .../Preprocessor/aarch64-target-features.c    | 22 ------
 ...-sme-func-attrs-without-target-feature.cpp |  5 --
 .../TableGen/Basic/ARMTargetDefEmitter.cpp    | 23 +++++++
 5 files changed, 39 insertions(+), 104 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 9a664dac21a12..2802d3471c740 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/clang/test/Preprocessor/aarch64-target-features.c 
b/clang/test/Preprocessor/aarch64-target-features.c
index 41393e423f17f..60ddaad639d48 100644
--- a/clang/test/Preprocessor/aarch64-target-features.c
+++ b/clang/test/Preprocessor/aarch64-target-features.c
@@ -235,7 +235,6 @@
 
 // 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
@@ -254,12 +253,10 @@
 
 // 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
@@ -274,16 +271,6 @@
 // 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
@@ -296,18 +283,12 @@
 // 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.
@@ -755,14 +736,12 @@
 // 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
@@ -839,7 +818,6 @@
 //  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 821c0082a3458..2ba266a93f94f 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,11 +21,6 @@ __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
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"

>From eb6215a1f0b48dd2a740c45a6aa8e5c43d408b2e Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <[email protected]>
Date: Thu, 28 May 2026 18:16:32 +0100
Subject: [PATCH 3/5] fixup! Address PR comments

---
 clang/lib/Basic/Targets/AArch64.cpp           | 173 +++++++-----------
 clang/lib/Basic/Targets/AArch64.h             |   5 +-
 clang/lib/Sema/SemaARM.cpp                    |  10 +-
 .../TableGen/Basic/ARMTargetDefEmitter.cpp    |   8 +-
 4 files changed, 75 insertions(+), 121 deletions(-)

diff --git a/clang/lib/Basic/Targets/AArch64.cpp 
b/clang/lib/Basic/Targets/AArch64.cpp
index 2802d3471c740..bcf47d7024063 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -42,19 +42,11 @@ 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;
+  AARCH64_DECLARE_EXTENSION_FEATURE_LOCALS(hasExtension)
 
 namespace clang {
 namespace AArch64 {
@@ -477,8 +469,12 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions 
&Opts,
   Builder.defineMacro("__ARM_STATE_ZA", "1");
   Builder.defineMacro("__ARM_STATE_ZT0", "1");
 
+  const bool FPUModeIsFP = FPU & FPUMode;
+  const bool FPUModeIsNeon = FPU & NeonMode;
+  const bool FPUModeIsSVE = FPU & SveMode;
+
   // 0xe implies support for half, single and double precision operations.
-  if (FPU & FPUMode)
+  if (FPUModeIsFP)
     Builder.defineMacro("__ARM_FP", "0xE");
 
   // PCS specifies this for SysV variants, which is all we support. Other ABIs
@@ -500,17 +496,15 @@ void AArch64TargetInfo::getTargetDefines(const 
LangOptions &Opts,
   // Clang supports range prefetch intrinsics
   Builder.defineMacro("__ARM_PREFETCH_RANGE", "1");
 
-  if (FPU & NeonMode) {
+  if (FPUModeIsNeon) {
     Builder.defineMacro("__ARM_NEON", "1");
     // 64-bit NEON supports half, single and double precision operations.
     Builder.defineMacro("__ARM_NEON_FP", "0xE");
   }
 
-  if (FPU & SveMode)
+  if (FPUModeIsSVE)
     Builder.defineMacro("__ARM_FEATURE_SVE", "1");
 
-  const bool HasSVE = FPU & SveMode;
-  const bool HasNeon = FPU & NeonMode;
   DECLARE_AARCH64_EXTENSION_FEATURE_LOCALS()
 
   if (HasSVE2)
@@ -572,10 +566,10 @@ void AArch64TargetInfo::getTargetDefines(const 
LangOptions &Opts,
   if (HasSSVE_FP8FMA)
     Builder.defineMacro("__ARM_FEATURE_SSVE_FP8FMA", "1");
 
-  if (HasSME_F8F32)
+  if (HasSMEF8F32)
     Builder.defineMacro("__ARM_FEATURE_SME_F8F32", "1");
 
-  if (HasSME_F8F16)
+  if (HasSMEF8F16)
     Builder.defineMacro("__ARM_FEATURE_SME_F8F16", "1");
 
   if (HasCRC)
@@ -640,7 +634,7 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions 
&Opts,
     Builder.defineMacro("__ARM_FEATURE_SM4", "1");
   }
 
-  if (hasPAuth())
+  if (HasPAuth || HasPAuthLR)
     Builder.defineMacro("__ARM_FEATURE_PAUTH", "1");
 
   if (HasPAuthLR)
@@ -652,9 +646,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions 
&Opts,
   if (HasUnalignedAccess)
     Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1");
 
-  if ((FPU & NeonMode) && hasFullFP16())
+  if (FPUModeIsNeon && hasFP16Arithmetic())
     Builder.defineMacro("__ARM_FEATURE_FP16_VECTOR_ARITHMETIC", "1");
-  if (hasFullFP16())
+  if (hasFP16Arithmetic())
     Builder.defineMacro("__ARM_FEATURE_FP16_SCALAR_ARITHMETIC", "1");
 
   if (HasDotProd)
@@ -663,33 +657,33 @@ void AArch64TargetInfo::getTargetDefines(const 
LangOptions &Opts,
   if (HasMTE)
     Builder.defineMacro("__ARM_FEATURE_MEMORY_TAGGING", "1");
 
-  if (HasI8MM)
+  if (HasMatMulInt8)
     Builder.defineMacro("__ARM_FEATURE_MATMUL_INT8", "1");
 
   if (HasLSE)
     Builder.defineMacro("__ARM_FEATURE_ATOMICS", "1");
 
-  if (HasBFloat16) {
+  if (HasBF16) {
     Builder.defineMacro("__ARM_FEATURE_BF16", "1");
     Builder.defineMacro("__ARM_FEATURE_BF16_VECTOR_ARITHMETIC", "1");
     Builder.defineMacro("__ARM_BF16_FORMAT_ALTERNATIVE", "1");
     Builder.defineMacro("__ARM_FEATURE_BF16_SCALAR_ARITHMETIC", "1");
   }
 
-  if (HasSVE && HasBFloat16) {
+  if (FPUModeIsSVE && HasBF16) {
     Builder.defineMacro("__ARM_FEATURE_SVE_BF16", "1");
   }
 
-  if (HasSVE && HasF64MM)
+  if (FPUModeIsSVE && HasMatMulFP64)
     Builder.defineMacro("__ARM_FEATURE_SVE_MATMUL_FP64", "1");
 
-  if (HasSVE && HasF32MM)
+  if (FPUModeIsSVE && HasMatMulFP32)
     Builder.defineMacro("__ARM_FEATURE_SVE_MATMUL_FP32", "1");
 
-  if (HasSVE && HasI8MM)
+  if (FPUModeIsSVE && HasMatMulInt8)
     Builder.defineMacro("__ARM_FEATURE_SVE_MATMUL_INT8", "1");
 
-  if (HasNeon && HasFP16FML)
+  if (FPUModeIsNeon && HasFP16FML)
     Builder.defineMacro("__ARM_FEATURE_FP16_FML", "1");
 
   if (Opts.hasSignReturnAddress()) {
@@ -782,7 +776,7 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions 
&Opts,
   Builder.defineMacro("__FP_FAST_FMAF", "1");
 
   // C/C++ operators work on both VLS and VLA SVE types
-  if (FPU & SveMode)
+  if (FPUModeIsSVE)
     Builder.defineMacro("__ARM_FEATURE_SVE_VECTOR_OPERATORS", "2");
 
   if (Opts.VScaleMin && Opts.VScaleMin == Opts.VScaleMax) {
@@ -888,18 +882,18 @@ struct FeatureLookupBuilder {
 };
 
 void AArch64TargetInfo::computeFeatureLookup() {
-  const bool HasFP = FPU & FPUMode;
-  const bool HasNeon = FPU & NeonMode;
-  const bool HasSVE = FPU & SveMode;
+  const bool FPUModeIsFP = FPU & FPUMode;
+  const bool FPUModeIsNeon = FPU & NeonMode;
+  const bool FPUModeIsSVE = FPU & SveMode;
   DECLARE_AARCH64_EXTENSION_FEATURE_LOCALS()
 
   FeatureLookupBuilder(HasFeatureLookup)
       .Cases({"aarch64", "arm64", "arm"}, true)
       .Case("fmv", HasFMV)
-      .Case("fp", HasFP)
-      .Cases({"neon", "simd"}, HasNeon)
-      .Case("jscvt", HasJSCVT)
-      .Case("fcma", HasFCMA)
+      .Case("fp", FPUModeIsFP)
+      .Cases({"neon", "simd"}, FPUModeIsNeon)
+      .Case("jscvt", HasJS)
+      .Case("fcma", HasComplxNum)
       .Case("rng", HasRandGen)
       .Case("flagm", HasFlagM)
       .Case("flagm2", HasAlternativeNZCV)
@@ -913,24 +907,24 @@ void AArch64TargetInfo::computeFeatureLookup() {
       .Case("sha2", HasSHA2)
       .Case("sha3", HasSHA3)
       .Cases({"aes", "pmull"}, HasAES)
-      .Cases({"fp16", "fullfp16"}, hasFullFP16())
+      .Cases({"fp16", "fullfp16"}, hasFP16Arithmetic())
       .Case("dit", HasDIT)
       .Case("dpb", HasCCPP)
       .Case("dpb2", HasCCDP)
       .Case("rcpc", HasRCPC)
       .Case("frintts", HasFRInt3264)
-      .Case("i8mm", HasI8MM)
-      .Case("bf16", HasBFloat16)
-      .Case("sve", HasSVE)
+      .Case("i8mm", HasMatMulInt8)
+      .Case("bf16", HasBF16)
+      .Case("sve", FPUModeIsSVE)
       .Case("sve-b16b16", HasSVEB16B16)
-      .Case("f32mm", HasSVE && HasF32MM)
-      .Case("f64mm", HasSVE && HasF64MM)
-      .Case("sve2", HasSVE && HasSVE2)
+      .Case("f32mm", FPUModeIsSVE && HasMatMulFP32)
+      .Case("f64mm", FPUModeIsSVE && HasMatMulFP64)
+      .Case("sve2", FPUModeIsSVE && HasSVE2)
       .Case("sve-aes", HasSVEAES)
       .Case("sve-bitperm", FPU & HasSVEBitPerm)
-      .Case("sve2-sha3", HasSVE && HasSVE2SHA3)
-      .Case("sve2-sm4", HasSVE && HasSVE2SM4)
-      .Case("sve2p1", HasSVE && HasSVE2p1)
+      .Case("sve2-sha3", FPUModeIsSVE && HasSVE2SHA3)
+      .Case("sve2-sm4", FPUModeIsSVE && HasSVE2SM4)
+      .Case("sve2p1", FPUModeIsSVE && HasSVE2p1)
       .Case("sme", HasSME)
       .Case("sme2", HasSME2)
       .Case("sme2p1", HasSME2p1)
@@ -954,8 +948,8 @@ void AArch64TargetInfo::computeFeatureLookup() {
       .Case("ssve-fp8dot2", HasSSVE_FP8DOT2)
       .Case("ssve-fp8dot4", HasSSVE_FP8DOT4)
       .Case("ssve-fp8fma", HasSSVE_FP8FMA)
-      .Case("sme-f8f32", HasSME_F8F32)
-      .Case("sme-f8f16", HasSME_F8F16)
+      .Case("sme-f8f32", HasSMEF8F32)
+      .Case("sme-f8f16", HasSMEF8F16)
       .Case("fprcvt", HasFPRCVT)
       .Case("f8f16mm", HasF8F16MM)
       .Case("f8f32mm", HasF8F32MM)
@@ -963,8 +957,10 @@ void AArch64TargetInfo::computeFeatureLookup() {
       .Case("sve-bfscale", HasSVE_BFSCALE)
       .Case("sve-aes2", HasSVE_AES2)
       .Case("ssve-aes", HasSSVE_AES)
-      .Case("sve2p2", HasSVE && HasSVE2p2)
-      .Case("sme2p2", HasSME2p2);
+      .Case("sve2p2", FPUModeIsSVE && HasSVE2p2)
+      .Case("sve2p3", FPUModeIsSVE && HasSVE2p3)
+      .Case("sme2p2", HasSME2p2)
+      .Case("sme2p3", HasSME2p3);
 }
 
 bool AArch64TargetInfo::hasFeature(StringRef Feature) const {
@@ -975,12 +971,7 @@ 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 {
+bool AArch64TargetInfo::hasFP16Arithmetic() const {
   return hasExtension(llvm::AArch64::AEK_FP16) ||
          hasExtension(llvm::AArch64::AEK_SVEAES) ||
          hasExtension(llvm::AArch64::AEK_SVEBITPERM);
@@ -1022,11 +1013,6 @@ lookupExtensionForTargetFeature(StringRef Feature) {
       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) {
@@ -1037,43 +1023,6 @@ static bool enablesNeonFPUCompat(StringRef Feature) {
       .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
@@ -1110,6 +1059,23 @@ void 
AArch64TargetInfo::setFeatureStateFromEnabledExtensions(
 void AArch64TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
                                           StringRef Name, bool Enabled) const {
   Features[Name] = Enabled;
+
+  if (Enabled) {
+    std::string TargetFeature = ("+" + Name).str();
+    if (auto ExtInfo = lookupExtensionForTargetFeature(TargetFeature)) {
+      llvm::AArch64::ExtensionSet FeatureBits;
+      FeatureBits.enable(ExtInfo->ID);
+
+      // Sema queries these mode features through the generic feature map, but
+      // feature guards still need to distinguish pairs like sve-aes/ssve-aes.
+      if (FeatureBits.Enabled.test(llvm::AArch64::AEK_SVE))
+        Features["sve"] = true;
+      if (FeatureBits.Enabled.test(llvm::AArch64::AEK_SME))
+        Features["sme"] = true;
+      return;
+    }
+  }
+
   // If the feature is an architecture feature (like v8.2a), add all previous
   // architecture versions and any dependant target features.
   const std::optional<llvm::AArch64::ArchInfo> ArchInfo =
@@ -1136,19 +1102,6 @@ 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) {
   llvm::AArch64::ExtensionSet FeatureBits;
diff --git a/clang/lib/Basic/Targets/AArch64.h 
b/clang/lib/Basic/Targets/AArch64.h
index b0c1fcedbc183..e5f23df6f2f05 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -82,8 +82,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public 
TargetInfo {
 
   void computeFeatureLookup();
   bool hasExtension(llvm::AArch64::ArchExtKind Ext) const;
-  bool hasPAuth() const;
-  bool hasFullFP16() const;
+  bool hasFP16Arithmetic() const;
   void setFeatureStateFromEnabledExtensions(
       const llvm::AArch64::ExtensionBitset &EnabledExtensions);
 
@@ -95,8 +94,6 @@ 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/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp
index 0576c53c50516..d8665bebce596 100644
--- a/clang/lib/Sema/SemaARM.cpp
+++ b/clang/lib/Sema/SemaARM.cpp
@@ -578,7 +578,8 @@ static bool checkArmStreamingBuiltin(Sema &S, CallExpr 
*TheCall,
     S.Context.getFunctionFeatureMap(CallerFeatures, FD);
 
     // Avoid emitting diagnostics for a function that can never compile.
-    if (FnType == SemaARM::ArmStreaming && !CallerFeatures["sme"])
+    if (FnType == SemaARM::ArmStreaming &&
+        !S.Context.getTargetInfo().hasFeatureEnabled(CallerFeatures, "sme"))
       return false;
 
     const auto FindTopLevelPipe = [](const char *S) {
@@ -603,6 +604,11 @@ static bool checkArmStreamingBuiltin(Sema &S, CallExpr 
*TheCall,
     StringRef NonStreamingBuiltinGuard = StringRef(RequiredFeatures, PipeIdx);
     StringRef StreamingBuiltinGuard = StringRef(RequiredFeatures + PipeIdx + 
1);
 
+    if (S.Context.getTargetInfo().hasFeatureEnabled(CallerFeatures, "sve"))
+      CallerFeatures["sve"] = true;
+    if (S.Context.getTargetInfo().hasFeatureEnabled(CallerFeatures, "sme"))
+      CallerFeatures["sme"] = true;
+
     bool SatisfiesSVE = Builtin::evaluateRequiredTargetFeatures(
         NonStreamingBuiltinGuard, CallerFeatures);
     bool SatisfiesSME = Builtin::evaluateRequiredTargetFeatures(
@@ -1761,7 +1767,7 @@ bool SemaARM::checkSVETypeSupport(QualType Ty, 
SourceLocation Loc,
   if (!Ty->isSVESizelessBuiltinType())
     return false;
 
-  if (FeatureMap.lookup("sve"))
+  if (getASTContext().getTargetInfo().hasFeatureEnabled(FeatureMap, "sve"))
     return false;
 
   // No SVE environment available.
diff --git a/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp 
b/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp
index 4d62215d3d395..f78cfe7ff73de 100644
--- a/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp
@@ -151,18 +151,16 @@ static void emitARMTargetDef(const RecordKeeper &RK, 
raw_ostream &OS) {
      << "\n";
 
   // Emit a macro that expands to local bool declarations for each extension,
-  // parameterized by a caller-provided extension test helper.
+  // parameterized by a caller-provided extension test function.
   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
-       << ");";
+    OS << "  [[maybe_unused]] const bool " << FieldName
+       << " = TEST_EXT(llvm::AArch64::" << AEK << ");";
     if (I + 1 != SortedExtensions.size())
       OS << " \\\n";
     else

>From e19a643027f652a61cd5f87a9389cd83e43bfe8a Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <[email protected]>
Date: Thu, 28 May 2026 19:01:15 +0100
Subject: [PATCH 4/5] fixup! Small tweaks

---
 clang/lib/Basic/Targets/AArch64.cpp | 84 ++++++++++++-----------------
 1 file changed, 33 insertions(+), 51 deletions(-)

diff --git a/clang/lib/Basic/Targets/AArch64.cpp 
b/clang/lib/Basic/Targets/AArch64.cpp
index bcf47d7024063..c1d748eb60aa8 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -469,12 +469,8 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions 
&Opts,
   Builder.defineMacro("__ARM_STATE_ZA", "1");
   Builder.defineMacro("__ARM_STATE_ZT0", "1");
 
-  const bool FPUModeIsFP = FPU & FPUMode;
-  const bool FPUModeIsNeon = FPU & NeonMode;
-  const bool FPUModeIsSVE = FPU & SveMode;
-
   // 0xe implies support for half, single and double precision operations.
-  if (FPUModeIsFP)
+  if (FPU & FPUMode)
     Builder.defineMacro("__ARM_FP", "0xE");
 
   // PCS specifies this for SysV variants, which is all we support. Other ABIs
@@ -496,13 +492,13 @@ void AArch64TargetInfo::getTargetDefines(const 
LangOptions &Opts,
   // Clang supports range prefetch intrinsics
   Builder.defineMacro("__ARM_PREFETCH_RANGE", "1");
 
-  if (FPUModeIsNeon) {
+  if (FPU & NeonMode) {
     Builder.defineMacro("__ARM_NEON", "1");
     // 64-bit NEON supports half, single and double precision operations.
     Builder.defineMacro("__ARM_NEON_FP", "0xE");
   }
 
-  if (FPUModeIsSVE)
+  if (FPU & SveMode)
     Builder.defineMacro("__ARM_FEATURE_SVE", "1");
 
   DECLARE_AARCH64_EXTENSION_FEATURE_LOCALS()
@@ -646,7 +642,7 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions 
&Opts,
   if (HasUnalignedAccess)
     Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1");
 
-  if (FPUModeIsNeon && hasFP16Arithmetic())
+  if ((FPU & NeonMode) && hasFP16Arithmetic())
     Builder.defineMacro("__ARM_FEATURE_FP16_VECTOR_ARITHMETIC", "1");
   if (hasFP16Arithmetic())
     Builder.defineMacro("__ARM_FEATURE_FP16_SCALAR_ARITHMETIC", "1");
@@ -670,20 +666,20 @@ void AArch64TargetInfo::getTargetDefines(const 
LangOptions &Opts,
     Builder.defineMacro("__ARM_FEATURE_BF16_SCALAR_ARITHMETIC", "1");
   }
 
-  if (FPUModeIsSVE && HasBF16) {
+  if ((FPU & SveMode) && HasBF16) {
     Builder.defineMacro("__ARM_FEATURE_SVE_BF16", "1");
   }
 
-  if (FPUModeIsSVE && HasMatMulFP64)
+  if ((FPU & SveMode) && HasMatMulFP64)
     Builder.defineMacro("__ARM_FEATURE_SVE_MATMUL_FP64", "1");
 
-  if (FPUModeIsSVE && HasMatMulFP32)
+  if ((FPU & SveMode) && HasMatMulFP32)
     Builder.defineMacro("__ARM_FEATURE_SVE_MATMUL_FP32", "1");
 
-  if (FPUModeIsSVE && HasMatMulInt8)
+  if ((FPU & SveMode) && HasMatMulInt8)
     Builder.defineMacro("__ARM_FEATURE_SVE_MATMUL_INT8", "1");
 
-  if (FPUModeIsNeon && HasFP16FML)
+  if ((FPU & NeonMode) && HasFP16FML)
     Builder.defineMacro("__ARM_FEATURE_FP16_FML", "1");
 
   if (Opts.hasSignReturnAddress()) {
@@ -776,7 +772,7 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions 
&Opts,
   Builder.defineMacro("__FP_FAST_FMAF", "1");
 
   // C/C++ operators work on both VLS and VLA SVE types
-  if (FPUModeIsSVE)
+  if (FPU & SveMode)
     Builder.defineMacro("__ARM_FEATURE_SVE_VECTOR_OPERATORS", "2");
 
   if (Opts.VScaleMin && Opts.VScaleMin == Opts.VScaleMax) {
@@ -882,16 +878,13 @@ struct FeatureLookupBuilder {
 };
 
 void AArch64TargetInfo::computeFeatureLookup() {
-  const bool FPUModeIsFP = FPU & FPUMode;
-  const bool FPUModeIsNeon = FPU & NeonMode;
-  const bool FPUModeIsSVE = FPU & SveMode;
   DECLARE_AARCH64_EXTENSION_FEATURE_LOCALS()
 
   FeatureLookupBuilder(HasFeatureLookup)
       .Cases({"aarch64", "arm64", "arm"}, true)
       .Case("fmv", HasFMV)
-      .Case("fp", FPUModeIsFP)
-      .Cases({"neon", "simd"}, FPUModeIsNeon)
+      .Case("fp", FPU & FPUMode)
+      .Cases({"neon", "simd"}, FPU & NeonMode)
       .Case("jscvt", HasJS)
       .Case("fcma", HasComplxNum)
       .Case("rng", HasRandGen)
@@ -915,16 +908,16 @@ void AArch64TargetInfo::computeFeatureLookup() {
       .Case("frintts", HasFRInt3264)
       .Case("i8mm", HasMatMulInt8)
       .Case("bf16", HasBF16)
-      .Case("sve", FPUModeIsSVE)
+      .Case("sve", FPU & SveMode)
       .Case("sve-b16b16", HasSVEB16B16)
-      .Case("f32mm", FPUModeIsSVE && HasMatMulFP32)
-      .Case("f64mm", FPUModeIsSVE && HasMatMulFP64)
-      .Case("sve2", FPUModeIsSVE && HasSVE2)
+      .Case("f32mm", FPU & SveMode && HasMatMulFP32)
+      .Case("f64mm", FPU & SveMode && HasMatMulFP64)
+      .Case("sve2", FPU & SveMode && HasSVE2)
       .Case("sve-aes", HasSVEAES)
       .Case("sve-bitperm", FPU & HasSVEBitPerm)
-      .Case("sve2-sha3", FPUModeIsSVE && HasSVE2SHA3)
-      .Case("sve2-sm4", FPUModeIsSVE && HasSVE2SM4)
-      .Case("sve2p1", FPUModeIsSVE && HasSVE2p1)
+      .Case("sve2-sha3", FPU & SveMode && HasSVE2SHA3)
+      .Case("sve2-sm4", FPU & SveMode && HasSVE2SM4)
+      .Case("sve2p1", FPU & SveMode && HasSVE2p1)
       .Case("sme", HasSME)
       .Case("sme2", HasSME2)
       .Case("sme2p1", HasSME2p1)
@@ -957,8 +950,8 @@ void AArch64TargetInfo::computeFeatureLookup() {
       .Case("sve-bfscale", HasSVE_BFSCALE)
       .Case("sve-aes2", HasSVE_AES2)
       .Case("ssve-aes", HasSSVE_AES)
-      .Case("sve2p2", FPUModeIsSVE && HasSVE2p2)
-      .Case("sve2p3", FPUModeIsSVE && HasSVE2p3)
+      .Case("sve2p2", FPU & SveMode && HasSVE2p2)
+      .Case("sve2p3", FPU & SveMode && HasSVE2p3)
       .Case("sme2p2", HasSME2p2)
       .Case("sme2p3", HasSME2p3);
 }
@@ -996,31 +989,14 @@ 
findExplicitBaseArchForTargetFeatures(ArrayRef<std::string> Features) {
   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));
-}
+  if (auto ExtInfo = llvm::AArch64::targetFeatureToExtension(Feature))
+    return ExtInfo;
 
-// 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);
+  if (!Feature.consume_front("+") && !Feature.consume_front("-"))
+    return {};
+  return llvm::AArch64::parseArchExtension(Feature);
 }
 
 // Synchronize the frontend's cached booleans and FPU mode bits from the
@@ -1121,7 +1097,13 @@ bool 
AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
   ExpandedFeatures.reserve(Features.size());
 
   for (const std::string &Feature : Features) {
-    if (enablesNeonFPUCompat(Feature))
+    // Direct feature spellings that historically force Clang's NEON-facing FPU
+    // state.
+    if (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))
       ExplicitFPUCompat |= NeonMode;
 
     if (auto ExtInfo = lookupExtensionForTargetFeature(Feature)) {

>From 26d8cfe362f972ba4d7c87c99e55a701c6837f5b Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <[email protected]>
Date: Thu, 28 May 2026 22:21:04 +0100
Subject: [PATCH 5/5] fixup! Address more CR comments

---
 clang/lib/Basic/Targets/AArch64.cpp | 106 +++++++++++++---------------
 clang/lib/Basic/Targets/AArch64.h   |   7 +-
 clang/lib/Sema/SemaARM.cpp          |  33 +++++----
 3 files changed, 72 insertions(+), 74 deletions(-)

diff --git a/clang/lib/Basic/Targets/AArch64.cpp 
b/clang/lib/Basic/Targets/AArch64.cpp
index c1d748eb60aa8..bd206eb642de6 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -46,7 +46,7 @@ static_assert(NumBuiltins ==
 #include "llvm/TargetParser/AArch64TargetParserDef.inc"
 
 #define DECLARE_AARCH64_EXTENSION_FEATURE_LOCALS()                             
\
-  AARCH64_DECLARE_EXTENSION_FEATURE_LOCALS(hasExtension)
+  AARCH64_DECLARE_EXTENSION_FEATURE_LOCALS(EnabledExtensions.test)
 
 namespace clang {
 namespace AArch64 {
@@ -261,7 +261,7 @@ bool AArch64TargetInfo::validateBranchProtection(StringRef 
Spec, StringRef,
                                                  StringRef &Err) const {
   llvm::ARM::ParsedBranchProtection PBP;
   if (!llvm::ARM::parseBranchProtection(
-          Spec, PBP, Err, hasExtension(llvm::AArch64::AEK_PAUTHLR)))
+          Spec, PBP, Err, EnabledExtensions.test(llvm::AArch64::AEK_PAUTHLR)))
     return false;
 
   // GCS is currently untested with ptrauth-returns, but enabling this could be
@@ -960,16 +960,6 @@ bool AArch64TargetInfo::hasFeature(StringRef Feature) 
const {
   return HasFeatureLookup.contains(Feature);
 }
 
-bool AArch64TargetInfo::hasExtension(llvm::AArch64::ArchExtKind Ext) const {
-  return EnabledExtensions.test(Ext);
-}
-
-bool AArch64TargetInfo::hasFP16Arithmetic() 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>
@@ -989,16 +979,6 @@ 
findExplicitBaseArchForTargetFeatures(ArrayRef<std::string> Features) {
   return BaseArch;
 }
 
-static std::optional<llvm::AArch64::ExtensionInfo>
-lookupExtensionForTargetFeature(StringRef Feature) {
-  if (auto ExtInfo = llvm::AArch64::targetFeatureToExtension(Feature))
-    return ExtInfo;
-
-  if (!Feature.consume_front("+") && !Feature.consume_front("-"))
-    return {};
-  return llvm::AArch64::parseArchExtension(Feature);
-}
-
 // 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
@@ -1006,8 +986,9 @@ 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);
+  const bool HasSVEAES = EnabledExtensions.test(llvm::AArch64::AEK_SVEAES);
+  const bool HasSVEBitPerm =
+      EnabledExtensions.test(llvm::AArch64::AEK_SVEBITPERM);
 
   // clear the cached FPU mode bits (FPUMode, NeonMode, SveMode)
   FPU &= ~(FPUMode | NeonMode | SveMode);
@@ -1020,16 +1001,31 @@ void 
AArch64TargetInfo::setFeatureStateFromEnabledExtensions(
   if (EnabledExtensions.test(llvm::AArch64::AEK_SVE))
     FPU |= SveMode;
 
+  if (EnabledExtensions.test(llvm::AArch64::AEK_SIMD))
+    FPU |= NeonMode;
+
   // 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.
+  // Keep the frontend's historical FPU compatibility for legacy feature
+  // spellings that do not enable the AdvSIMD extension.
   FPU |= ExplicitFPUCompat & (NeonMode | SveMode);
   if (HasSVEAES || HasSVEBitPerm)
     FPU |= NeonMode;
+
+  if (HasNoFP) {
+    FPU &= ~FPUMode;
+    FPU &= ~NeonMode;
+    FPU &= ~SveMode;
+  }
+  if (HasNoNeon) {
+    FPU &= ~NeonMode;
+    FPU &= ~SveMode;
+  }
+  if (HasNoSVE)
+    FPU &= ~SveMode;
 }
 
 void AArch64TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
@@ -1038,7 +1034,11 @@ void 
AArch64TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
 
   if (Enabled) {
     std::string TargetFeature = ("+" + Name).str();
-    if (auto ExtInfo = lookupExtensionForTargetFeature(TargetFeature)) {
+    auto ExtInfo = llvm::AArch64::targetFeatureToExtension(TargetFeature);
+    if (!ExtInfo)
+      ExtInfo = llvm::AArch64::parseArchExtension(Name);
+
+    if (ExtInfo) {
       llvm::AArch64::ExtensionSet FeatureBits;
       FeatureBits.enable(ExtInfo->ID);
 
@@ -1048,6 +1048,8 @@ void 
AArch64TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
         Features["sve"] = true;
       if (FeatureBits.Enabled.test(llvm::AArch64::AEK_SME))
         Features["sme"] = true;
+      if (FeatureBits.Enabled.test(llvm::AArch64::AEK_SME2))
+        Features["sme2"] = true;
       return;
     }
   }
@@ -1097,32 +1099,32 @@ bool 
AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
   ExpandedFeatures.reserve(Features.size());
 
   for (const std::string &Feature : Features) {
-    // Direct feature spellings that historically force Clang's NEON-facing FPU
-    // state.
     if (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)
+            .Cases({"+fp-armv8", "+jscvt", "+jsconv", "+fullfp16"}, true)
             .Default(false))
       ExplicitFPUCompat |= NeonMode;
 
-    if (auto ExtInfo = lookupExtensionForTargetFeature(Feature)) {
-      if (!Feature.empty() && Feature[0] == '+')
+    StringRef ExtensionName = Feature;
+    bool Enable = ExtensionName.consume_front("+");
+    bool Disable = !Enable && ExtensionName.consume_front("-");
+    if (Enable || Disable) {
+      auto ExtInfo = llvm::AArch64::targetFeatureToExtension(Feature);
+      if (!ExtInfo)
+        ExtInfo = llvm::AArch64::parseArchExtension(ExtensionName);
+      if (!ExtInfo) {
+        ExpandedFeatures.push_back(Feature);
+        continue;
+      }
+
+      if (Enable)
         FeatureBits.enable(ExtInfo->ID);
-      else if (!Feature.empty() && Feature[0] == '-') {
-        switch (ExtInfo->ID) {
-        case llvm::AArch64::AEK_FP:
+      else {
+        if (ExtInfo->ID == llvm::AArch64::AEK_FP)
           HasNoFP = true;
-          break;
-        case llvm::AArch64::AEK_SIMD:
+        if (ExtInfo->ID == llvm::AArch64::AEK_SIMD)
           HasNoNeon = true;
-          break;
-        case llvm::AArch64::AEK_SVE:
+        if (ExtInfo->ID == llvm::AArch64::AEK_SVE)
           HasNoSVE = true;
-          break;
-        default:
-          break;
-        }
         FeatureBits.disable(ExtInfo->ID);
       }
       continue;
@@ -1205,18 +1207,6 @@ bool 
AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
 
   resetDataLayout();
 
-  if (HasNoFP) {
-    FPU &= ~FPUMode;
-    FPU &= ~NeonMode;
-    FPU &= ~SveMode;
-  }
-  if (HasNoNeon) {
-    FPU &= ~NeonMode;
-    FPU &= ~SveMode;
-  }
-  if (HasNoSVE)
-    FPU &= ~SveMode;
-
   computeFeatureLookup();
   return true;
 }
@@ -1577,7 +1567,7 @@ bool AArch64TargetInfo::validateConstraintModifier(
     return true;
   case 'z':
   case 'r': {
-    const bool HasLS64 = hasExtension(llvm::AArch64::AEK_LS64);
+    const bool HasLS64 = EnabledExtensions.test(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 e5f23df6f2f05..84ebc3b633993 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -81,8 +81,11 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public 
TargetInfo {
   AArch64FeatureSet HasFeatureLookup;
 
   void computeFeatureLookup();
-  bool hasExtension(llvm::AArch64::ArchExtKind Ext) const;
-  bool hasFP16Arithmetic() const;
+  bool hasFP16Arithmetic() const {
+    return EnabledExtensions.test(llvm::AArch64::AEK_FP16) ||
+           EnabledExtensions.test(llvm::AArch64::AEK_SVEAES) ||
+           EnabledExtensions.test(llvm::AArch64::AEK_SVEBITPERM);
+  }
   void setFeatureStateFromEnabledExtensions(
       const llvm::AArch64::ExtensionBitset &EnabledExtensions);
 
diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp
index d8665bebce596..c61532e45ef13 100644
--- a/clang/lib/Sema/SemaARM.cpp
+++ b/clang/lib/Sema/SemaARM.cpp
@@ -576,10 +576,12 @@ static bool checkArmStreamingBuiltin(Sema &S, CallExpr 
*TheCall,
   if (BuiltinType == SemaARM::VerifyRuntimeMode) {
     llvm::StringMap<bool> CallerFeatures;
     S.Context.getFunctionFeatureMap(CallerFeatures, FD);
+    const TargetInfo &TI = S.Context.getTargetInfo();
+    bool CallerHasSVE = TI.hasFeatureEnabled(CallerFeatures, "sve");
+    bool CallerHasSME = TI.hasFeatureEnabled(CallerFeatures, "sme");
 
     // Avoid emitting diagnostics for a function that can never compile.
-    if (FnType == SemaARM::ArmStreaming &&
-        !S.Context.getTargetInfo().hasFeatureEnabled(CallerFeatures, "sme"))
+    if (FnType == SemaARM::ArmStreaming && !CallerHasSME)
       return false;
 
     const auto FindTopLevelPipe = [](const char *S) {
@@ -604,9 +606,9 @@ static bool checkArmStreamingBuiltin(Sema &S, CallExpr 
*TheCall,
     StringRef NonStreamingBuiltinGuard = StringRef(RequiredFeatures, PipeIdx);
     StringRef StreamingBuiltinGuard = StringRef(RequiredFeatures + PipeIdx + 
1);
 
-    if (S.Context.getTargetInfo().hasFeatureEnabled(CallerFeatures, "sve"))
+    if (CallerHasSVE)
       CallerFeatures["sve"] = true;
-    if (S.Context.getTargetInfo().hasFeatureEnabled(CallerFeatures, "sme"))
+    if (CallerHasSME)
       CallerFeatures["sme"] = true;
 
     bool SatisfiesSVE = Builtin::evaluateRequiredTargetFeatures(
@@ -1478,11 +1480,13 @@ void SemaARM::CheckSMEFunctionDefAttributes(const 
FunctionDecl *FD) {
                FunctionType::ARM_None;
   }
 
-  ASTContext &Context = getASTContext();
-  if (UsesSM || UsesZA) {
+  if (UsesSM || UsesZA || UsesZT0) {
+    ASTContext &Context = getASTContext();
     llvm::StringMap<bool> FeatureMap;
     Context.getFunctionFeatureMap(FeatureMap, FD);
-    if (!Context.getTargetInfo().hasFeatureEnabled(FeatureMap, "sme")) {
+    const TargetInfo &TI = Context.getTargetInfo();
+
+    if ((UsesSM || UsesZA) && !TI.hasFeatureEnabled(FeatureMap, "sme")) {
       if (UsesSM)
         Diag(FD->getLocation(),
              diag::err_sme_definition_using_sm_in_non_sme_target);
@@ -1490,11 +1494,8 @@ void SemaARM::CheckSMEFunctionDefAttributes(const 
FunctionDecl *FD) {
         Diag(FD->getLocation(),
              diag::err_sme_definition_using_za_in_non_sme_target);
     }
-  }
-  if (UsesZT0) {
-    llvm::StringMap<bool> FeatureMap;
-    Context.getFunctionFeatureMap(FeatureMap, FD);
-    if (!Context.getTargetInfo().hasFeatureEnabled(FeatureMap, "sme2")) {
+
+    if (UsesZT0 && !TI.hasFeatureEnabled(FeatureMap, "sme2")) {
       Diag(FD->getLocation(),
            diag::err_sme_definition_using_zt0_in_non_sme2_target);
     }
@@ -1767,11 +1768,15 @@ bool SemaARM::checkSVETypeSupport(QualType Ty, 
SourceLocation Loc,
   if (!Ty->isSVESizelessBuiltinType())
     return false;
 
-  if (getASTContext().getTargetInfo().hasFeatureEnabled(FeatureMap, "sve"))
+  const TargetInfo &TI = getASTContext().getTargetInfo();
+  bool HasSVE = TI.hasFeatureEnabled(FeatureMap, "sve");
+  bool HasSME = TI.hasFeatureEnabled(FeatureMap, "sme");
+
+  if (HasSVE)
     return false;
 
   // No SVE environment available.
-  if (!getASTContext().getTargetInfo().hasFeatureEnabled(FeatureMap, "sme"))
+  if (!HasSME)
     return Diag(Loc, diag::err_sve_vector_in_non_sve_target) << Ty;
 
   // SVE environment only available to streaming functions.

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

Reply via email to