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
