Skip to content

Commit

Permalink
[X86] __builtin_cpu_supports: support x86-64{,-v2,-v3,-v4}
Browse files Browse the repository at this point in the history
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 9de3b35

Close #59961

Reviewed By: pengfei

Differential Revision: https://reviews.llvm.org/D158811
  • Loading branch information
MaskRay committed Aug 26, 2023
1 parent 9de3b35 commit 27da153
Show file tree
Hide file tree
Showing 9 changed files with 61 additions and 29 deletions.
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
4 changes: 1 addition & 3 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 *
Expand Down
22 changes: 5 additions & 17 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
20 changes: 20 additions & 0 deletions clang/test/CodeGen/builtin-cpu-supports.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"); }
6 changes: 6 additions & 0 deletions clang/test/Sema/builtin-cpu-supports.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
10 changes: 10 additions & 0 deletions llvm/include/llvm/TargetParser/X86TargetParser.def
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
8 changes: 6 additions & 2 deletions llvm/include/llvm/TargetParser/X86TargetParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringMap.h"
#include <array>

namespace llvm {
template <typename T> class SmallVectorImpl;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
14 changes: 9 additions & 5 deletions llvm/lib/TargetParser/X86TargetParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit 27da153

Please sign in to comment.