Author: Fangrui Song Date: 2023-08-25T20:56:25-07:00 New Revision: 27da15381cbe2ac6fd1319f6409dbbab9a857b7b
URL: https://github.com/llvm/llvm-project/commit/27da15381cbe2ac6fd1319f6409dbbab9a857b7b DIFF: https://github.com/llvm/llvm-project/commit/27da15381cbe2ac6fd1319f6409dbbab9a857b7b.diff LOG: [X86] __builtin_cpu_supports: support x86-64{,-v2,-v3,-v4} GCC 12 (https://gcc.gnu.org/PR101696) allows __builtin_cpu_supports("x86-64") (and -v2 -v3 -v4). This patch ports the feature. * Add `FEATURE_X86_64_{BASELINE,V2,V3,V4}` to enum ProcessorFeatures, but keep CPU_FEATURE_MAX unchanged to make FeatureInfos/FeatureInfos_WithPLUS happy. * Change validateCpuSupports to allow `x86-64{,-v2,-v3,-v4}` * Change getCpuSupportsMask to return `std::array<uint32_t, 4>` where `x86-64{,-v2,-v3,-v4}` set bits `FEATURE_X86_64_{BASELINE,V2,V3,V4}`. * `target("x86-64")` and `cpu_dispatch(x86_64)` are invalid. Tested by commit 9de3b35ac9159d5bae6e6796cb91e4f877a07189 Close https://github.com/llvm/llvm-project/issues/59961 Reviewed By: pengfei Differential Revision: https://reviews.llvm.org/D158811 Added: Modified: clang/lib/Basic/Targets/X86.cpp clang/lib/CodeGen/CGBuiltin.cpp clang/lib/CodeGen/CodeGenFunction.cpp clang/lib/CodeGen/CodeGenModule.cpp clang/test/CodeGen/builtin-cpu-supports.c clang/test/Sema/builtin-cpu-supports.c llvm/include/llvm/TargetParser/X86TargetParser.def llvm/include/llvm/TargetParser/X86TargetParser.h llvm/lib/TargetParser/X86TargetParser.cpp Removed: ################################################################################ diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index e18b459c0f51eb..9c464a3afdf767 100644 --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -1170,6 +1170,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const { bool X86TargetInfo::validateCpuSupports(StringRef FeatureStr) const { return llvm::StringSwitch<bool>(FeatureStr) #define X86_FEATURE_COMPAT(ENUM, STR, PRIORITY) .Case(STR, true) +#define X86_MICROARCH_LEVEL(ENUM, STR, PRIORITY) .Case(STR, true) #include "llvm/TargetParser/X86TargetParser.def" .Default(false); } diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 25e1b36d05fd97..daa4b095eaa8ae 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -13325,9 +13325,7 @@ Value *CodeGenFunction::EmitX86CpuSupports(const CallExpr *E) { } Value *CodeGenFunction::EmitX86CpuSupports(ArrayRef<StringRef> FeatureStrs) { - uint64_t Mask = llvm::X86::getCpuSupportsMask(FeatureStrs); - std::array<uint32_t, 4> FeatureMask{Lo_32(Mask), Hi_32(Mask), 0, 0}; - return EmitX86CpuSupports(FeatureMask); + return EmitX86CpuSupports(llvm::X86::getCpuSupportsMask(FeatureStrs)); } llvm::Value * diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 7b456edf5a3623..bf83171e2c6814 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2683,24 +2683,12 @@ llvm::Value *CodeGenFunction::FormX86ResolverCondition( if (!RO.Conditions.Architecture.empty()) { StringRef Arch = RO.Conditions.Architecture; - std::array<uint32_t, 4> Mask{}; - // If arch= specifies an x86-64 micro-architecture level, test a special - // feature named FEATURE_X86_64_*, otherwise we use __builtin_cpu_is. - if (Arch.consume_front("x86-64")) { - if (Arch.empty()) // FEATURE_X86_64_BASELINE 95=2*32+31 - Mask[2] = 1u << 31; - else if (Arch == "-v2") // FEATURE_X86_64_V2 96==3*32+0 - Mask[3] = 1u << 0; - else if (Arch == "-v3") // FEATURE_X86_64_V3 97==3*32+1 - Mask[3] = 1u << 1; - else if (Arch == "-v4") // FEATURE_X86_64_V3 98==3*32+2 - Mask[3] = 1u << 2; - else - llvm_unreachable("invalid x86-64 micro-architecture level"); - Condition = EmitX86CpuSupports(Mask); - } else { + // If arch= specifies an x86-64 micro-architecture level, test the feature + // with __builtin_cpu_supports, otherwise use __builtin_cpu_is. + if (Arch.starts_with("x86-64")) + Condition = EmitX86CpuSupports({Arch}); + else Condition = EmitX86CpuIs(Arch); - } } if (!RO.Conditions.Features.empty()) { diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index b1e5c9fc96faa5..9b241165b7c579 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -4168,8 +4168,9 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) { // always run on at least a 'pentium'). We do this by deleting the 'least // advanced' (read, lowest mangling letter). while (Options.size() > 1 && - llvm::X86::getCpuSupportsMask( - (Options.end() - 2)->Conditions.Features) == 0) { + llvm::all_of(llvm::X86::getCpuSupportsMask( + (Options.end() - 2)->Conditions.Features), + [](auto X) { return X == 0; })) { StringRef LHSName = (Options.end() - 2)->Function->getName(); StringRef RHSName = (Options.end() - 1)->Function->getName(); if (LHSName.compare(RHSName) < 0) diff --git a/clang/test/CodeGen/builtin-cpu-supports.c b/clang/test/CodeGen/builtin-cpu-supports.c index 59a82f89b03797..796611c1fcd9af 100644 --- a/clang/test/CodeGen/builtin-cpu-supports.c +++ b/clang/test/CodeGen/builtin-cpu-supports.c @@ -30,3 +30,23 @@ int main(void) { } // CHECK: declare dso_local void @__cpu_indicator_init() + +// CHECK-LABEL: define{{.*}} @baseline( +// CHECK: [[LOAD:%.*]] = load i32, ptr getelementptr inbounds ([[[#]] x i32], ptr @__cpu_features2, i32 0, i32 1) +// CHECK-NEXT: and i32 [[LOAD]], -2147483648 +int baseline() { return __builtin_cpu_supports("x86-64"); } + +// CHECK-LABEL: define{{.*}} @v2( +// CHECK: [[LOAD:%.*]] = load i32, ptr getelementptr inbounds ([[[#]] x i32], ptr @__cpu_features2, i32 0, i32 2) +// CHECK-NEXT: and i32 [[LOAD]], 1 +int v2() { return __builtin_cpu_supports("x86-64-v2"); } + +// CHECK-LABEL: define{{.*}} @v3( +// CHECK: [[LOAD:%.*]] = load i32, ptr getelementptr inbounds ([[[#]] x i32], ptr @__cpu_features2, i32 0, i32 2) +// CHECK-NEXT: and i32 [[LOAD]], 2 +int v3() { return __builtin_cpu_supports("x86-64-v3"); } + +// CHECK-LABEL: define{{.*}} @v4( +// CHECK: [[LOAD:%.*]] = load i32, ptr getelementptr inbounds ([[[#]] x i32], ptr @__cpu_features2, i32 0, i32 2) +// CHECK-NEXT: and i32 [[LOAD]], 4 +int v4() { return __builtin_cpu_supports("x86-64-v4"); } diff --git a/clang/test/Sema/builtin-cpu-supports.c b/clang/test/Sema/builtin-cpu-supports.c index ece695a1a65135..ad310128fecebf 100644 --- a/clang/test/Sema/builtin-cpu-supports.c +++ b/clang/test/Sema/builtin-cpu-supports.c @@ -20,6 +20,12 @@ int main(void) { (void)__builtin_cpu_is("x86-64-v2"); // expected-error {{invalid cpu name for builtin}} (void)__builtin_cpu_is("x86-64-v3"); // expected-error {{invalid cpu name for builtin}} (void)__builtin_cpu_is("x86-64-v4"); // expected-error {{invalid cpu name for builtin}} + + (void)__builtin_cpu_supports("x86-64"); + (void)__builtin_cpu_supports("x86-64-v2"); + (void)__builtin_cpu_supports("x86-64-v3"); + (void)__builtin_cpu_supports("x86-64-v4"); + (void)__builtin_cpu_supports("x86-64-v5"); // expected-error {{invalid cpu feature string for builtin}} #else if (__builtin_cpu_supports("vsx")) // expected-error {{use of unknown builtin}} a("vsx"); diff --git a/llvm/include/llvm/TargetParser/X86TargetParser.def b/llvm/include/llvm/TargetParser/X86TargetParser.def index 5e5bc51342b3f2..817db0f69bc863 100644 --- a/llvm/include/llvm/TargetParser/X86TargetParser.def +++ b/llvm/include/llvm/TargetParser/X86TargetParser.def @@ -128,6 +128,10 @@ X86_CPU_SUBTYPE_ALIAS(INTEL_COREI7_ALDERLAKE, "gracemont") #define X86_FEATURE(ENUM, STR) #endif +#ifndef X86_MICROARCH_LEVEL +#define X86_MICROARCH_LEVEL(ENUM, STR, PRIORITY) +#endif + X86_FEATURE_COMPAT(CMOV, "cmov", 0) X86_FEATURE_COMPAT(MMX, "mmx", 1) X86_FEATURE_COMPAT(POPCNT, "popcnt", 9) @@ -242,5 +246,11 @@ X86_FEATURE (RETPOLINE_INDIRECT_BRANCHES, "retpoline-indirect-branches") X86_FEATURE (RETPOLINE_INDIRECT_CALLS, "retpoline-indirect-calls") X86_FEATURE (LVI_CFI, "lvi-cfi") X86_FEATURE (LVI_LOAD_HARDENING, "lvi-load-hardening") + +X86_MICROARCH_LEVEL(X86_64_BASELINE,"x86-64", 95) +X86_MICROARCH_LEVEL(X86_64_V2, "x86-64-v2", 96) +X86_MICROARCH_LEVEL(X86_64_V3, "x86-64-v3", 97) +X86_MICROARCH_LEVEL(X86_64_V4, "x86-64-v4", 98) #undef X86_FEATURE_COMPAT #undef X86_FEATURE +#undef X86_MICROARCH_LEVEL diff --git a/llvm/include/llvm/TargetParser/X86TargetParser.h b/llvm/include/llvm/TargetParser/X86TargetParser.h index 57d7b5d16a2329..a3ba7262db5774 100644 --- a/llvm/include/llvm/TargetParser/X86TargetParser.h +++ b/llvm/include/llvm/TargetParser/X86TargetParser.h @@ -15,6 +15,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringMap.h" +#include <array> namespace llvm { template <typename T> class SmallVectorImpl; @@ -57,7 +58,10 @@ enum ProcessorSubtypes : unsigned { enum ProcessorFeatures { #define X86_FEATURE(ENUM, STRING) FEATURE_##ENUM, #include "llvm/TargetParser/X86TargetParser.def" - CPU_FEATURE_MAX + CPU_FEATURE_MAX, + +#define X86_MICROARCH_LEVEL(ENUM, STRING, PRIORITY) FEATURE_##ENUM = PRIORITY, +#include "llvm/TargetParser/X86TargetParser.def" }; enum CPUKind { @@ -171,7 +175,7 @@ void updateImpliedFeatures(StringRef Feature, bool Enabled, char getCPUDispatchMangling(StringRef Name); bool validateCPUSpecificCPUDispatch(StringRef Name); -uint64_t getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs); +std::array<uint32_t, 4> getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs); unsigned getFeaturePriority(ProcessorFeatures Feat); } // namespace X86 diff --git a/llvm/lib/TargetParser/X86TargetParser.cpp b/llvm/lib/TargetParser/X86TargetParser.cpp index b934f02404ec05..b8a19cfd26fa28 100644 --- a/llvm/lib/TargetParser/X86TargetParser.cpp +++ b/llvm/lib/TargetParser/X86TargetParser.cpp @@ -703,18 +703,22 @@ bool llvm::X86::validateCPUSpecificCPUDispatch(StringRef Name) { return I != std::end(Processors); } -uint64_t llvm::X86::getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs) { +std::array<uint32_t, 4> +llvm::X86::getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs) { // Processor features and mapping to processor feature value. - uint64_t FeaturesMask = 0; - for (const StringRef &FeatureStr : FeatureStrs) { + std::array<uint32_t, 4> FeatureMask{}; + for (StringRef FeatureStr : FeatureStrs) { unsigned Feature = StringSwitch<unsigned>(FeatureStr) #define X86_FEATURE_COMPAT(ENUM, STR, PRIORITY) \ .Case(STR, llvm::X86::FEATURE_##ENUM) +#define X86_MICROARCH_LEVEL(ENUM, STR, PRIORITY) \ + .Case(STR, llvm::X86::FEATURE_##ENUM) #include "llvm/TargetParser/X86TargetParser.def" ; - FeaturesMask |= (1ULL << Feature); + assert(Feature / 32 < FeatureMask.size()); + FeatureMask[Feature / 32] |= 1U << (Feature % 32); } - return FeaturesMask; + return FeatureMask; } unsigned llvm::X86::getFeaturePriority(ProcessorFeatures Feat) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits