[clang] 27da153 - [X86] __builtin_cpu_supports: support x86-64{, -v2, -v3, -v4}

Fangrui Song via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 25 20:56:30 PDT 2023


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) {


        


More information about the cfe-commits mailing list