https://github.com/w2yehia updated https://github.com/llvm/llvm-project/pull/206786
>From e08d4f4208366811fb329bd090dfbcace3d3e887 Mon Sep 17 00:00:00 2001 From: Wael Yehia <[email protected]> Date: Mon, 29 Jun 2026 17:28:53 +0000 Subject: [PATCH 01/15] proto 1 by bob add TODO in Sema/SemaPPC.cpp add Sema test add tests and remove isel from runtime-detected features since it's always available remove cmpb and fprnd from runtime-detected features since it's always available fix codegen for no-FEATURE documentation priority of features in powerXX should be between cpu=powerXX and cpu=power(XX+1) clang-format --- clang/include/clang/Basic/AttrDocs.td | 8 +- .../clang/Basic/DiagnosticSemaKinds.td | 4 + clang/include/clang/Basic/TargetInfo.h | 12 ++ clang/lib/AST/ASTContext.cpp | 7 +- clang/lib/Basic/Targets/PPC.cpp | 132 +++++++++++++++++- clang/lib/Basic/Targets/PPC.h | 13 +- clang/lib/CodeGen/CodeGenFunction.cpp | 55 ++++++-- clang/lib/CodeGen/Targets/PPC.cpp | 28 +++- clang/lib/Sema/SemaPPC.cpp | 55 +++++++- .../CodeGen/PowerPC/attr-target-clones-mma.c | 16 +++ .../test/CodeGen/PowerPC/attr-target-clones.c | 89 ++++++++++++ clang/test/Sema/PowerPC/attr-target-clones.c | 99 ++++++++++++- 12 files changed, 482 insertions(+), 36 deletions(-) create mode 100644 clang/test/CodeGen/PowerPC/attr-target-clones-mma.c diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 3052dd6c77ab1..26392cead7cc3 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -3439,8 +3439,12 @@ For backward compatibility with earlier Clang releases, a function alias with an `.ifunc` suffix is also emitted. The `.ifunc` suffixed symbol is a deprecated feature and support for it may be removed in the future. -For PowerPC targets, `target_clones` is supported on AIX only. Only CPU -(specified as `cpu=CPU`) and `default` options are allowed. IFUNC is supported +For PowerPC targets, `target_clones` is supported on AIX only. The attribute +contains comma-separated strings of one of: +(a) `default`, (b) `cpu=CPU`, (c) `FEATURE` or `no-FEATURE`. +The minimum CPU supported is `pwr7` (long spelling such as `power7` is accepted). +The list of target features is a subset of what's allowed on `target`, limited +to what is detectable at runtime using `__builtin_cpu_supports`. IFUNC is supported on AIX in Clang, so dispatch is implemented similar to other targets using IFUNC. An FMV function that is only declared in a translation unit is treated as a non-FMV. The resolver and the function clones are given internal linkage. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index b314c17ad27bd..6a9389ba3994d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11584,6 +11584,10 @@ def err_ppc_invalid_test_data_class_type : Error< "expected a 'float', 'double' or '__float128' for the first argument">; def err_ppc_invalid_arg_type : Error< "argument %0 must be of type %1">; +def err_ppc_feature_no_runtime_detection : Error< + "feature '%0' cannot be used with 'target_clones' because it has no " + "runtime detection; use 'target' attribute instead">; + def err_x86_builtin_invalid_rounding : Error< "invalid rounding argument">; def err_x86_builtin_invalid_scale : Error< diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 6311b6b567a5e..9baacffc81493 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1469,6 +1469,18 @@ class TargetInfo : public TransferrableTargetInfo, return true; } + /// Validate feature name for target_clones attribute (subset with runtime + /// detection) Default implementation delegates to isValidFeatureName + virtual bool isValidClonesFeatureName(StringRef Feature) const { + return isValidFeatureName(Feature); + } + + /// Get __builtin_cpu_supports() argument for a feature + /// Returns empty string if feature has no runtime detection + virtual StringRef getBuiltinCpuSupportsName(StringRef Feature) const { + return ""; + } + /// Returns true if feature has an impact on target code /// generation. virtual bool doesFeatureAffectCodeGen(StringRef Feature) const { diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 35a2a0b131a3f..17e2605f13f35 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -15422,8 +15422,11 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap, StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex()); if (VersionStr.starts_with("cpu=")) TargetCPU = VersionStr.drop_front(sizeof("cpu=") - 1); - else - assert(VersionStr == "default"); + else if (VersionStr != "default") { + // Handle feature strings + ParsedTargetAttr ParsedAttr = Target->parseTargetAttr(VersionStr); + Features = ParsedAttr.Features; + } Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features); } else { std::vector<std::string> Features; diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp index 1ecb474c1ede8..143c1ef1cc00f 100644 --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -727,17 +727,54 @@ llvm::APInt PPCTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const { return llvm::APInt(32, 0); assert(Features.size() == 1 && "one feature/cpu per clone on PowerPC"); ParsedTargetAttr ParsedAttr = parseTargetAttr(Features[0]); + + // Priority scheme: Features requiring POWERXX are higher than cpu=pwrXX + // but lower than cpu=pwr(XX+1). This ensures proper version selection. + // Example: mma (POWER10 feature) > cpu=pwr10 > power9-vector (POWER9 feature) + if (!ParsedAttr.CPU.empty()) { int Priority = llvm::StringSwitch<int>(ParsedAttr.CPU) - .Case("pwr7", 1) - .Case("pwr8", 2) - .Case("pwr9", 3) - .Case("pwr10", 4) - .Case("pwr11", 5) + .Case("pwr7", 100) + .Case("pwr8", 200) + .Case("pwr9", 300) + .Case("pwr10", 400) + .Case("pwr11", 500) .Default(0); return llvm::APInt(32, Priority); } - assert(false && "unimplemented"); + + // Feature strings: priority between cpu=pwrN and cpu=pwr(N+1) + if (!ParsedAttr.Features.empty()) { + StringRef Feature = ParsedAttr.Features[0]; + // Remove leading '+' or '-' + if (Feature.starts_with("+") || Feature.starts_with("-")) + Feature = Feature.drop_front(1); + + int Priority = llvm::StringSwitch<int>(Feature) + // POWER10 features (between pwr10=400 and pwr11=500) + .Case("mma", 419) + .Case("paired-vector-memops", 418) + .Case("pcrel", 417) + .Case("power10-vector", 416) + .Case("prefixed", 415) + // POWER9 features (between pwr9=300 and pwr10=400) + .Case("float128", 312) + .Case("power9-vector", 311) + // POWER8 features (between pwr8=200 and pwr9=300) + .Case("crypto", 214) + .Case("direct-move", 213) + .Case("power8-vector", 212) + .Case("htm", 211) + // POWER7 features (between pwr7=100 and pwr8=200) + .Case("popcntd", 112) + .Case("vsx", 111) + // Base features: 50-99 (below pwr7=100) + .Case("altivec", 50) + .Default(0); + + return llvm::APInt(32, Priority); + } + return llvm::APInt(32, 0); } @@ -830,6 +867,89 @@ void PPCTargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const { llvm::PPC::fillValidCPUList(Values); } +bool PPCTargetInfo::isValidFeatureName(StringRef Name) const { + // All 28 PPC features valid for target attribute + return llvm::StringSwitch<bool>(Name) + // Features with runtime detection (valid for target_clones) + .Case("altivec", true) + .Case("htm", true) + .Case("mma", true) + .Case("vsx", true) + .Case("crypto", true) + .Case("direct-move", true) + .Case("float128", true) + .Case("paired-vector-memops", true) + .Case("pcrel", true) + .Case("popcntd", true) + .Case("power8-vector", true) + .Case("power9-vector", true) + .Case("power10-vector", true) + .Case("prefixed", true) + // Features without runtime checks (NOT valid for target_clones) + .Case("aix-shared-lib-tls-model-opt", true) + .Case("aix-small-local-dynamic-tls", true) + .Case("aix-small-local-exec-tls", true) + .Case("cmpb", true) + .Case("crbits", true) + .Case("fprnd", true) + .Case("invariant-function-descriptors", true) + .Case("isel", true) + .Case("longcall", true) + .Case("mfcrf", true) + .Case("mfocrf", true) + .Case("privileged", true) + .Case("rop-protect", true) + .Case("secure-plt", true) + .Default(false); +} + +bool PPCTargetInfo::isValidClonesFeatureName(StringRef Name) const { + // Only 14 features with runtime detection are valid for target_clones + return llvm::StringSwitch<bool>(Name) + // Direct mappings (4 features) + .Case("altivec", true) + .Case("htm", true) + .Case("mma", true) + .Case("vsx", true) + // ISA level mappings (10 features) + .Case("crypto", true) + .Case("direct-move", true) + .Case("float128", true) + .Case("paired-vector-memops", true) + .Case("pcrel", true) + .Case("popcntd", true) + .Case("power8-vector", true) + .Case("power9-vector", true) + .Case("power10-vector", true) + .Case("prefixed", true) + .Default(false); +} + +StringRef +PPCTargetInfo::getBuiltinCpuSupportsName(StringRef FeatureName) const { + // Map feature names to __builtin_cpu_supports() strings + // Only returns non-empty for features with runtime detection + return llvm::StringSwitch<StringRef>(FeatureName) + // Direct mappings (4 features) + .Case("altivec", "altivec") + .Case("htm", "htm") + .Case("mma", "mma") + .Case("vsx", "vsx") + // ISA level mappings (10 features) + .Case("popcntd", "arch_2_06") + .Case("crypto", "arch_2_07") + .Case("direct-move", "arch_2_07") + .Case("power8-vector", "arch_2_07") + .Case("float128", "arch_3_00") + .Case("power9-vector", "arch_3_00") + .Case("paired-vector-memops", "arch_3_1") + .Case("pcrel", "arch_3_1") + .Case("power10-vector", "arch_3_1") + .Case("prefixed", "arch_3_1") + // Features without runtime checks return empty string + .Default(""); +} + void PPCTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts, const TargetInfo *Aux) { if (HasAltivec) diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h index 22880e5a04a3f..e46daaa85a993 100644 --- a/clang/lib/Basic/Targets/PPC.h +++ b/clang/lib/Basic/Targets/PPC.h @@ -98,7 +98,18 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo { bool isValidCPUName(StringRef Name) const override; void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; - bool setCPU(StringRef Name) override { + // Validate feature name for target attribute (all 28 features) + bool isValidFeatureName(StringRef Name) const override; + + // Validate feature name for target_clones (only 17 features with runtime + // detection) + bool isValidClonesFeatureName(StringRef Name) const; + + // Get __builtin_cpu_supports() argument for a feature (returns empty string + // if no runtime check) + StringRef getBuiltinCpuSupportsName(StringRef FeatureName) const; + + bool setCPU(StringRef &Name) override { bool CPUKnown = isValidCPUName(Name); if (CPUKnown) { CPU = Name; diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 119aebb673789..0a90a6041816d 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -3149,18 +3149,49 @@ void CodeGenFunction::EmitPPCAIXMultiVersionResolver( assert(RO.Features.size() == 1 && "for now one feature requirement per version"); - assert(RO.Features[0].starts_with("cpu=")); - StringRef CPU = RO.Features[0].split("=").second.trim(); - StringRef Feature = llvm::StringSwitch<StringRef>(CPU) - .Case("pwr7", "arch_2_06") - .Case("pwr8", "arch_2_07") - .Case("pwr9", "arch_3_00") - .Case("pwr10", "arch_3_1") - .Case("pwr11", "arch_3_1") - .Default("error"); - - llvm::Value *Condition = EmitPPCBuiltinCpu( - Builtin::BI__builtin_cpu_supports, Builder.getInt1Ty(), Feature); + StringRef FeatureStr = RO.Features[0]; + StringRef BuiltinCpuSupportsArg; + bool IsNegated = false; + + if (FeatureStr.starts_with("cpu=")) { + // CPU specification - map to ISA level + StringRef CPU = FeatureStr.split("=").second.trim(); + BuiltinCpuSupportsArg = llvm::StringSwitch<StringRef>(CPU) + .Case("pwr7", "arch_2_06") + .Case("pwr8", "arch_2_07") + .Case("pwr9", "arch_3_00") + .Case("pwr10", "arch_3_1") + .Case("pwr11", "arch_3_1") + .Default("error"); + } else { + // Feature string - check for "no-" negation prefix + StringRef BaseFeature = FeatureStr; + + // Feature strings arrive here already normalized: + // - Positive features: just the name (e.g., "altivec") + // - Negated features: "no-" prefix (e.g., "no-altivec") + if (BaseFeature.starts_with("no-")) { + IsNegated = true; + BaseFeature = BaseFeature.drop_front(3); + } + + BuiltinCpuSupportsArg = + getTarget().getBuiltinCpuSupportsName(BaseFeature); + + // All features in target_clones must have runtime detection + assert(!BuiltinCpuSupportsArg.empty() && + "feature without runtime detection should have been rejected in " + "Sema"); + } + + llvm::Value *Condition = + EmitPPCBuiltinCpu(Builtin::BI__builtin_cpu_supports, + Builder.getInt1Ty(), BuiltinCpuSupportsArg); + + // Negate the condition if this is a negated feature + if (IsNegated) { + Condition = Builder.CreateNot(Condition, "neg"); + } llvm::BasicBlock *ThenBlock = createBasicBlock("if.version", Resolver); CurBlock = createBasicBlock("if.else", Resolver); diff --git a/clang/lib/CodeGen/Targets/PPC.cpp b/clang/lib/CodeGen/Targets/PPC.cpp index a87f841063650..449ca39b9faba 100644 --- a/clang/lib/CodeGen/Targets/PPC.cpp +++ b/clang/lib/CodeGen/Targets/PPC.cpp @@ -158,7 +158,33 @@ void AIXABIInfo::appendAttributeMangling(StringRef AttrStr, return; } - assert(0 && "specifying target features on an FMV is unsupported on AIX"); + // Handle feature strings + if (!Info.Features.empty()) { + assert(Info.Features.size() == 1 && "one feature per version for now"); + StringRef Feature = Info.Features[0]; + std::string MangledFeature; + + // Handle negation prefix "no-" specially - convert to "no_" + if (Feature.starts_with("no-")) { + MangledFeature = "no_"; + Feature = Feature.drop_front(3); + } else if (Feature.starts_with("+")) { + // Remove leading '+' for positive features + Feature = Feature.drop_front(1); + } else if (Feature.starts_with("-")) { + // Leading '-' means negation, convert to "no_" + MangledFeature = "no_"; + Feature = Feature.drop_front(1); + } + + // Append the base feature name and replace hyphens with underscores + MangledFeature += Feature.str(); + std::replace(MangledFeature.begin(), MangledFeature.end(), '-', '_'); + Out << "." << MangledFeature; + return; + } + + llvm_unreachable("Invalid target_clones parameter"); } class AIXTargetCodeGenInfo : public TargetCodeGenInfo { diff --git a/clang/lib/Sema/SemaPPC.cpp b/clang/lib/Sema/SemaPPC.cpp index 8a594fc86dea6..be76bac5de6c8 100644 --- a/clang/lib/Sema/SemaPPC.cpp +++ b/clang/lib/Sema/SemaPPC.cpp @@ -618,21 +618,32 @@ bool SemaPPC::checkTargetClonesAttr(const SmallVectorImpl<StringRef> &Params, const StringRef Param = Params[I].trim(); const SourceLocation &Loc = Locs[I]; - if (Param.empty() || Param.ends_with(',')) - return Diag(Loc, diag::warn_unsupported_target_attribute) - << Unsupported << None << "" << TargetClones; - if (Param.contains(',')) HasComma = true; StringRef LHS; StringRef RHS = Param; + // TODO: simplify the logic to diagnose empty strings + bool checkTrailingEmpty = false; do { std::tie(LHS, RHS) = RHS.split(','); LHS = LHS.trim(); + + // After processing last non-empty item, check if we need to process + // trailing empty + if (RHS.empty() && !LHS.empty() && Param.ends_with(',')) { + checkTrailingEmpty = true; + } + const SourceLocation &CurLoc = Loc.getLocWithOffset(LHS.data() - Param.data()); + // Check for empty string (from trailing comma, leading comma, or ",,") + if (LHS.empty()) { + return Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unknown << None << "" << TargetClones; + } + if (LHS.starts_with("cpu=")) { StringRef CPUStr = LHS.drop_front(sizeof("cpu=") - 1); if (!TargetInfo.isValidCPUName(CPUStr)) @@ -644,9 +655,30 @@ bool SemaPPC::checkTargetClonesAttr(const SmallVectorImpl<StringRef> &Params, } else if (LHS == "default") { HasDefault = true; } else { - // it's a feature string, but not supported yet. - return Diag(CurLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << LHS << TargetClones; + // Handle feature strings + StringRef FeatureName = LHS; + bool IsNegated = false; + + // Check for negation prefix + if (FeatureName.starts_with("no-")) { + IsNegated = true; + FeatureName = FeatureName.drop_front(3); + } + + // First check if it's a valid feature name at all + if (!TargetInfo.isValidFeatureName(FeatureName)) { + return Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unknown << None << LHS << TargetClones; + } + + // Check if feature is valid for target_clones (has runtime detection) + // Use virtual method that defaults to isValidFeatureName for non-PPC + // targets + if (!TargetInfo.isValidClonesFeatureName(FeatureName)) { + // Feature is valid for target attribute but not target_clones + return Diag(CurLoc, diag::err_ppc_feature_no_runtime_detection) + << FeatureName; + } } SmallString<64> CPU; if (LHS.starts_with("cpu=")) { @@ -660,6 +692,15 @@ bool SemaPPC::checkTargetClonesAttr(const SmallVectorImpl<StringRef> &Params, continue; } NewParams.push_back(LHS); + + // If we just processed the last item and there's a trailing comma, + // do one more iteration to catch the empty string + if (checkTrailingEmpty) { + LHS = ""; + const SourceLocation &EmptyCurLoc = Loc.getLocWithOffset(Param.size()); + return Diag(EmptyCurLoc, diag::warn_unsupported_target_attribute) + << Unknown << None << "" << TargetClones; + } } while (!RHS.empty()); } if (HasComma && Params.size() > 1) diff --git a/clang/test/CodeGen/PowerPC/attr-target-clones-mma.c b/clang/test/CodeGen/PowerPC/attr-target-clones-mma.c new file mode 100644 index 0000000000000..8e069eb17d64c --- /dev/null +++ b/clang/test/CodeGen/PowerPC/attr-target-clones-mma.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -target-cpu pwr10 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -target-cpu pwr10 -emit-llvm %s -o - | FileCheck %s + +// Test MMA feature which requires pwr10 +int __attribute__((target_clones("mma", "default"))) +foo_mma(void) { return 0; } +// CHECK: define internal {{.*}}i32 @foo_mma.mma() +// CHECK: define internal {{.*}}i32 @foo_mma.default() +// CHECK: define internal ptr @foo_mma.resolver() +// if (__builtin_cpu_supports("mma")) return &foo_mma.mma; +// CHECK: %[[#MMA:]] = call i64 @getsystemcfg(i32 62) +// CHECK-NEXT: icmp ugt i64 %[[#MMA]], 0 +// CHECK: ret ptr @foo_mma.mma +// CHECK: ret ptr @foo_mma.default + +// CHECK: declare i64 @getsystemcfg(i32) diff --git a/clang/test/CodeGen/PowerPC/attr-target-clones.c b/clang/test/CodeGen/PowerPC/attr-target-clones.c index c8cc9f2204b65..40f5a31f693e2 100644 --- a/clang/test/CodeGen/PowerPC/attr-target-clones.c +++ b/clang/test/CodeGen/PowerPC/attr-target-clones.c @@ -134,6 +134,95 @@ foo_priority(int x) { return x & (x - 1); } // CHECK: ret ptr @foo_priority.default +// Test feature-based target_clones +int __attribute__((target_clones("altivec", "default"))) +foo_altivec(void) { return 0; } +// CHECK: define internal {{.*}}i32 @foo_altivec.altivec() +// CHECK: define internal {{.*}}i32 @foo_altivec.default() +// CHECK: define internal ptr @foo_altivec.resolver() +// if (__builtin_cpu_supports("altivec")) return &foo_altivec.altivec; +// CHECK: %[[#ALTIVEC:]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @_system_configuration, {{i32|i64}} 204) +// CHECK-NEXT: icmp ugt i32 %[[#ALTIVEC]], 0 +// CHECK: ret ptr @foo_altivec.altivec +// CHECK: ret ptr @foo_altivec.default + +int __attribute__((target_clones("vsx", "default"))) +foo_vsx(void) { return 0; } +// CHECK: define internal {{.*}}i32 @foo_vsx.vsx() +// CHECK: define internal {{.*}}i32 @foo_vsx.default() +// CHECK: define internal ptr @foo_vsx.resolver() +// if (__builtin_cpu_supports("vsx")) return &foo_vsx.vsx; +// CHECK: %[[#VSX:]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @_system_configuration, {{i32|i64}} 204) +// CHECK-NEXT: icmp ugt i32 %[[#VSX]], 1 +// CHECK: ret ptr @foo_vsx.vsx +// CHECK: ret ptr @foo_vsx.default + +int __attribute__((target_clones("htm", "default"))) +foo_htm(void) { return 0; } +// CHECK: define internal {{.*}}i32 @foo_htm.htm() +// CHECK: define internal {{.*}}i32 @foo_htm.default() +// CHECK: define internal ptr @foo_htm.resolver() +// if (__builtin_cpu_supports("htm")) return &foo_htm.htm; +// CHECK: %[[#HTM:]] = call i64 @getsystemcfg(i32 59) +// CHECK-NEXT: icmp ugt i64 %[[#HTM]], 0 +// CHECK: ret ptr @foo_htm.htm +// CHECK: ret ptr @foo_htm.default + + + +// Test multiple features with priority ordering (random source order) +// Source order: altivec, power8-vector, cpu=pwr11, vsx, power9-vector, default +// Resolver order by priority: cpu=pwr11 (500) > power9-vector (311) > power8-vector (212) > vsx (111) > altivec (50) > default (0) +int __attribute__((target_clones("altivec", "power8-vector", "cpu=pwr11", "vsx", "power9-vector", "default"))) +foo_multi_features(void) { return 0; } +// CHECK: define internal {{.*}}i32 @foo_multi_features.altivec() +// CHECK: define internal {{.*}}i32 @foo_multi_features.power8_vector() +// CHECK: define internal {{.*}}i32 @foo_multi_features.cpu_pwr11() #[[#ATTR_P11]] +// CHECK: define internal {{.*}}i32 @foo_multi_features.vsx() +// CHECK: define internal {{.*}}i32 @foo_multi_features.power9_vector() +// CHECK: define internal {{.*}}i32 @foo_multi_features.default() +// CHECK: define internal ptr @foo_multi_features.resolver() +// Resolver checks in priority order (highest first): +// if (__builtin_cpu_supports("arch_3_1")) return &foo_multi_features.cpu_pwr11; +// CHECK: load i32, ptr getelementptr inbounds nuw (i8, ptr @_system_configuration, {{i32|i64}} 4) +// CHECK-NEXT: icmp uge i32 {{.*}}, 262144 +// CHECK: ret ptr @foo_multi_features.cpu_pwr11 +// if (__builtin_cpu_supports("arch_3_00")) return &foo_multi_features.power9_vector; +// CHECK: load i32, ptr getelementptr inbounds nuw (i8, ptr @_system_configuration, {{i32|i64}} 4) +// CHECK-NEXT: icmp uge i32 {{.*}}, 131072 +// CHECK: ret ptr @foo_multi_features.power9_vector +// if (__builtin_cpu_supports("arch_2_07")) return &foo_multi_features.power8_vector; +// CHECK: load i32, ptr getelementptr inbounds nuw (i8, ptr @_system_configuration, {{i32|i64}} 4) +// CHECK-NEXT: icmp uge i32 {{.*}}, 65536 +// CHECK: ret ptr @foo_multi_features.power8_vector +// if (__builtin_cpu_supports("vsx")) return &foo_multi_features.vsx; +// CHECK: %[[#VSX2:]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @_system_configuration, {{i32|i64}} 204) +// CHECK-NEXT: icmp ugt i32 %[[#VSX2]], 1 +// CHECK: ret ptr @foo_multi_features.vsx +// if (__builtin_cpu_supports("altivec")) return &foo_multi_features.altivec; +// CHECK: %[[#ALTIVEC2:]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @_system_configuration, {{i32|i64}} 204) +// CHECK-NEXT: icmp ugt i32 %[[#ALTIVEC2]], 0 +// CHECK: ret ptr @foo_multi_features.altivec +// CHECK: ret ptr @foo_multi_features.default + +// Test negated feature (no-altivec) - should negate the condition +int __attribute__((target_clones("no-altivec", "default"))) +foo_no_altivec(void) { return 0; } +// CHECK: define internal {{.*}}i32 @foo_no_altivec.no_altivec() +// CHECK: define internal {{.*}}i32 @foo_no_altivec.default() +// CHECK: define internal ptr @foo_no_altivec.resolver() +// if (!__builtin_cpu_supports("altivec")) return &foo_no_altivec.no_altivec; +// CHECK: load i32, ptr getelementptr inbounds nuw (i8, ptr @_system_configuration, {{i32|i64}} 204) +// CHECK-NEXT: icmp ugt i32 +// CHECK-NEXT: %neg = xor i1 {{.*}}, true +// CHECK-NEXT: br i1 %neg, label %if.version, label %if.else +// CHECK: if.version: +// CHECK-NEXT: ret ptr @foo_no_altivec.no_altivec +// CHECK: if.else: +// CHECK-NEXT: ret ptr @foo_no_altivec.default + +// CHECK: declare i64 @getsystemcfg(i32) + // CHECK: attributes #[[#ATTR_P7]] = {{.*}} "target-cpu"="pwr7" // CHECK: attributes #[[#ATTR_P10]] = {{.*}} "target-cpu"="pwr10" // CHECK: attributes #[[#ATTR_P11]] = {{.*}} "target-cpu"="pwr11" diff --git a/clang/test/Sema/PowerPC/attr-target-clones.c b/clang/test/Sema/PowerPC/attr-target-clones.c index 96acc974320b0..0f078fa2e805c 100644 --- a/clang/test/Sema/PowerPC/attr-target-clones.c +++ b/clang/test/Sema/PowerPC/attr-target-clones.c @@ -42,20 +42,20 @@ int __attribute__((target_clones("cpu=pwr9,default"))) redef3(void) { return 1; int __attribute__((target_clones("cpu=pwr9,cpu=power9", "cpu=power9, default"))) dupes(void) { return 1; } -// expected-warning@+1 {{unsupported '' in the 'target_clones' attribute string;}} +// expected-warning@+1 {{unknown '' in the 'target_clones' attribute string;}} void __attribute__((target_clones(""))) empty_target_1(void); -// expected-warning@+1 {{unsupported '' in the 'target_clones' attribute string;}} +// expected-warning@+1 {{unknown '' in the 'target_clones' attribute string;}} void __attribute__((target_clones(",default"))) empty_target_2(void); -// expected-warning@+1 {{unsupported '' in the 'target_clones' attribute string;}} +// expected-warning@+1 {{unknown '' in the 'target_clones' attribute string;}} void __attribute__((target_clones("default,"))) empty_target_3(void); -// expected-warning@+1 {{unsupported '' in the 'target_clones' attribute string;}} +// expected-warning@+1 {{unknown '' in the 'target_clones' attribute string;}} void __attribute__((target_clones("default, ,cpu=pwr7"))) empty_target_4(void); -// expected-warning@+1 {{unsupported '' in the 'target_clones' attribute string;}} +// expected-warning@+1 {{unknown '' in the 'target_clones' attribute string;}} void __attribute__((target_clones("default,cpu=pwr7", ""))) empty_target_5(void); @@ -130,3 +130,92 @@ gh173684_empty_attribute_args(void); // expected-error@+1 {{'target_clones' multiversioning requires a default target}} void __attribute__((target_clones)) gh173684_empty_attribute_args_2(void); + +// TODO: Consider combining some of these tests into fewer test cases with multiple features +// e.g., target_clones("feature1", "feature2", "feature3", ..., "default") to test +// feature1, feature2, feature3 all in one declaration instead of separate functions + +// Test that all valid feature names are accepted (no diagnostics expected) +void __attribute__((target_clones("altivec", "default"))) +valid_feature_altivec(void); + +void __attribute__((target_clones("vsx", "default"))) +valid_feature_vsx(void); + +void __attribute__((target_clones("crypto", "default"))) +valid_feature_crypto(void); + +void __attribute__((target_clones("power8-vector", "default"))) +valid_feature_power8_vector(void); + +void __attribute__((target_clones("power9-vector", "default"))) +valid_feature_power9_vector(void); + +void __attribute__((target_clones("power10-vector", "default"))) +valid_feature_power10_vector(void); + +void __attribute__((target_clones("mma", "default"))) +valid_feature_mma(void); + +void __attribute__((target_clones("htm", "default"))) +valid_feature_htm(void); + +// isel is always available on AIX (no runtime check), so it's not valid for target_clones +// expected-error@+1 {{feature 'isel' cannot be used with 'target_clones' because it has no runtime detection; use 'target' attribute instead}} +void __attribute__((target_clones("isel", "default"))) +invalid_feature_isel(void); + +// expected-error@+1 {{feature 'isel' cannot be used with 'target_clones' because it has no runtime detection; use 'target' attribute instead}} +void __attribute__((target_clones("no-isel", "default"))) +invalid_feature_no_isel(void); + +// Test that negated valid feature names are accepted (no diagnostics expected) +void __attribute__((target_clones("no-altivec", "default"))) +valid_feature_no_altivec(void); + +void __attribute__((target_clones("no-vsx", "default"))) +valid_feature_no_vsx(void); + +void __attribute__((target_clones("no-crypto", "default"))) +valid_feature_no_crypto(void); + +void __attribute__((target_clones("no-power8-vector", "default"))) +valid_feature_no_power8_vector(void); + +void __attribute__((target_clones("no-power9-vector", "default"))) +valid_feature_no_power9_vector(void); + +void __attribute__((target_clones("no-power10-vector", "default"))) +valid_feature_no_power10_vector(void); + +void __attribute__((target_clones("no-mma", "default"))) +valid_feature_no_mma(void); + +void __attribute__((target_clones("no-htm", "default"))) +valid_feature_no_htm(void); + +// Test multiple valid features together (one example with mixing warning) +// expected-warning@+1 {{mixing 'target_clones' specifier mechanisms is permitted for GCC compatibility}} +void __attribute__((target_clones("altivec,vsx", "default"))) +valid_multiple_features_1(void); + +// Use separate string literals to avoid mixing warning +void __attribute__((target_clones("vsx", "crypto", "htm", "default"))) +valid_multiple_features_2(void); + +void __attribute__((target_clones("power9-vector", "mma", "default"))) +valid_multiple_features_3(void); + +// Test mix of features and negations +void __attribute__((target_clones("altivec", "no-vsx", "default"))) +valid_mixed_features_1(void); + +void __attribute__((target_clones("vsx", "no-crypto", "default"))) +valid_mixed_features_2(void); + +// Test features with CPU specifications +void __attribute__((target_clones("altivec", "cpu=pwr8", "default"))) +valid_feature_with_cpu_1(void); + +void __attribute__((target_clones("vsx", "crypto", "cpu=pwr9", "default"))) +valid_feature_with_cpu_2(void); >From ce04e1024df199207457429cda04da0d93c14451 Mon Sep 17 00:00:00 2001 From: Wael Yehia <[email protected]> Date: Wed, 1 Jul 2026 02:37:23 +0000 Subject: [PATCH 02/15] pcrel is not supported on AIX, reject it from target/target_clones --- clang/lib/Basic/Targets/PPC.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp index 143c1ef1cc00f..077b35003e17c 100644 --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -754,7 +754,6 @@ llvm::APInt PPCTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const { // POWER10 features (between pwr10=400 and pwr11=500) .Case("mma", 419) .Case("paired-vector-memops", 418) - .Case("pcrel", 417) .Case("power10-vector", 416) .Case("prefixed", 415) // POWER9 features (between pwr9=300 and pwr10=400) @@ -868,9 +867,9 @@ void PPCTargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const { } bool PPCTargetInfo::isValidFeatureName(StringRef Name) const { - // All 28 PPC features valid for target attribute + if (!getTriple().isOSAIX()) + return TargetInfo::isValidFeatureName(Name); return llvm::StringSwitch<bool>(Name) - // Features with runtime detection (valid for target_clones) .Case("altivec", true) .Case("htm", true) .Case("mma", true) @@ -879,13 +878,11 @@ bool PPCTargetInfo::isValidFeatureName(StringRef Name) const { .Case("direct-move", true) .Case("float128", true) .Case("paired-vector-memops", true) - .Case("pcrel", true) .Case("popcntd", true) .Case("power8-vector", true) .Case("power9-vector", true) .Case("power10-vector", true) .Case("prefixed", true) - // Features without runtime checks (NOT valid for target_clones) .Case("aix-shared-lib-tls-model-opt", true) .Case("aix-small-local-dynamic-tls", true) .Case("aix-small-local-exec-tls", true) @@ -916,7 +913,6 @@ bool PPCTargetInfo::isValidClonesFeatureName(StringRef Name) const { .Case("direct-move", true) .Case("float128", true) .Case("paired-vector-memops", true) - .Case("pcrel", true) .Case("popcntd", true) .Case("power8-vector", true) .Case("power9-vector", true) @@ -943,7 +939,6 @@ PPCTargetInfo::getBuiltinCpuSupportsName(StringRef FeatureName) const { .Case("float128", "arch_3_00") .Case("power9-vector", "arch_3_00") .Case("paired-vector-memops", "arch_3_1") - .Case("pcrel", "arch_3_1") .Case("power10-vector", "arch_3_1") .Case("prefixed", "arch_3_1") // Features without runtime checks return empty string >From 5d05e49c2c45861583c61fb1c7ae33e460137ee8 Mon Sep 17 00:00:00 2001 From: Wael Yehia <[email protected]> Date: Wed, 1 Jul 2026 03:01:53 +0000 Subject: [PATCH 03/15] merge attr-target-clones-mma.c into attr-target-clones.c --- .../CodeGen/PowerPC/attr-target-clones-mma.c | 16 ---------------- clang/test/CodeGen/PowerPC/attr-target-clones.c | 14 +++++++++++++- 2 files changed, 13 insertions(+), 17 deletions(-) delete mode 100644 clang/test/CodeGen/PowerPC/attr-target-clones-mma.c diff --git a/clang/test/CodeGen/PowerPC/attr-target-clones-mma.c b/clang/test/CodeGen/PowerPC/attr-target-clones-mma.c deleted file mode 100644 index 8e069eb17d64c..0000000000000 --- a/clang/test/CodeGen/PowerPC/attr-target-clones-mma.c +++ /dev/null @@ -1,16 +0,0 @@ -// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -target-cpu pwr10 -emit-llvm %s -o - | FileCheck %s -// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -target-cpu pwr10 -emit-llvm %s -o - | FileCheck %s - -// Test MMA feature which requires pwr10 -int __attribute__((target_clones("mma", "default"))) -foo_mma(void) { return 0; } -// CHECK: define internal {{.*}}i32 @foo_mma.mma() -// CHECK: define internal {{.*}}i32 @foo_mma.default() -// CHECK: define internal ptr @foo_mma.resolver() -// if (__builtin_cpu_supports("mma")) return &foo_mma.mma; -// CHECK: %[[#MMA:]] = call i64 @getsystemcfg(i32 62) -// CHECK-NEXT: icmp ugt i64 %[[#MMA]], 0 -// CHECK: ret ptr @foo_mma.mma -// CHECK: ret ptr @foo_mma.default - -// CHECK: declare i64 @getsystemcfg(i32) diff --git a/clang/test/CodeGen/PowerPC/attr-target-clones.c b/clang/test/CodeGen/PowerPC/attr-target-clones.c index 40f5a31f693e2..48557660929b1 100644 --- a/clang/test/CodeGen/PowerPC/attr-target-clones.c +++ b/clang/test/CodeGen/PowerPC/attr-target-clones.c @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -target-cpu pwr7 -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -target-cpu pwr7 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -target-cpu pwr10 -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-P10 // CHECK: @internal = internal ifunc i32 (), ptr @internal.resolver // CHECK: @foo = ifunc i32 (), ptr @foo.resolver @@ -168,7 +169,18 @@ foo_htm(void) { return 0; } // CHECK: ret ptr @foo_htm.htm // CHECK: ret ptr @foo_htm.default - +#ifdef _ARCH_PWR10 +int __attribute__((target_clones("mma", "default"))) +foo_mma(void) { return 0; } +#endif +// CHECK-P10: define internal {{.*}}i32 @foo_mma.mma() +// CHECK-P10: define internal {{.*}}i32 @foo_mma.default() +// CHECK-P10: define internal ptr @foo_mma.resolver() +// if (__builtin_cpu_supports("mma")) return &foo_mma.mma; +// CHECK-P10: %[[#MMA:]] = call i64 @getsystemcfg(i32 62) +// CHECK-P10-NEXT: icmp ugt i64 %[[#MMA]], 0 +// CHECK-P10: ret ptr @foo_mma.mma +// CHECK-P10: ret ptr @foo_mma.default // Test multiple features with priority ordering (random source order) // Source order: altivec, power8-vector, cpu=pwr11, vsx, power9-vector, default >From 6b6ceb7d53b0d284ab776136162f54d6ab80ea66 Mon Sep 17 00:00:00 2001 From: Wael Yehia <[email protected]> Date: Sat, 4 Jul 2026 16:53:28 +0000 Subject: [PATCH 04/15] comments --- clang/lib/Basic/Targets/PPC.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp index 077b35003e17c..b50041d5efd8f 100644 --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -901,14 +901,14 @@ bool PPCTargetInfo::isValidFeatureName(StringRef Name) const { } bool PPCTargetInfo::isValidClonesFeatureName(StringRef Name) const { - // Only 14 features with runtime detection are valid for target_clones + // Only features with runtime detection are valid for target_clones return llvm::StringSwitch<bool>(Name) // Direct mappings (4 features) .Case("altivec", true) .Case("htm", true) .Case("mma", true) .Case("vsx", true) - // ISA level mappings (10 features) + // ISA level mappings .Case("crypto", true) .Case("direct-move", true) .Case("float128", true) @@ -931,7 +931,7 @@ PPCTargetInfo::getBuiltinCpuSupportsName(StringRef FeatureName) const { .Case("htm", "htm") .Case("mma", "mma") .Case("vsx", "vsx") - // ISA level mappings (10 features) + // ISA LEVEL MAPPINGS .Case("popcntd", "arch_2_06") .Case("crypto", "arch_2_07") .Case("direct-move", "arch_2_07") >From 3c5d33ebf522847f9ca2e2e1b69e2b2ecd665871 Mon Sep 17 00:00:00 2001 From: Wael Yehia <[email protected]> Date: Sun, 5 Jul 2026 20:53:36 -0400 Subject: [PATCH 05/15] clean up: - remove PPCTargetInfo::isValidFeatureName (to be reimplemented in a separate PR) - handle build warnings - rewire isValidClonesFeatureName to use a new macro PPC_AIX_CLONES_FEATURE - remove getBuiltinCpuSupportsName as it's only used during clang codegen in a PPC path, so inline it's implementation into the usage point. --- clang/include/clang/Basic/TargetInfo.h | 6 -- clang/lib/Basic/Targets/PPC.cpp | 79 +------------------ clang/lib/Basic/Targets/PPC.h | 12 +-- clang/lib/CodeGen/CodeGenFunction.cpp | 8 +- clang/lib/Sema/SemaPPC.cpp | 11 --- .../llvm/TargetParser/PPCTargetParser.def | 19 +++++ 6 files changed, 32 insertions(+), 103 deletions(-) diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 9baacffc81493..52b200deaee70 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1475,12 +1475,6 @@ class TargetInfo : public TransferrableTargetInfo, return isValidFeatureName(Feature); } - /// Get __builtin_cpu_supports() argument for a feature - /// Returns empty string if feature has no runtime detection - virtual StringRef getBuiltinCpuSupportsName(StringRef Feature) const { - return ""; - } - /// Returns true if feature has an impact on target code /// generation. virtual bool doesFeatureAffectCodeGen(StringRef Feature) const { diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp index b50041d5efd8f..80de3bf2ba95b 100644 --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -866,85 +866,14 @@ void PPCTargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const { llvm::PPC::fillValidCPUList(Values); } -bool PPCTargetInfo::isValidFeatureName(StringRef Name) const { - if (!getTriple().isOSAIX()) - return TargetInfo::isValidFeatureName(Name); - return llvm::StringSwitch<bool>(Name) - .Case("altivec", true) - .Case("htm", true) - .Case("mma", true) - .Case("vsx", true) - .Case("crypto", true) - .Case("direct-move", true) - .Case("float128", true) - .Case("paired-vector-memops", true) - .Case("popcntd", true) - .Case("power8-vector", true) - .Case("power9-vector", true) - .Case("power10-vector", true) - .Case("prefixed", true) - .Case("aix-shared-lib-tls-model-opt", true) - .Case("aix-small-local-dynamic-tls", true) - .Case("aix-small-local-exec-tls", true) - .Case("cmpb", true) - .Case("crbits", true) - .Case("fprnd", true) - .Case("invariant-function-descriptors", true) - .Case("isel", true) - .Case("longcall", true) - .Case("mfcrf", true) - .Case("mfocrf", true) - .Case("privileged", true) - .Case("rop-protect", true) - .Case("secure-plt", true) - .Default(false); -} - -bool PPCTargetInfo::isValidClonesFeatureName(StringRef Name) const { +bool PPCTargetInfo::isValidClonesFeatureName(StringRef FeatureStr) const { // Only features with runtime detection are valid for target_clones - return llvm::StringSwitch<bool>(Name) - // Direct mappings (4 features) - .Case("altivec", true) - .Case("htm", true) - .Case("mma", true) - .Case("vsx", true) - // ISA level mappings - .Case("crypto", true) - .Case("direct-move", true) - .Case("float128", true) - .Case("paired-vector-memops", true) - .Case("popcntd", true) - .Case("power8-vector", true) - .Case("power9-vector", true) - .Case("power10-vector", true) - .Case("prefixed", true) + return llvm::StringSwitch<bool>(FeatureStr) +#define PPC_AIX_CLONES_FEATURE(FEATURE_NAME, _) .Case(FEATURE_NAME, true) +#include "llvm/TargetParser/PPCTargetParser.def" .Default(false); } -StringRef -PPCTargetInfo::getBuiltinCpuSupportsName(StringRef FeatureName) const { - // Map feature names to __builtin_cpu_supports() strings - // Only returns non-empty for features with runtime detection - return llvm::StringSwitch<StringRef>(FeatureName) - // Direct mappings (4 features) - .Case("altivec", "altivec") - .Case("htm", "htm") - .Case("mma", "mma") - .Case("vsx", "vsx") - // ISA LEVEL MAPPINGS - .Case("popcntd", "arch_2_06") - .Case("crypto", "arch_2_07") - .Case("direct-move", "arch_2_07") - .Case("power8-vector", "arch_2_07") - .Case("float128", "arch_3_00") - .Case("power9-vector", "arch_3_00") - .Case("paired-vector-memops", "arch_3_1") - .Case("power10-vector", "arch_3_1") - .Case("prefixed", "arch_3_1") - // Features without runtime checks return empty string - .Default(""); -} - void PPCTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts, const TargetInfo *Aux) { if (HasAltivec) diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h index e46daaa85a993..e1e26d578d57d 100644 --- a/clang/lib/Basic/Targets/PPC.h +++ b/clang/lib/Basic/Targets/PPC.h @@ -98,16 +98,8 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo { bool isValidCPUName(StringRef Name) const override; void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; - // Validate feature name for target attribute (all 28 features) - bool isValidFeatureName(StringRef Name) const override; - - // Validate feature name for target_clones (only 17 features with runtime - // detection) - bool isValidClonesFeatureName(StringRef Name) const; - - // Get __builtin_cpu_supports() argument for a feature (returns empty string - // if no runtime check) - StringRef getBuiltinCpuSupportsName(StringRef FeatureName) const; + // Validate if given feature name is supported on target_clones + bool isValidClonesFeatureName(StringRef Name) const override; bool setCPU(StringRef &Name) override { bool CPUKnown = isValidCPUName(Name); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 0a90a6041816d..cc9dedca8edb3 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -3175,8 +3175,14 @@ void CodeGenFunction::EmitPPCAIXMultiVersionResolver( BaseFeature = BaseFeature.drop_front(3); } + // Map feature names to __builtin_cpu_supports() strings BuiltinCpuSupportsArg = - getTarget().getBuiltinCpuSupportsName(BaseFeature); + llvm::StringSwitch<StringRef>(BaseFeature) +#define PPC_AIX_CLONES_FEATURE(FEATURE_NAME, AIX_BUILTIN_CPU_SUPPORTS_NAME) \ + .Case(FEATURE_NAME, AIX_BUILTIN_CPU_SUPPORTS_NAME) +#include "llvm/TargetParser/PPCTargetParser.def" + // Features without runtime checks return empty string + .Default(""); // All features in target_clones must have runtime detection assert(!BuiltinCpuSupportsArg.empty() && diff --git a/clang/lib/Sema/SemaPPC.cpp b/clang/lib/Sema/SemaPPC.cpp index be76bac5de6c8..1446a277b6947 100644 --- a/clang/lib/Sema/SemaPPC.cpp +++ b/clang/lib/Sema/SemaPPC.cpp @@ -657,25 +657,14 @@ bool SemaPPC::checkTargetClonesAttr(const SmallVectorImpl<StringRef> &Params, } else { // Handle feature strings StringRef FeatureName = LHS; - bool IsNegated = false; // Check for negation prefix if (FeatureName.starts_with("no-")) { - IsNegated = true; FeatureName = FeatureName.drop_front(3); } - // First check if it's a valid feature name at all - if (!TargetInfo.isValidFeatureName(FeatureName)) { - return Diag(CurLoc, diag::warn_unsupported_target_attribute) - << Unknown << None << LHS << TargetClones; - } - // Check if feature is valid for target_clones (has runtime detection) - // Use virtual method that defaults to isValidFeatureName for non-PPC - // targets if (!TargetInfo.isValidClonesFeatureName(FeatureName)) { - // Feature is valid for target attribute but not target_clones return Diag(CurLoc, diag::err_ppc_feature_no_runtime_detection) << FeatureName; } diff --git a/llvm/include/llvm/TargetParser/PPCTargetParser.def b/llvm/include/llvm/TargetParser/PPCTargetParser.def index da4be3e39f2c7..968323fecd6fc 100644 --- a/llvm/include/llvm/TargetParser/PPCTargetParser.def +++ b/llvm/include/llvm/TargetParser/PPCTargetParser.def @@ -276,6 +276,25 @@ PPC_AIX_FEATURE("ucache","CPU has unified I/D cache",USE_SYS_CONF,AIX_SYSCON_CAC PPC_AIX_FEATURE("vsx","CPU supports the vector-scalar extension",USE_SYS_CONF,AIX_SYSCON_VMX_IDX,0,ICmpInst::ICMP_UGT,1) #undef PPC_AIX_FEATURE +#ifndef PPC_AIX_CLONES_FEATURE +#define PPC_AIX_CLONES_FEATURE(TARGET_FEATURE_NAME, AIX_BUILTIN_CPU_SUPPORTS_NAME) +#endif + +PPC_AIX_CLONES_FEATURE("altivec", "altivec") +PPC_AIX_CLONES_FEATURE("htm", "htm") +PPC_AIX_CLONES_FEATURE("vsx", "vsx") +PPC_AIX_CLONES_FEATURE("mma", "mma") +PPC_AIX_CLONES_FEATURE("popcntd", "arch_2_06") +PPC_AIX_CLONES_FEATURE("crypto", "arch_2_07") +PPC_AIX_CLONES_FEATURE("direct-move", "arch_2_07") +PPC_AIX_CLONES_FEATURE("power8-vector", "arch_2_07") +PPC_AIX_CLONES_FEATURE("float128", "arch_3_00") +PPC_AIX_CLONES_FEATURE("power9-vector", "arch_3_00") +PPC_AIX_CLONES_FEATURE("paired-vector-memops","arch_3_1") +PPC_AIX_CLONES_FEATURE("power10-vector", "arch_3_1") +PPC_AIX_CLONES_FEATURE("prefixed", "arch_3_1") +#undef PPC_AIX_CLONES_FEATURE + // PPC_SYSTEMCONFIG_TYPE defines the IR data structure of kernel variable // `_system_configuration`, that is found in the AIX OS header file: </usr/include/sys/systemcfg.h>. #ifndef PPC_SYSTEMCONFIG_TYPE >From bd6f4b948bdf775c35c9f316c201c49f5fbfe56c Mon Sep 17 00:00:00 2001 From: Wael Yehia <[email protected]> Date: Mon, 6 Jul 2026 16:11:56 +0000 Subject: [PATCH 06/15] more cleanup --- clang/include/clang/Basic/TargetInfo.h | 3 +-- clang/lib/CodeGen/Targets/PPC.cpp | 24 ++++++------------------ 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 52b200deaee70..e93d7ee98e419 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1469,8 +1469,7 @@ class TargetInfo : public TransferrableTargetInfo, return true; } - /// Validate feature name for target_clones attribute (subset with runtime - /// detection) Default implementation delegates to isValidFeatureName + /// Does this TargetInfo support the given feature on target_clones? virtual bool isValidClonesFeatureName(StringRef Feature) const { return isValidFeatureName(Feature); } diff --git a/clang/lib/CodeGen/Targets/PPC.cpp b/clang/lib/CodeGen/Targets/PPC.cpp index 449ca39b9faba..72d7d7be4b56c 100644 --- a/clang/lib/CodeGen/Targets/PPC.cpp +++ b/clang/lib/CodeGen/Targets/PPC.cpp @@ -162,25 +162,13 @@ void AIXABIInfo::appendAttributeMangling(StringRef AttrStr, if (!Info.Features.empty()) { assert(Info.Features.size() == 1 && "one feature per version for now"); StringRef Feature = Info.Features[0]; - std::string MangledFeature; - - // Handle negation prefix "no-" specially - convert to "no_" - if (Feature.starts_with("no-")) { - MangledFeature = "no_"; - Feature = Feature.drop_front(3); - } else if (Feature.starts_with("+")) { - // Remove leading '+' for positive features - Feature = Feature.drop_front(1); - } else if (Feature.starts_with("-")) { - // Leading '-' means negation, convert to "no_" - MangledFeature = "no_"; - Feature = Feature.drop_front(1); - } + assert(Feature.starts_with("+") || Feature.starts_with("-")); + + // replace hyphens with underscores + std::string MangledName(Feature.drop_front(1)); + std::replace(MangledName.begin(), MangledName.end(), '-', '_'); - // Append the base feature name and replace hyphens with underscores - MangledFeature += Feature.str(); - std::replace(MangledFeature.begin(), MangledFeature.end(), '-', '_'); - Out << "." << MangledFeature; + Out << "." << (Feature.starts_with("-") ? "no_" : "") << MangledName; return; } >From 9e5e301c5ed42b10a9463074926c082b4ccdb0c3 Mon Sep 17 00:00:00 2001 From: Wael Yehia <[email protected]> Date: Mon, 6 Jul 2026 13:45:03 -0400 Subject: [PATCH 07/15] integrate FMV priority into PPC_AIX_CLONES_FEATURE --- clang/lib/Basic/Targets/PPC.cpp | 24 ++------ clang/lib/CodeGen/CodeGenFunction.cpp | 4 +- .../llvm/TargetParser/PPCTargetParser.def | 56 ++++++++++++++----- 3 files changed, 49 insertions(+), 35 deletions(-) diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp index 80de3bf2ba95b..71e0c828b5fe0 100644 --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -751,26 +751,10 @@ llvm::APInt PPCTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const { Feature = Feature.drop_front(1); int Priority = llvm::StringSwitch<int>(Feature) - // POWER10 features (between pwr10=400 and pwr11=500) - .Case("mma", 419) - .Case("paired-vector-memops", 418) - .Case("power10-vector", 416) - .Case("prefixed", 415) - // POWER9 features (between pwr9=300 and pwr10=400) - .Case("float128", 312) - .Case("power9-vector", 311) - // POWER8 features (between pwr8=200 and pwr9=300) - .Case("crypto", 214) - .Case("direct-move", 213) - .Case("power8-vector", 212) - .Case("htm", 211) - // POWER7 features (between pwr7=100 and pwr8=200) - .Case("popcntd", 112) - .Case("vsx", 111) - // Base features: 50-99 (below pwr7=100) - .Case("altivec", 50) +#define PPC_AIX_CLONES_FEATURE(FEATURE_NAME, _, PRIORITY) \ + .Case(FEATURE_NAME, PRIORITY) +#include "llvm/TargetParser/PPCTargetParser.def" .Default(0); - return llvm::APInt(32, Priority); } @@ -869,7 +853,7 @@ void PPCTargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const { bool PPCTargetInfo::isValidClonesFeatureName(StringRef FeatureStr) const { // Only features with runtime detection are valid for target_clones return llvm::StringSwitch<bool>(FeatureStr) -#define PPC_AIX_CLONES_FEATURE(FEATURE_NAME, _) .Case(FEATURE_NAME, true) +#define PPC_AIX_CLONES_FEATURE(FEATURE_NAME, _, __) .Case(FEATURE_NAME, true) #include "llvm/TargetParser/PPCTargetParser.def" .Default(false); } diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index cc9dedca8edb3..d9b67c9dde0da 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -3178,7 +3178,7 @@ void CodeGenFunction::EmitPPCAIXMultiVersionResolver( // Map feature names to __builtin_cpu_supports() strings BuiltinCpuSupportsArg = llvm::StringSwitch<StringRef>(BaseFeature) -#define PPC_AIX_CLONES_FEATURE(FEATURE_NAME, AIX_BUILTIN_CPU_SUPPORTS_NAME) \ +#define PPC_AIX_CLONES_FEATURE(FEATURE_NAME, AIX_BUILTIN_CPU_SUPPORTS_NAME, _) \ .Case(FEATURE_NAME, AIX_BUILTIN_CPU_SUPPORTS_NAME) #include "llvm/TargetParser/PPCTargetParser.def" // Features without runtime checks return empty string @@ -3190,6 +3190,8 @@ void CodeGenFunction::EmitPPCAIXMultiVersionResolver( "Sema"); } + assert(getContext().getTargetInfo().validateCpuSupports(BuiltinCpuSupportsArg)); + llvm::Value *Condition = EmitPPCBuiltinCpu(Builtin::BI__builtin_cpu_supports, Builder.getInt1Ty(), BuiltinCpuSupportsArg); diff --git a/llvm/include/llvm/TargetParser/PPCTargetParser.def b/llvm/include/llvm/TargetParser/PPCTargetParser.def index 968323fecd6fc..29cc300089d1c 100644 --- a/llvm/include/llvm/TargetParser/PPCTargetParser.def +++ b/llvm/include/llvm/TargetParser/PPCTargetParser.def @@ -277,22 +277,50 @@ PPC_AIX_FEATURE("vsx","CPU supports the vector-scalar extension",USE_SYS_CONF,AI #undef PPC_AIX_FEATURE #ifndef PPC_AIX_CLONES_FEATURE -#define PPC_AIX_CLONES_FEATURE(TARGET_FEATURE_NAME, AIX_BUILTIN_CPU_SUPPORTS_NAME) +#define PPC_AIX_CLONES_FEATURE(TARGET_FEATURE_NAME, AIX_BUILTIN_CPU_SUPPORTS_NAME, PRIORITY) #endif -PPC_AIX_CLONES_FEATURE("altivec", "altivec") -PPC_AIX_CLONES_FEATURE("htm", "htm") -PPC_AIX_CLONES_FEATURE("vsx", "vsx") -PPC_AIX_CLONES_FEATURE("mma", "mma") -PPC_AIX_CLONES_FEATURE("popcntd", "arch_2_06") -PPC_AIX_CLONES_FEATURE("crypto", "arch_2_07") -PPC_AIX_CLONES_FEATURE("direct-move", "arch_2_07") -PPC_AIX_CLONES_FEATURE("power8-vector", "arch_2_07") -PPC_AIX_CLONES_FEATURE("float128", "arch_3_00") -PPC_AIX_CLONES_FEATURE("power9-vector", "arch_3_00") -PPC_AIX_CLONES_FEATURE("paired-vector-memops","arch_3_1") -PPC_AIX_CLONES_FEATURE("power10-vector", "arch_3_1") -PPC_AIX_CLONES_FEATURE("prefixed", "arch_3_1") +// Description of parameters: +// - TARGET_FEATURE_NAME: a target-feature name that is supported (in its +// positive or negative (i.e. no-FEATURE) form) on a target and a target_clones +// attribute on AIX. +// - AIX_BUILTIN_CPU_SUPPORTS_NAME: the corresponding __builtin_cpu_supports +// testable feature. +// - PRIORITY: an integer value that determines the order of which features are +// tested first when selecting between clones in the resolver. Higher priority +// items will be tested first. The function PPCTargetInfo::getFMVPriority uses +// this table to return the priority value for a given target feature or CPU. +// The CPU priorities are (from PPCTargetInfo::getFMVPriority): +// pwr7: 100 +// pwr8: 200 +// pwr9: 300 +// pwr10: 400 +// pwr11: 500 +// Some features (e.g. "prefixed") don't have an explicit bit to check at runtime, +// instead the minimum ISA is checked. +// Features in CPU X are given higher priority than features in CPU "X-1". +// Eg. resolver for a target_clones("cpu=pwr8", "float128", "default") will test +// for "float128" via __builtin_cpu_supports("arch_3_00") before testing for +// __builtin_cpu_supports("arch_2_07") (aka cpu=pwr8). +// +// POWER10 features (between pwr10=400 and pwr11=500) +PPC_AIX_CLONES_FEATURE("mma", "mma", 415) +PPC_AIX_CLONES_FEATURE("paired-vector-memops","arch_3_1", 416) +PPC_AIX_CLONES_FEATURE("power10-vector", "arch_3_1", 417) +PPC_AIX_CLONES_FEATURE("prefixed", "arch_3_1", 418) +// POWER9 features +PPC_AIX_CLONES_FEATURE("float128", "arch_3_00", 311) +PPC_AIX_CLONES_FEATURE("power9-vector", "arch_3_00", 312) +// POWER8 features +PPC_AIX_CLONES_FEATURE("crypto", "arch_2_07", 211) +PPC_AIX_CLONES_FEATURE("direct-move", "arch_2_07", 212) +PPC_AIX_CLONES_FEATURE("power8-vector", "arch_2_07", 213) +PPC_AIX_CLONES_FEATURE("htm", "htm", 214) +// POWER7 features +PPC_AIX_CLONES_FEATURE("vsx", "vsx", 111) +PPC_AIX_CLONES_FEATURE("popcntd", "arch_2_06", 112) +// Base features: 50-99 (below pwr7=100) +PPC_AIX_CLONES_FEATURE("altivec", "altivec", 50) #undef PPC_AIX_CLONES_FEATURE // PPC_SYSTEMCONFIG_TYPE defines the IR data structure of kernel variable >From ab8cfd81378da20aefbdec5234a61e683cc7d655 Mon Sep 17 00:00:00 2001 From: Wael Yehia <[email protected]> Date: Mon, 6 Jul 2026 18:28:04 +0000 Subject: [PATCH 08/15] clang-format --- clang/lib/Basic/Targets/PPC.cpp | 4 ++-- clang/lib/CodeGen/CodeGenFunction.cpp | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp index 71e0c828b5fe0..a356bb199a445 100644 --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -751,8 +751,8 @@ llvm::APInt PPCTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const { Feature = Feature.drop_front(1); int Priority = llvm::StringSwitch<int>(Feature) -#define PPC_AIX_CLONES_FEATURE(FEATURE_NAME, _, PRIORITY) \ - .Case(FEATURE_NAME, PRIORITY) +#define PPC_AIX_CLONES_FEATURE(FEATURE_NAME, _, PRIORITY) \ + .Case(FEATURE_NAME, PRIORITY) #include "llvm/TargetParser/PPCTargetParser.def" .Default(0); return llvm::APInt(32, Priority); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index d9b67c9dde0da..dff5734aec2d8 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -3178,7 +3178,7 @@ void CodeGenFunction::EmitPPCAIXMultiVersionResolver( // Map feature names to __builtin_cpu_supports() strings BuiltinCpuSupportsArg = llvm::StringSwitch<StringRef>(BaseFeature) -#define PPC_AIX_CLONES_FEATURE(FEATURE_NAME, AIX_BUILTIN_CPU_SUPPORTS_NAME, _) \ +#define PPC_AIX_CLONES_FEATURE(FEATURE_NAME, AIX_BUILTIN_CPU_SUPPORTS_NAME, _) \ .Case(FEATURE_NAME, AIX_BUILTIN_CPU_SUPPORTS_NAME) #include "llvm/TargetParser/PPCTargetParser.def" // Features without runtime checks return empty string @@ -3190,7 +3190,8 @@ void CodeGenFunction::EmitPPCAIXMultiVersionResolver( "Sema"); } - assert(getContext().getTargetInfo().validateCpuSupports(BuiltinCpuSupportsArg)); + assert(getContext().getTargetInfo().validateCpuSupports( + BuiltinCpuSupportsArg)); llvm::Value *Condition = EmitPPCBuiltinCpu(Builtin::BI__builtin_cpu_supports, >From 213831852b2a76ab37f9a876e8e1d722705a6250 Mon Sep 17 00:00:00 2001 From: Wael Yehia <[email protected]> Date: Mon, 6 Jul 2026 18:58:00 +0000 Subject: [PATCH 09/15] cleanup --- clang/lib/CodeGen/CodeGenFunction.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index dff5734aec2d8..1d83eec0cb018 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -3164,20 +3164,17 @@ void CodeGenFunction::EmitPPCAIXMultiVersionResolver( .Case("pwr11", "arch_3_1") .Default("error"); } else { - // Feature string - check for "no-" negation prefix - StringRef BaseFeature = FeatureStr; - // Feature strings arrive here already normalized: // - Positive features: just the name (e.g., "altivec") // - Negated features: "no-" prefix (e.g., "no-altivec") - if (BaseFeature.starts_with("no-")) { + if (FeatureStr.starts_with("no-")) { IsNegated = true; - BaseFeature = BaseFeature.drop_front(3); + FeatureStr = FeatureStr.drop_front(3); } // Map feature names to __builtin_cpu_supports() strings BuiltinCpuSupportsArg = - llvm::StringSwitch<StringRef>(BaseFeature) + llvm::StringSwitch<StringRef>(FeatureStr) #define PPC_AIX_CLONES_FEATURE(FEATURE_NAME, AIX_BUILTIN_CPU_SUPPORTS_NAME, _) \ .Case(FEATURE_NAME, AIX_BUILTIN_CPU_SUPPORTS_NAME) #include "llvm/TargetParser/PPCTargetParser.def" >From 85a20172e35f61fd808e2606c4bf277787c917b2 Mon Sep 17 00:00:00 2001 From: Wael Yehia <[email protected]> Date: Mon, 6 Jul 2026 21:14:23 -0400 Subject: [PATCH 10/15] simplify checkTargetClonesAttr logic --- clang/lib/Sema/SemaPPC.cpp | 41 ++++---------------- clang/test/Sema/PowerPC/attr-target-clones.c | 10 ++--- 2 files changed, 13 insertions(+), 38 deletions(-) diff --git a/clang/lib/Sema/SemaPPC.cpp b/clang/lib/Sema/SemaPPC.cpp index 1446a277b6947..27c57a5ff8d40 100644 --- a/clang/lib/Sema/SemaPPC.cpp +++ b/clang/lib/Sema/SemaPPC.cpp @@ -618,31 +618,24 @@ bool SemaPPC::checkTargetClonesAttr(const SmallVectorImpl<StringRef> &Params, const StringRef Param = Params[I].trim(); const SourceLocation &Loc = Locs[I]; + if (Param.empty() || Param.ends_with(',')) + return Diag(Loc, diag::warn_unsupported_target_attribute) + << Unsupported << None << "" << TargetClones; + if (Param.contains(',')) HasComma = true; StringRef LHS; StringRef RHS = Param; - // TODO: simplify the logic to diagnose empty strings - bool checkTrailingEmpty = false; do { std::tie(LHS, RHS) = RHS.split(','); LHS = LHS.trim(); - - // After processing last non-empty item, check if we need to process - // trailing empty - if (RHS.empty() && !LHS.empty() && Param.ends_with(',')) { - checkTrailingEmpty = true; - } - const SourceLocation &CurLoc = Loc.getLocWithOffset(LHS.data() - Param.data()); - // Check for empty string (from trailing comma, leading comma, or ",,") - if (LHS.empty()) { + if (LHS.empty()) return Diag(CurLoc, diag::warn_unsupported_target_attribute) - << Unknown << None << "" << TargetClones; - } + << Unsupported << None << "" << TargetClones; if (LHS.starts_with("cpu=")) { StringRef CPUStr = LHS.drop_front(sizeof("cpu=") - 1); @@ -655,19 +648,10 @@ bool SemaPPC::checkTargetClonesAttr(const SmallVectorImpl<StringRef> &Params, } else if (LHS == "default") { HasDefault = true; } else { - // Handle feature strings - StringRef FeatureName = LHS; - - // Check for negation prefix - if (FeatureName.starts_with("no-")) { - FeatureName = FeatureName.drop_front(3); - } - - // Check if feature is valid for target_clones (has runtime detection) - if (!TargetInfo.isValidClonesFeatureName(FeatureName)) { + StringRef FeatureName = LHS.starts_with("no-") ? LHS.drop_front(3) : LHS; + if (!TargetInfo.isValidClonesFeatureName(FeatureName)) return Diag(CurLoc, diag::err_ppc_feature_no_runtime_detection) << FeatureName; - } } SmallString<64> CPU; if (LHS.starts_with("cpu=")) { @@ -681,15 +665,6 @@ bool SemaPPC::checkTargetClonesAttr(const SmallVectorImpl<StringRef> &Params, continue; } NewParams.push_back(LHS); - - // If we just processed the last item and there's a trailing comma, - // do one more iteration to catch the empty string - if (checkTrailingEmpty) { - LHS = ""; - const SourceLocation &EmptyCurLoc = Loc.getLocWithOffset(Param.size()); - return Diag(EmptyCurLoc, diag::warn_unsupported_target_attribute) - << Unknown << None << "" << TargetClones; - } } while (!RHS.empty()); } if (HasComma && Params.size() > 1) diff --git a/clang/test/Sema/PowerPC/attr-target-clones.c b/clang/test/Sema/PowerPC/attr-target-clones.c index 0f078fa2e805c..7bde2e47ccda7 100644 --- a/clang/test/Sema/PowerPC/attr-target-clones.c +++ b/clang/test/Sema/PowerPC/attr-target-clones.c @@ -42,20 +42,20 @@ int __attribute__((target_clones("cpu=pwr9,default"))) redef3(void) { return 1; int __attribute__((target_clones("cpu=pwr9,cpu=power9", "cpu=power9, default"))) dupes(void) { return 1; } -// expected-warning@+1 {{unknown '' in the 'target_clones' attribute string;}} +// expected-warning@+1 {{unsupported '' in the 'target_clones' attribute string;}} void __attribute__((target_clones(""))) empty_target_1(void); -// expected-warning@+1 {{unknown '' in the 'target_clones' attribute string;}} +// expected-warning@+1 {{unsupported '' in the 'target_clones' attribute string;}} void __attribute__((target_clones(",default"))) empty_target_2(void); -// expected-warning@+1 {{unknown '' in the 'target_clones' attribute string;}} +// expected-warning@+1 {{unsupported '' in the 'target_clones' attribute string;}} void __attribute__((target_clones("default,"))) empty_target_3(void); -// expected-warning@+1 {{unknown '' in the 'target_clones' attribute string;}} +// expected-warning@+1 {{unsupported '' in the 'target_clones' attribute string;}} void __attribute__((target_clones("default, ,cpu=pwr7"))) empty_target_4(void); -// expected-warning@+1 {{unknown '' in the 'target_clones' attribute string;}} +// expected-warning@+1 {{unsupported '' in the 'target_clones' attribute string;}} void __attribute__((target_clones("default,cpu=pwr7", ""))) empty_target_5(void); >From cb20b04d615af1a8abdb91b0eb21e941b9e0a493 Mon Sep 17 00:00:00 2001 From: Wael Yehia <[email protected]> Date: Wed, 15 Jul 2026 02:12:22 +0000 Subject: [PATCH 11/15] code review --- clang/lib/AST/ASTContext.cpp | 7 ++----- clang/lib/Basic/Targets/PPC.cpp | 11 ++++------- clang/lib/CodeGen/CodeGenFunction.cpp | 10 ++++------ llvm/include/llvm/TargetParser/PPCTargetParser.def | 11 +++++++++++ 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 17e2605f13f35..3b39889b96b3b 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -15422,11 +15422,8 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap, StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex()); if (VersionStr.starts_with("cpu=")) TargetCPU = VersionStr.drop_front(sizeof("cpu=") - 1); - else if (VersionStr != "default") { - // Handle feature strings - ParsedTargetAttr ParsedAttr = Target->parseTargetAttr(VersionStr); - Features = ParsedAttr.Features; - } + else if (VersionStr != "default") + Features = Target->parseTargetAttr(VersionStr).Features; Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features); } else { std::vector<std::string> Features; diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp index a356bb199a445..cb8e4b5d1de70 100644 --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -734,11 +734,9 @@ llvm::APInt PPCTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const { if (!ParsedAttr.CPU.empty()) { int Priority = llvm::StringSwitch<int>(ParsedAttr.CPU) - .Case("pwr7", 100) - .Case("pwr8", 200) - .Case("pwr9", 300) - .Case("pwr10", 400) - .Case("pwr11", 500) +#define PPC_AIX_CLONES_CPU(CPU_NAME, _, PRIORITY) \ + .Case(CPU_NAME, PRIORITY) +#include "llvm/TargetParser/PPCTargetParser.def" .Default(0); return llvm::APInt(32, Priority); } @@ -757,8 +755,7 @@ llvm::APInt PPCTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const { .Default(0); return llvm::APInt(32, Priority); } - - return llvm::APInt(32, 0); + llvm_unreachable("Invalid target_clones parameter"); } // Make sure that registers are added in the correct array index which should be diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 1d83eec0cb018..74d974896c5ce 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -3157,11 +3157,9 @@ void CodeGenFunction::EmitPPCAIXMultiVersionResolver( // CPU specification - map to ISA level StringRef CPU = FeatureStr.split("=").second.trim(); BuiltinCpuSupportsArg = llvm::StringSwitch<StringRef>(CPU) - .Case("pwr7", "arch_2_06") - .Case("pwr8", "arch_2_07") - .Case("pwr9", "arch_3_00") - .Case("pwr10", "arch_3_1") - .Case("pwr11", "arch_3_1") +#define PPC_AIX_CLONES_CPU(CPU_NAME, AIX_BUILTIN_CPU_SUPPORTS_NAME, _) \ + .Case(CPU_NAME, AIX_BUILTIN_CPU_SUPPORTS_NAME) +#include "llvm/TargetParser/PPCTargetParser.def" .Default("error"); } else { // Feature strings arrive here already normalized: @@ -3183,7 +3181,7 @@ void CodeGenFunction::EmitPPCAIXMultiVersionResolver( // All features in target_clones must have runtime detection assert(!BuiltinCpuSupportsArg.empty() && - "feature without runtime detection should have been rejected in " + "Feature without runtime detection should have been rejected in " "Sema"); } diff --git a/llvm/include/llvm/TargetParser/PPCTargetParser.def b/llvm/include/llvm/TargetParser/PPCTargetParser.def index 29cc300089d1c..10a7e302e3481 100644 --- a/llvm/include/llvm/TargetParser/PPCTargetParser.def +++ b/llvm/include/llvm/TargetParser/PPCTargetParser.def @@ -323,6 +323,17 @@ PPC_AIX_CLONES_FEATURE("popcntd", "arch_2_06", 112) PPC_AIX_CLONES_FEATURE("altivec", "altivec", 50) #undef PPC_AIX_CLONES_FEATURE +#ifndef PPC_AIX_CLONES_CPU +#define PPC_AIX_CLONES_CPU(CPU_NAME, AIX_BUILTIN_CPU_SUPPORTS_NAME, PRIORITY) +#endif +PPC_AIX_CLONES_CPU("pwr7", "arch_2_06", 100) +PPC_AIX_CLONES_CPU("pwr8", "arch_2_07", 200) +PPC_AIX_CLONES_CPU("pwr9", "arch_3_00", 300) +PPC_AIX_CLONES_CPU("pwr10", "arch_3_1", 400) +// Power11 implements the same ISA as Power10 +PPC_AIX_CLONES_CPU("pwr11", "arch_3_1", 500) +#undef PPC_AIX_CLONES_CPU + // PPC_SYSTEMCONFIG_TYPE defines the IR data structure of kernel variable // `_system_configuration`, that is found in the AIX OS header file: </usr/include/sys/systemcfg.h>. #ifndef PPC_SYSTEMCONFIG_TYPE >From 6b572f25f25a18106a50fa5d9b56225ae6fa5bc9 Mon Sep 17 00:00:00 2001 From: Wael Yehia <[email protected]> Date: Wed, 15 Jul 2026 04:03:54 +0000 Subject: [PATCH 12/15] add isValidFeatureName assertion to valid target_clones features --- clang/lib/Sema/SemaPPC.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/lib/Sema/SemaPPC.cpp b/clang/lib/Sema/SemaPPC.cpp index 27c57a5ff8d40..88ba8c235188c 100644 --- a/clang/lib/Sema/SemaPPC.cpp +++ b/clang/lib/Sema/SemaPPC.cpp @@ -652,6 +652,8 @@ bool SemaPPC::checkTargetClonesAttr(const SmallVectorImpl<StringRef> &Params, if (!TargetInfo.isValidClonesFeatureName(FeatureName)) return Diag(CurLoc, diag::err_ppc_feature_no_runtime_detection) << FeatureName; + // All target_clones feature names must be valid target feature names. + assert(isValidFeatureName(FeatureName)); } SmallString<64> CPU; if (LHS.starts_with("cpu=")) { >From 149cc4a8eb12bb524b02e3d902f2030a0b6e6e35 Mon Sep 17 00:00:00 2001 From: Wael Yehia <[email protected]> Date: Thu, 10 Sep 2026 22:12:02 +0000 Subject: [PATCH 13/15] fix build break fixes --- clang/lib/Basic/Targets/PPC.h | 2 +- clang/lib/Sema/SemaPPC.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h index e1e26d578d57d..f78f36d8bab9f 100644 --- a/clang/lib/Basic/Targets/PPC.h +++ b/clang/lib/Basic/Targets/PPC.h @@ -101,7 +101,7 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo { // Validate if given feature name is supported on target_clones bool isValidClonesFeatureName(StringRef Name) const override; - bool setCPU(StringRef &Name) override { + bool setCPU(StringRef Name) override { bool CPUKnown = isValidCPUName(Name); if (CPUKnown) { CPU = Name; diff --git a/clang/lib/Sema/SemaPPC.cpp b/clang/lib/Sema/SemaPPC.cpp index 88ba8c235188c..0c8f9ec06e369 100644 --- a/clang/lib/Sema/SemaPPC.cpp +++ b/clang/lib/Sema/SemaPPC.cpp @@ -653,7 +653,7 @@ bool SemaPPC::checkTargetClonesAttr(const SmallVectorImpl<StringRef> &Params, return Diag(CurLoc, diag::err_ppc_feature_no_runtime_detection) << FeatureName; // All target_clones feature names must be valid target feature names. - assert(isValidFeatureName(FeatureName)); + assert(TargetInfo.isValidFeatureName(FeatureName)); } SmallString<64> CPU; if (LHS.starts_with("cpu=")) { >From 4df784cb1b13288da3fc9e6f256b45a9a230e4d8 Mon Sep 17 00:00:00 2001 From: Wael Yehia <[email protected]> Date: Thu, 10 Sep 2026 22:25:47 +0000 Subject: [PATCH 14/15] categorize features into ones that can be disabled at runtime and ones that cannot --- .../clang/Basic/DiagnosticSemaKinds.td | 3 ++ clang/lib/Basic/Targets/PPC.cpp | 31 ++++++++++++++++--- clang/lib/Sema/SemaPPC.cpp | 19 +++++++++++- clang/test/Sema/PowerPC/attr-target-clones.c | 7 +++++ .../llvm/TargetParser/PPCTargetParser.def | 14 ++++++--- .../llvm/TargetParser/PPCTargetParser.h | 4 +++ llvm/lib/TargetParser/PPCTargetParser.cpp | 5 +++ 7 files changed, 73 insertions(+), 10 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 6a9389ba3994d..eedd8c13deda1 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11587,6 +11587,9 @@ def err_ppc_invalid_arg_type : Error< def err_ppc_feature_no_runtime_detection : Error< "feature '%0' cannot be used with 'target_clones' because it has no " "runtime detection; use 'target' attribute instead">; +def err_ppc_multiple_negative_category2 : Error< + "only one negative form of runtime-disableable features (vsx, htm) is allowed in 'target_clones'; " + "'%0' conflicts with '%1'">; def err_x86_builtin_invalid_rounding : Error< "invalid rounding argument">; diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp index cb8e4b5d1de70..9c7ea76137bea 100644 --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -728,10 +728,24 @@ llvm::APInt PPCTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const { assert(Features.size() == 1 && "one feature/cpu per clone on PowerPC"); ParsedTargetAttr ParsedAttr = parseTargetAttr(Features[0]); - // Priority scheme: Features requiring POWERXX are higher than cpu=pwrXX - // but lower than cpu=pwr(XX+1). This ensures proper version selection. - // Example: mma (POWER10 feature) > cpu=pwr10 > power9-vector (POWER9 feature) - + // Priority scheme: + // CPU specifications: 100-500 (pwr7=100, pwr8=200, ..., pwr11=500) + // For target-features, they can be divided into 3 categories: + // 1) non-CPU properties (e.g. invariant-function-descriptors); those cannot + // be tested at runtime, and are currently excluded from target_clones. + // 2) CPU properties that cannot be disabled (e.g. mma); these features map to + // CPUs directly: + // +feature => __builtin_cpu_supports("<minimum-cpu>") + // => true for CPU <minimum-cpu> and above. + // -feature => !__builtin_cpu_supports("<minimum-cpu>") + // => true for CPU <minimum-cpu-minus-one> and below. + // 3) CPU properties that can be disabled (e.g. vsx); those can map to CPUs + // directly for the positive requirement (same as (2)); + // for the negative requirement checking the CPU is incorrect: + // target_clones(no-vsx, cpu=pwr8) + // should pick no-vsx when vsx is disabled at runtime, so we need to test + // negative form of category 3 first, and will only allow one negative form + // from this category on a target_clones. if (!ParsedAttr.CPU.empty()) { int Priority = llvm::StringSwitch<int>(ParsedAttr.CPU) #define PPC_AIX_CLONES_CPU(CPU_NAME, _, PRIORITY) \ @@ -741,13 +755,20 @@ llvm::APInt PPCTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const { return llvm::APInt(32, Priority); } - // Feature strings: priority between cpu=pwrN and cpu=pwr(N+1) + // Feature strings if (!ParsedAttr.Features.empty()) { StringRef Feature = ParsedAttr.Features[0]; + bool IsNegated = Feature.starts_with("-"); // Remove leading '+' or '-' if (Feature.starts_with("+") || Feature.starts_with("-")) Feature = Feature.drop_front(1); + // Check if this is a negative category 3 feature (highest priority) + // Sema guarantees there's only one such version on a target_clones. + if (IsNegated && llvm::PPC::canDisableFeatureOnAIX(Feature)) + Feature = "NEGATIVE-FEATURE"; + + // Regular feature priority (positive or negative category 2) int Priority = llvm::StringSwitch<int>(Feature) #define PPC_AIX_CLONES_FEATURE(FEATURE_NAME, _, PRIORITY) \ .Case(FEATURE_NAME, PRIORITY) diff --git a/clang/lib/Sema/SemaPPC.cpp b/clang/lib/Sema/SemaPPC.cpp index 0c8f9ec06e369..ff640ea67c9fc 100644 --- a/clang/lib/Sema/SemaPPC.cpp +++ b/clang/lib/Sema/SemaPPC.cpp @@ -614,6 +614,8 @@ bool SemaPPC::checkTargetClonesAttr(const SmallVectorImpl<StringRef> &Params, auto &TargetInfo = getASTContext().getTargetInfo(); bool HasDefault = false; bool HasComma = false; + bool HasNegativeCategory2 = false; + StringRef NegativeCategory2Feature; for (unsigned I = 0, E = Params.size(); I < E; ++I) { const StringRef Param = Params[I].trim(); const SourceLocation &Loc = Locs[I]; @@ -648,12 +650,27 @@ bool SemaPPC::checkTargetClonesAttr(const SmallVectorImpl<StringRef> &Params, } else if (LHS == "default") { HasDefault = true; } else { - StringRef FeatureName = LHS.starts_with("no-") ? LHS.drop_front(3) : LHS; + bool IsNegated = LHS.starts_with("no-"); + StringRef FeatureName = IsNegated ? LHS.drop_front(3) : LHS; if (!TargetInfo.isValidClonesFeatureName(FeatureName)) return Diag(CurLoc, diag::err_ppc_feature_no_runtime_detection) << FeatureName; // All target_clones feature names must be valid target feature names. assert(TargetInfo.isValidFeatureName(FeatureName)); + + if (llvm::PPC::canDisableFeatureOnAIX(FeatureName)) { + if (IsNegated) { + // Only one negative target-feature that can be disabled. + if (HasNegativeCategory2) { + return Diag(CurLoc, diag::err_ppc_multiple_negative_category2) + << LHS << NegativeCategory2Feature; + } + HasNegativeCategory2 = true; + NegativeCategory2Feature = LHS; + } + // Positive category 2 features are always allowed + } + // Category 1 features (positive or negative) are always allowed } SmallString<64> CPU; if (LHS.starts_with("cpu=")) { diff --git a/clang/test/Sema/PowerPC/attr-target-clones.c b/clang/test/Sema/PowerPC/attr-target-clones.c index 7bde2e47ccda7..f676167016226 100644 --- a/clang/test/Sema/PowerPC/attr-target-clones.c +++ b/clang/test/Sema/PowerPC/attr-target-clones.c @@ -213,6 +213,13 @@ valid_mixed_features_1(void); void __attribute__((target_clones("vsx", "no-crypto", "default"))) valid_mixed_features_2(void); +// expected-error@+1 {{only one negative form of runtime-disableable features (vsx, htm) is allowed in 'target_clones'; 'no-vsx' conflicts with 'no-htm'}} +void __attribute__((target_clones("no-htm", "no-vsx", "default"))) +mixed_features_3(void); + +void __attribute__((target_clones("htm", "no-vsx", "default"))) +valid_mixed_features_4(void); + // Test features with CPU specifications void __attribute__((target_clones("altivec", "cpu=pwr8", "default"))) valid_feature_with_cpu_1(void); diff --git a/llvm/include/llvm/TargetParser/PPCTargetParser.def b/llvm/include/llvm/TargetParser/PPCTargetParser.def index 10a7e302e3481..61185211f0725 100644 --- a/llvm/include/llvm/TargetParser/PPCTargetParser.def +++ b/llvm/include/llvm/TargetParser/PPCTargetParser.def @@ -321,17 +321,23 @@ PPC_AIX_CLONES_FEATURE("vsx", "vsx", 111) PPC_AIX_CLONES_FEATURE("popcntd", "arch_2_06", 112) // Base features: 50-99 (below pwr7=100) PPC_AIX_CLONES_FEATURE("altivec", "altivec", 50) + +// A special non-feature entry, that holds the priority for the negative form +// (e.g. no-vsx) for features that can be disabled at runtime. This should have +// the highest priority among all features and cpus. +// See llvm::PPC::canDisableFeatureOnAIX() query. +PPC_AIX_CLONES_FEATURE("NEGATIVE-FEATURE", "", 1000) #undef PPC_AIX_CLONES_FEATURE #ifndef PPC_AIX_CLONES_CPU #define PPC_AIX_CLONES_CPU(CPU_NAME, AIX_BUILTIN_CPU_SUPPORTS_NAME, PRIORITY) #endif -PPC_AIX_CLONES_CPU("pwr7", "arch_2_06", 100) -PPC_AIX_CLONES_CPU("pwr8", "arch_2_07", 200) -PPC_AIX_CLONES_CPU("pwr9", "arch_3_00", 300) -PPC_AIX_CLONES_CPU("pwr10", "arch_3_1", 400) // Power11 implements the same ISA as Power10 PPC_AIX_CLONES_CPU("pwr11", "arch_3_1", 500) +PPC_AIX_CLONES_CPU("pwr10", "arch_3_1", 400) +PPC_AIX_CLONES_CPU("pwr9", "arch_3_00", 300) +PPC_AIX_CLONES_CPU("pwr8", "arch_2_07", 200) +PPC_AIX_CLONES_CPU("pwr7", "arch_2_06", 100) #undef PPC_AIX_CLONES_CPU // PPC_SYSTEMCONFIG_TYPE defines the IR data structure of kernel variable diff --git a/llvm/include/llvm/TargetParser/PPCTargetParser.h b/llvm/include/llvm/TargetParser/PPCTargetParser.h index 9f39551377f70..8b4d5e35b26f8 100644 --- a/llvm/include/llvm/TargetParser/PPCTargetParser.h +++ b/llvm/include/llvm/TargetParser/PPCTargetParser.h @@ -44,6 +44,10 @@ LLVM_ABI std::optional<llvm::StringMap<bool>> getPPCDefaultTargetFeatures(const Triple &T, StringRef CPUName); LLVM_ABI bool isValidFeatureName(StringRef Name); + +// Return true for target features that can be disabled at runtime. +// For example, VSX can be disabled via the allow_vmx tunable using the schedo command. +LLVM_ABI bool canDisableFeatureOnAIX(StringRef Name); } // namespace PPC } // namespace llvm diff --git a/llvm/lib/TargetParser/PPCTargetParser.cpp b/llvm/lib/TargetParser/PPCTargetParser.cpp index 76c2c13ac53a4..fc7f815d09718 100644 --- a/llvm/lib/TargetParser/PPCTargetParser.cpp +++ b/llvm/lib/TargetParser/PPCTargetParser.cpp @@ -152,5 +152,10 @@ bool isValidFeatureName(StringRef Name) { const BasicSubtargetFeatureKV *F = llvm::lower_bound(A, Name); return F != A.end() && StringRef(F->Key) == Name; } + +bool canDisableFeatureOnAIX(StringRef Name) { + return Name == "vsx" || Name == "htm"; +} + } // namespace PPC } // namespace llvm >From 26056e272a395b3419265453a3bacb122aef74ac Mon Sep 17 00:00:00 2001 From: Wael Yehia <[email protected]> Date: Fri, 11 Sep 2026 04:06:00 +0000 Subject: [PATCH 15/15] clang-foramt --- clang/lib/Basic/Targets/PPC.cpp | 3 +-- clang/lib/CodeGen/CodeGenFunction.cpp | 2 +- clang/lib/Sema/SemaPPC.cpp | 2 +- llvm/include/llvm/TargetParser/PPCTargetParser.h | 3 ++- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp index 9c7ea76137bea..4f4754ecdcb29 100644 --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -748,8 +748,7 @@ llvm::APInt PPCTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const { // from this category on a target_clones. if (!ParsedAttr.CPU.empty()) { int Priority = llvm::StringSwitch<int>(ParsedAttr.CPU) -#define PPC_AIX_CLONES_CPU(CPU_NAME, _, PRIORITY) \ - .Case(CPU_NAME, PRIORITY) +#define PPC_AIX_CLONES_CPU(CPU_NAME, _, PRIORITY) .Case(CPU_NAME, PRIORITY) #include "llvm/TargetParser/PPCTargetParser.def" .Default(0); return llvm::APInt(32, Priority); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 74d974896c5ce..37b664227a064 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -3157,7 +3157,7 @@ void CodeGenFunction::EmitPPCAIXMultiVersionResolver( // CPU specification - map to ISA level StringRef CPU = FeatureStr.split("=").second.trim(); BuiltinCpuSupportsArg = llvm::StringSwitch<StringRef>(CPU) -#define PPC_AIX_CLONES_CPU(CPU_NAME, AIX_BUILTIN_CPU_SUPPORTS_NAME, _) \ +#define PPC_AIX_CLONES_CPU(CPU_NAME, AIX_BUILTIN_CPU_SUPPORTS_NAME, _) \ .Case(CPU_NAME, AIX_BUILTIN_CPU_SUPPORTS_NAME) #include "llvm/TargetParser/PPCTargetParser.def" .Default("error"); diff --git a/clang/lib/Sema/SemaPPC.cpp b/clang/lib/Sema/SemaPPC.cpp index ff640ea67c9fc..f4d89e3ffd1a8 100644 --- a/clang/lib/Sema/SemaPPC.cpp +++ b/clang/lib/Sema/SemaPPC.cpp @@ -657,7 +657,7 @@ bool SemaPPC::checkTargetClonesAttr(const SmallVectorImpl<StringRef> &Params, << FeatureName; // All target_clones feature names must be valid target feature names. assert(TargetInfo.isValidFeatureName(FeatureName)); - + if (llvm::PPC::canDisableFeatureOnAIX(FeatureName)) { if (IsNegated) { // Only one negative target-feature that can be disabled. diff --git a/llvm/include/llvm/TargetParser/PPCTargetParser.h b/llvm/include/llvm/TargetParser/PPCTargetParser.h index 8b4d5e35b26f8..10565697f537a 100644 --- a/llvm/include/llvm/TargetParser/PPCTargetParser.h +++ b/llvm/include/llvm/TargetParser/PPCTargetParser.h @@ -46,7 +46,8 @@ getPPCDefaultTargetFeatures(const Triple &T, StringRef CPUName); LLVM_ABI bool isValidFeatureName(StringRef Name); // Return true for target features that can be disabled at runtime. -// For example, VSX can be disabled via the allow_vmx tunable using the schedo command. +// For example, VSX can be disabled via the allow_vmx tunable using the schedo +// command. LLVM_ABI bool canDisableFeatureOnAIX(StringRef Name); } // namespace PPC } // namespace llvm _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
