[clang] [PowerPC][X86] Make cpu id builtins target independent and lower for PPC (PR #68919)

via cfe-commits cfe-commits at lists.llvm.org
Thu Oct 12 11:21:57 PDT 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Nemanja Ivanovic (nemanjai)

<details>
<summary>Changes</summary>

Make __builtin_cpu_{init|supports|is} target independent and provide an opt-in query for targets that want to support it. Each target is still responsible for their specific lowering/code-gen. Also provide code-gen for PowerPC.

I originally proposed this in https://reviews.llvm.org/D152914 and this addresses the comments I received there.

---

Patch is 34.63 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/68919.diff


17 Files Affected:

- (modified) clang/include/clang/Basic/Builtins.def (+5) 
- (modified) clang/include/clang/Basic/BuiltinsX86.def (-7) 
- (modified) clang/include/clang/Basic/TargetInfo.h (+6) 
- (modified) clang/lib/Basic/Targets/PPC.cpp (+14) 
- (modified) clang/lib/Basic/Targets/PPC.h (+7) 
- (modified) clang/lib/Basic/Targets/X86.h (+4) 
- (modified) clang/lib/CodeGen/CGBuiltin.cpp (+39-3) 
- (modified) clang/lib/Sema/SemaChecking.cpp (+77-47) 
- (modified) clang/test/CodeGen/builtin-cpu-supports.c (+46-22) 
- (modified) clang/test/Sema/builtin-cpu-supports.c (+5-3) 
- (modified) llvm/include/llvm/IR/IntrinsicsPowerPC.td (+6) 
- (added) llvm/include/llvm/TargetParser/PPCTargetParser.def (+80) 
- (modified) llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp (+4) 
- (modified) llvm/lib/Target/PowerPC/PPCInstrInfo.cpp (+33) 
- (modified) llvm/lib/Target/PowerPC/PPCInstrInfo.td (+3) 
- (modified) llvm/lib/Target/PowerPC/PPCTargetMachine.h (+3) 
- (added) llvm/test/CodeGen/PowerPC/cpu-supports.ll (+111) 


``````````diff
diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def
index 6ea8484606cfd5d..5e1f4088ff63f8a 100644
--- a/clang/include/clang/Basic/Builtins.def
+++ b/clang/include/clang/Basic/Builtins.def
@@ -118,6 +118,11 @@
 #  define LANGBUILTIN(ID, TYPE, ATTRS, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS)
 #endif
 
+// Builtins for checking CPU features based on the GCC builtins.
+BUILTIN(__builtin_cpu_supports, "bcC*", "nc")
+BUILTIN(__builtin_cpu_is, "bcC*", "nc")
+BUILTIN(__builtin_cpu_init, "v", "n")
+
 // Standard libc/libm functions:
 BUILTIN(__builtin_atan2 , "ddd"  , "Fne")
 BUILTIN(__builtin_atan2f, "fff"  , "Fne")
diff --git a/clang/include/clang/Basic/BuiltinsX86.def b/clang/include/clang/Basic/BuiltinsX86.def
index e4802f8ab1c1562..2acc5ce0f4a3653 100644
--- a/clang/include/clang/Basic/BuiltinsX86.def
+++ b/clang/include/clang/Basic/BuiltinsX86.def
@@ -26,13 +26,6 @@
 #  define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANG, FEATURE) BUILTIN(ID, TYPE, ATTRS)
 #endif
 
-// Miscellaneous builtin for checking x86 cpu features.
-// TODO: Make this somewhat generic so that other backends
-// can use it?
-BUILTIN(__builtin_cpu_init, "v", "n")
-BUILTIN(__builtin_cpu_supports, "bcC*", "nc")
-BUILTIN(__builtin_cpu_is, "bcC*", "nc")
-
 // Undefined Values
 //
 TARGET_BUILTIN(__builtin_ia32_undef128, "V2d", "ncV:128:", "")
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 9d56e97a3d4bb88..3d83b387aac0931 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -1415,6 +1415,12 @@ class TargetInfo : public TransferrableTargetInfo,
             getTriple().isOSFreeBSD());
   }
 
+  // Identify whether this target supports __builtin_cpu_supports and
+  // __builtin_cpu_is.
+  virtual bool supportsCpuSupports() const { return false; }
+  virtual bool supportsCpuIs() const { return false; }
+  virtual bool supportsCpuInit() const { return false; }
+
   // Validate the contents of the __builtin_cpu_supports(const char*)
   // argument.
   virtual bool validateCpuSupports(StringRef Name) const { return false; }
diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp
index 0d87a3a4e8c20f3..d8759c86c9932ca 100644
--- a/clang/lib/Basic/Targets/PPC.cpp
+++ b/clang/lib/Basic/Targets/PPC.cpp
@@ -873,3 +873,17 @@ ArrayRef<Builtin::Info> PPCTargetInfo::getTargetBuiltins() const {
   return llvm::ArrayRef(BuiltinInfo,
                         clang::PPC::LastTSBuiltin - Builtin::FirstTSBuiltin);
 }
+
+bool PPCTargetInfo::validateCpuSupports(StringRef FeatureStr) const {
+#define PPC_FEATURE(NAME, DESC, ENUMNAME, ENUMVAL, HWCAPN) .Case(NAME, true)
+  return llvm::StringSwitch<bool>(FeatureStr)
+#include "llvm/TargetParser/PPCTargetParser.def"
+      .Default(false);
+}
+
+bool PPCTargetInfo::validateCpuIs(StringRef CPUName) const {
+#define PPC_CPU(NAME, NUM) .Case(NAME, true)
+  return llvm::StringSwitch<bool>(CPUName)
+#include "llvm/TargetParser/PPCTargetParser.def"
+      .Default(false);
+}
diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h
index 4d62673ba7fb8c5..f700b625b790309 100644
--- a/clang/lib/Basic/Targets/PPC.h
+++ b/clang/lib/Basic/Targets/PPC.h
@@ -359,6 +359,13 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
   bool isSPRegName(StringRef RegName) const override {
     return RegName.equals("r1") || RegName.equals("x1");
   }
+
+  // We support __builtin_cpu_supports/__builtin_cpu_is on targets that
+  // have GLIBC since it is GLIBC that provides the HWCAP[2] in the auxv.
+  bool supportsCpuSupports() const override { return getTriple().isOSGlibc(); }
+  bool supportsCpuIs() const override { return getTriple().isOSGlibc(); }
+  bool validateCpuSupports(StringRef Feature) const override;
+  bool validateCpuIs(StringRef Name) const override;
 };
 
 class LLVM_LIBRARY_VISIBILITY PPC32TargetInfo : public PPCTargetInfo {
diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h
index 4fdc94de1e0cb4d..3b379715163a8a8 100644
--- a/clang/lib/Basic/Targets/X86.h
+++ b/clang/lib/Basic/Targets/X86.h
@@ -211,6 +211,10 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
     return RegName.equals("esp") || RegName.equals("rsp");
   }
 
+  bool supportsCpuSupports() const override { return true; }
+  bool supportsCpuIs() const override { return true; }
+  bool supportsCpuInit() const override { return true; }
+
   bool validateCpuSupports(StringRef FeatureStr) const override;
 
   bool validateCpuIs(StringRef FeatureStr) const override;
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 8cb7943df9a7822..583b2be69ba1664 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -13585,11 +13585,11 @@ CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) {
 
 Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
                                            const CallExpr *E) {
-  if (BuiltinID == X86::BI__builtin_cpu_is)
+  if (BuiltinID == Builtin::BI__builtin_cpu_is)
     return EmitX86CpuIs(E);
-  if (BuiltinID == X86::BI__builtin_cpu_supports)
+  if (BuiltinID == Builtin::BI__builtin_cpu_supports)
     return EmitX86CpuSupports(E);
-  if (BuiltinID == X86::BI__builtin_cpu_init)
+  if (BuiltinID == Builtin::BI__builtin_cpu_init)
     return EmitX86CpuInit();
 
   // Handle MSVC intrinsics before argument evaluation to prevent double
@@ -16086,6 +16086,42 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
   switch (BuiltinID) {
   default: return nullptr;
 
+  case Builtin::BI__builtin_cpu_is: {
+    const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts();
+    StringRef CPUStr = cast<clang::StringLiteral>(CPUExpr)->getString();
+    unsigned NumCPUID = StringSwitch<unsigned>(CPUStr)
+#define PPC_CPU(Name, NumericID) .Case(Name, NumericID)
+#include "llvm/TargetParser/PPCTargetParser.def"
+                            .Default(-1U);
+    Value *Op0 =
+        llvm::ConstantInt::get(Int32Ty, PPC_FAWORD_CPUID);
+    llvm::Function *F = CGM.getIntrinsic(Intrinsic::ppc_fixed_addr_ld);
+    Value *TheCall = Builder.CreateCall(F, {Op0}, "cpu_is");
+    return Builder.CreateICmpEQ(TheCall,
+                                llvm::ConstantInt::get(Int32Ty, NumCPUID));
+  }
+  case Builtin::BI__builtin_cpu_supports: {
+    unsigned FeatureWord;
+    unsigned BitMask;
+    const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts();
+    StringRef CPUStr = cast<clang::StringLiteral>(CPUExpr)->getString();
+    std::tie(FeatureWord, BitMask) =
+        StringSwitch<std::pair<unsigned, unsigned>>(CPUStr)
+#define PPC_FEATURE(Name, Description, EnumName, Bitmask, FA_WORD)             \
+  .Case(Name, {FA_WORD, Bitmask})
+#include "llvm/TargetParser/PPCTargetParser.def"
+            .Default({0, 0});
+    Value *Op0 = llvm::ConstantInt::get(Int32Ty, FeatureWord);
+    llvm::Function *F = CGM.getIntrinsic(Intrinsic::ppc_fixed_addr_ld);
+    Value *TheCall = Builder.CreateCall(F, {Op0}, "cpu_supports");
+    Value *Mask =
+        Builder.CreateAnd(TheCall, llvm::ConstantInt::get(Int32Ty, BitMask));
+    return Builder.CreateICmpNE(Mask, llvm::Constant::getNullValue(Int32Ty));
+#undef PPC_FAWORD_HWCAP
+#undef PPC_FAWORD_HWCAP2
+#undef PPC_FAWORD_CPUID
+  }
+
   // __builtin_ppc_get_timebase is GCC 4.8+'s PowerPC-specific name for what we
   // call __builtin_readcyclecounter.
   case PPC::BI__builtin_ppc_get_timebase:
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 2594a8f97f7d94e..6e67f4edc9da32e 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2110,6 +2110,66 @@ static bool checkFPMathBuiltinElementType(Sema &S, SourceLocation Loc,
   return false;
 }
 
+/// SemaBuiltinCpuSupports - Handle __builtin_cpu_supports(char *).
+/// This checks that the target supports __builtin_cpu_supports and
+/// that the string argument is constant and valid.
+static bool SemaBuiltinCpuSupports(Sema &S, const TargetInfo &TI,
+                                   const TargetInfo *AuxTI, CallExpr *TheCall) {
+  Expr *Arg = TheCall->getArg(0);
+
+  const TargetInfo *TheTI = nullptr;
+  if (TI.supportsCpuSupports())
+    TheTI = &TI;
+  else if (AuxTI && AuxTI->supportsCpuSupports())
+    TheTI = AuxTI;
+  else
+    return S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
+           << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
+
+  // Check if the argument is a string literal.
+  if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts()))
+    return S.Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
+           << Arg->getSourceRange();
+
+  // Check the contents of the string.
+  StringRef Feature =
+      cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString();
+  if (!TheTI->validateCpuSupports(Feature))
+    return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_supports)
+           << Arg->getSourceRange();
+  return false;
+}
+
+/// SemaBuiltinCpuIs - Handle __builtin_cpu_is(char *).
+/// This checks that the target supports __builtin_cpu_is and
+/// that the string argument is constant and valid.
+static bool SemaBuiltinCpuIs(Sema &S, const TargetInfo &TI,
+                             const TargetInfo *AuxTI, CallExpr *TheCall) {
+  Expr *Arg = TheCall->getArg(0);
+
+  const TargetInfo *TheTI = nullptr;
+  if (TI.supportsCpuIs())
+    TheTI = &TI;
+  else if (AuxTI && AuxTI->supportsCpuIs())
+    TheTI = AuxTI;
+  else
+    return S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
+           << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
+
+  // Check if the argument is a string literal.
+  if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts()))
+    return S.Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
+           << Arg->getSourceRange();
+
+  // Check the contents of the string.
+  StringRef Feature =
+      cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString();
+  if (!TheTI->validateCpuIs(Feature))
+    return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_is)
+           << Arg->getSourceRange();
+  return false;
+}
+
 ExprResult
 Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
                                CallExpr *TheCall) {
@@ -2137,6 +2197,23 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
   }
 
   switch (BuiltinID) {
+  case Builtin::BI__builtin_cpu_supports:
+    if (SemaBuiltinCpuSupports(*this, Context.getTargetInfo(),
+                               Context.getAuxTargetInfo(), TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_cpu_is:
+    if (SemaBuiltinCpuIs(*this, Context.getTargetInfo(),
+                         Context.getAuxTargetInfo(), TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_cpu_init:
+    if (!Context.getTargetInfo().supportsCpuInit()) {
+      Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
+          << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
+      return ExprError();
+    }
+    break;
   case Builtin::BI__builtin___CFStringMakeConstantString:
     // CFStringMakeConstantString is currently not implemented for GOFF (i.e.,
     // on z/OS) and for XCOFF (i.e., on AIX). Emit unsupported
@@ -5582,47 +5659,6 @@ bool Sema::CheckNVPTXBuiltinFunctionCall(const TargetInfo &TI,
   return false;
 }
 
-/// SemaBuiltinCpuSupports - Handle __builtin_cpu_supports(char *).
-/// This checks that the target supports __builtin_cpu_supports and
-/// that the string argument is constant and valid.
-static bool SemaBuiltinCpuSupports(Sema &S, const TargetInfo &TI,
-                                   CallExpr *TheCall) {
-  Expr *Arg = TheCall->getArg(0);
-
-  // Check if the argument is a string literal.
-  if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts()))
-    return S.Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
-           << Arg->getSourceRange();
-
-  // Check the contents of the string.
-  StringRef Feature =
-      cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString();
-  if (!TI.validateCpuSupports(Feature))
-    return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_supports)
-           << Arg->getSourceRange();
-  return false;
-}
-
-/// SemaBuiltinCpuIs - Handle __builtin_cpu_is(char *).
-/// This checks that the target supports __builtin_cpu_is and
-/// that the string argument is constant and valid.
-static bool SemaBuiltinCpuIs(Sema &S, const TargetInfo &TI, CallExpr *TheCall) {
-  Expr *Arg = TheCall->getArg(0);
-
-  // Check if the argument is a string literal.
-  if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts()))
-    return S.Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
-           << Arg->getSourceRange();
-
-  // Check the contents of the string.
-  StringRef Feature =
-      cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString();
-  if (!TI.validateCpuIs(Feature))
-    return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_is)
-           << Arg->getSourceRange();
-  return false;
-}
-
 // Check if the rounding mode is legal.
 bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) {
   // Indicates if this instruction has rounding control or just SAE.
@@ -6097,12 +6133,6 @@ static bool isX86_32Builtin(unsigned BuiltinID) {
 
 bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
                                        CallExpr *TheCall) {
-  if (BuiltinID == X86::BI__builtin_cpu_supports)
-    return SemaBuiltinCpuSupports(*this, TI, TheCall);
-
-  if (BuiltinID == X86::BI__builtin_cpu_is)
-    return SemaBuiltinCpuIs(*this, TI, TheCall);
-
   // Check for 32-bit only builtins on a 64-bit target.
   const llvm::Triple &TT = TI.getTriple();
   if (TT.getArch() != llvm::Triple::x86 && isX86_32Builtin(BuiltinID))
diff --git a/clang/test/CodeGen/builtin-cpu-supports.c b/clang/test/CodeGen/builtin-cpu-supports.c
index 796611c1fcd9afd..42497d8845437a4 100644
--- a/clang/test/CodeGen/builtin-cpu-supports.c
+++ b/clang/test/CodeGen/builtin-cpu-supports.c
@@ -1,11 +1,16 @@
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm < %s| FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm < %s | FileCheck %s \
+// RUN:   --check-prefix=CHECK-X86
+// RUN: %clang_cc1 -triple ppc64le-linux-gnu -emit-llvm < %s | FileCheck %s \
+// RUN:   --check-prefix=CHECK-PPC
+
+#ifndef __PPC__
 
 // Test that we have the structure definition, the gep offsets, the name of the
 // global, the bit grab, and the icmp correct.
 extern void a(const char *);
 
-// CHECK: @__cpu_model = external dso_local global { i32, i32, i32, [1 x i32] }
-// CHECK: @__cpu_features2 = external dso_local global [3 x i32]
+// CHECK-X86: @__cpu_model = external dso_local global { i32, i32, i32, [1 x i32] }
+// CHECK-X86: @__cpu_features2 = external dso_local global [3 x i32]
 
 int main(void) {
   __builtin_cpu_init();
@@ -15,38 +20,57 @@ int main(void) {
   if (__builtin_cpu_supports("sse4.2"))
     a("sse4.2");
 
-  // CHECK: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, ptr @__cpu_model, i32 0, i32 3, i32 0)
-  // CHECK: [[AND:%[^ ]+]] = and i32 [[LOAD]], 256
-  // CHECK: = icmp eq i32 [[AND]], 256
+  // CHECK-X86: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, ptr @__cpu_model, i32 0, i32 3, i32 0)
+  // CHECK-X86: [[AND:%[^ ]+]] = and i32 [[LOAD]], 256
+  // CHECK-X86: = icmp eq i32 [[AND]], 256
 
   if (__builtin_cpu_supports("gfni"))
     a("gfni");
 
-  // CHECK: [[LOAD:%[^ ]+]] = load i32, ptr @__cpu_features2
-  // CHECK: [[AND:%[^ ]+]] = and i32 [[LOAD]], 1
-  // CHECK: = icmp eq i32 [[AND]], 1
+  // CHECK-X86: [[LOAD:%[^ ]+]] = load i32, ptr @__cpu_features2
+  // CHECK-X86: [[AND:%[^ ]+]] = and i32 [[LOAD]], 1
+  // CHECK-X86: = icmp eq i32 [[AND]], 1
 
   return 0;
 }
 
-// CHECK: declare dso_local void @__cpu_indicator_init()
+// CHECK-X86: 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
+// CHECK-X86-LABEL: define{{.*}} @baseline(
+// CHECK-X86:         [[LOAD:%.*]] = load i32, ptr getelementptr inbounds ([[[#]] x i32], ptr @__cpu_features2, i32 0, i32 1)
+// CHECK-X86-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
+// CHECK-X86-LABEL: define{{.*}} @v2(
+// CHECK-X86:         [[LOAD:%.*]] = load i32, ptr getelementptr inbounds ([[[#]] x i32], ptr @__cpu_features2, i32 0, i32 2)
+// CHECK-X86-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
+// CHECK-X86-LABEL: define{{.*}} @v3(
+// CHECK-X86:         [[LOAD:%.*]] = load i32, ptr getelementptr inbounds ([[[#]] x i32], ptr @__cpu_features2, i32 0, i32 2)
+// CHECK-X86-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
+// CHECK-X86-LABEL: define{{.*}} @v4(
+// CHECK-X86:         [[LOAD:%.*]] = load i32, ptr getelementptr inbounds ([[[#]] x i32], ptr @__cpu_features2, i32 0, i32 2)
+// CHECK-X86-NEXT:    and i32 [[LOAD]], 4
 int v4() { return __builtin_cpu_supports("x86-64-v4"); }
+#else
+int test(int a) {
+// CHECK-PPC: [[CPUSUP:%[^ ]+]] = call i32 @llvm.ppc.fixed.addr.ld(i32 2)
+// CHECK-PPC: [[AND:%[^ ]+]] = and i32 [[CPUSUP]], 8388608
+// CHECK-PPC: icmp ne i32 [[AND]], 0
+// CHECK-PPC: [[CPUSUP2:%[^ ]+]] = call i32 @llvm.ppc.fixed.addr.ld(i32 1)
+// CHECK-PPC: [[AND2:%[^ ]+]] = and i32 [[CPUSUP2]], 67108864
+// CHECK-PPC: icmp ne i32 [[AND2]], 0
+// CHECK-PPC: [[CPUID:%[^ ]+]] = call i32 @llvm.ppc.fixed.addr.ld(i32 3)
+// CHECK-PPC: icmp eq i32 [[CPUID]], 39
+  if (__builtin_cpu_supports("arch_3_00")) // HWCAP2
+    return a;
+  else if (__builtin_cpu_supports("mmu"))  // HWCAP
+    return a - 5;
+  else if (__builtin_cpu_is("power7"))     // CPUID
+    return a + a;
+  return a + 5;
+}
+#endif
diff --git a/clang/test/Sema/builtin-cpu-supports.c b/clang/test/Sema/builtin-cpu-supports.c
index ad310128fecebf6..cc6f1beb5d8a7c4 100644
--- a/clang/test/Sema/builtin-cpu-supports.c
+++ b/clang/test/Sema/builtin-cpu-supports.c
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -triple x86_64-pc-linux-gnu -verify %s
-// RUN: %clang_cc1 -fsyntax-only -triple powerpc64le-linux-gnu -verify %s
+// RUN: %clang_cc1 -fsyntax-only -triple aarch64-linux-gnu -verify %s
 
 extern void a(const char *);
 
@@ -27,11 +27,13 @@ int main(void) {
   (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}}
+  if (__builtin_cpu_supports("aes")) // expected-error {{builtin is not supported on this target}}
     a("vsx");
 
-  if (__builtin_cpu_is("pwr9")) // expected-error {{use of unknown builtin}}
+  if (__builtin_cpu_is("cortex-x3")) // expected-error {{builtin is not supported on this target}}
     a("pwr9");
+
+  __builtin_cpu_init(); // expected-error {{builtin is not supported on this target}}
 #endif
 
   return 0;
diff --git a/llvm/include/llvm/IR/IntrinsicsPowerPC.td b/llvm/include/llvm/IR/IntrinsicsPowerPC.td
index 3ede2a3736bf30d..f4e64764b4d1ccd 100644
--- a/llvm/include/llvm/IR/IntrinsicsPowerPC.td
+++ b/llvm/include/llvm/IR/IntrinsicsPowerPC.td
@@ -210,6 +210,12 @@ let TargetPrefix = "ppc" in {  // All intrinsics start with "llvm.ppc.".
             [llvm_float_ty],
             [llvm_float_ty, llvm_float_ty, llvm_float_ty, ll...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/68919


More information about the cfe-commits mailing list