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

Nemanja Ivanovic via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 25 22:46:01 PST 2024


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

>From 65c84f2ba78efcbf92ce9c8232fc40f493414930 Mon Sep 17 00:00:00 2001
From: Nemanja Ivanovic <nemanjaivanovic at nemanjas-air.kpn>
Date: Thu, 12 Oct 2023 14:08:42 -0400
Subject: [PATCH 1/5] [PowerPC][X86] Make cpu id builtins target independent
 and lower for PPC

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.
---
 clang/include/clang/Basic/Builtins.td         |  20 +++
 clang/include/clang/Basic/BuiltinsX86.def     |   7 -
 clang/include/clang/Basic/TargetInfo.h        |   6 +
 clang/lib/Basic/Targets/PPC.cpp               |  14 ++
 clang/lib/Basic/Targets/PPC.h                 |   7 +
 clang/lib/Basic/Targets/X86.h                 |   4 +
 clang/lib/CodeGen/CGBuiltin.cpp               |  42 +++++-
 clang/lib/Sema/SemaChecking.cpp               | 124 +++++++++++-------
 clang/test/CodeGen/builtin-cpu-supports.c     |  68 ++++++----
 clang/test/Sema/builtin-cpu-supports.c        |   8 +-
 llvm/include/llvm/IR/IntrinsicsPowerPC.td     |   6 +
 .../llvm/TargetParser/PPCTargetParser.def     |  80 +++++++++++
 llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp     |   4 +
 llvm/lib/Target/PowerPC/PPCInstrInfo.cpp      |  33 +++++
 llvm/lib/Target/PowerPC/PPCInstrInfo.td       |   3 +
 llvm/lib/Target/PowerPC/PPCTargetMachine.h    |   3 +
 llvm/test/CodeGen/PowerPC/cpu-supports.ll     | 111 ++++++++++++++++
 17 files changed, 458 insertions(+), 82 deletions(-)
 create mode 100644 llvm/include/llvm/TargetParser/PPCTargetParser.def
 create mode 100644 llvm/test/CodeGen/PowerPC/cpu-supports.ll

diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 22e616e6cde599..1af01fe0d700c9 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -727,6 +727,26 @@ def RotateRight : BitInt8_16_32_64BuiltinsTemplate, Builtin {
 // FIXME: The builtins marked FunctionWithBuiltinPrefix below should be
 //        merged with the library definitions. They are currently not because
 //        the attributes are different.
+
+// Builtins for checking CPU features based on the GCC builtins.
+def BuiltinCPUIs : Builtin {
+  let Spellings = ["__builtin_cpu_is"];
+  let Attributes = [NoThrow, Const];
+  let Prototype = "bool(char const*)";
+}
+
+def BuiltinCPUSupports : Builtin {
+  let Spellings = ["__builtin_cpu_supports"];
+  let Attributes = [NoThrow, Const];
+  let Prototype = "bool(char const*)";
+}
+
+def BuiltinCPUInit : Builtin {
+  let Spellings = ["__builtin_cpu_init"];
+  let Attributes = [NoThrow];
+  let Prototype = "void()";
+}
+
 def BuiltinCalloc : Builtin {
   let Spellings = ["__builtin_calloc"];
   let Attributes = [FunctionWithBuiltinPrefix, NoThrow];
diff --git a/clang/include/clang/Basic/BuiltinsX86.def b/clang/include/clang/Basic/BuiltinsX86.def
index 60b752ad48548f..207cde0414b54e 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 3eb23ebdacf0ed..9432154d5063ce 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -1432,6 +1432,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 41935abfb65d3b..2cf1bacd95fd95 100644
--- a/clang/lib/Basic/Targets/PPC.cpp
+++ b/clang/lib/Basic/Targets/PPC.cpp
@@ -878,3 +878,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 4d62673ba7fb8c..f700b625b79030 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 0ab1c10833db26..1845f5a747af40 100644
--- a/clang/lib/Basic/Targets/X86.h
+++ b/clang/lib/Basic/Targets/X86.h
@@ -220,6 +220,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 27183c69b7ea37..3c9d8155569fac 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -14053,11 +14053,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
@@ -16545,6 +16545,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 4d280f25cc04c2..36305eeac8c9de 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2143,6 +2143,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) {
@@ -2171,6 +2231,23 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
 
   FPOptions FPO;
   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
@@ -6256,47 +6333,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.
@@ -6771,12 +6807,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 796611c1fcd9af..42497d8845437a 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 ad310128fecebf..cc6f1beb5d8a7c 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 6d1e8eb47405dd..d1abc37e072f70 100644
--- a/llvm/include/llvm/IR/IntrinsicsPowerPC.td
+++ b/llvm/include/llvm/IR/IntrinsicsPowerPC.td
@@ -215,6 +215,12 @@ let TargetPrefix = "ppc" in {  // All intrinsics start with "llvm.ppc.".
             [llvm_float_ty],
             [llvm_float_ty, llvm_float_ty, llvm_float_ty, llvm_vararg_ty],
             [IntrNoMem]>;
+  // Load of a value provided by the system library at a fixed address. Used for
+  // accessing things like HWCAP word provided by GLIBC.
+  def int_ppc_fixed_addr_ld
+      : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty],
+                              [IntrInaccessibleMemOnly, ImmArg<ArgIndex<0>>]>;
+
 }
 
 let TargetPrefix = "ppc" in {  // All PPC intrinsics start with "llvm.ppc.".
diff --git a/llvm/include/llvm/TargetParser/PPCTargetParser.def b/llvm/include/llvm/TargetParser/PPCTargetParser.def
new file mode 100644
index 00000000000000..e935e0112956fe
--- /dev/null
+++ b/llvm/include/llvm/TargetParser/PPCTargetParser.def
@@ -0,0 +1,80 @@
+#ifndef PPC_FEATURE
+#define PPC_FEATURE(NAME, DESC, ENUMNAME, ENUMVAL, HWCAPN)
+#endif
+#ifndef PPC_CPU
+#define PPC_CPU(NAME, NUM)
+#endif
+#ifndef PPC_FAWORD_HWCAP
+#define PPC_FAWORD_HWCAP 1
+#endif
+#ifndef PPC_FAWORD_HWCAP2
+#define PPC_FAWORD_HWCAP2 2
+#endif
+#ifndef PPC_FAWORD_CPUID
+#define PPC_FAWORD_CPUID 3
+#endif
+
+// PPC_FEATURE(Name, Description, EnumName, BitMask, PPC_FAWORD_WORD)
+PPC_FEATURE("4xxmac","4xx CPU has a Multiply Accumulator",PPCF_4XXMAC,0x02000000,PPC_FAWORD_HWCAP)
+PPC_FEATURE("altivec","CPU has a SIMD/Vector Unit",PPCF_ALTIVEC,0x10000000,PPC_FAWORD_HWCAP)
+PPC_FEATURE("arch_2_05","CPU supports ISA 205 (eg, POWER6)",PPCF_ARCH205,0x00001000,PPC_FAWORD_HWCAP)
+PPC_FEATURE("arch_2_06","CPU supports ISA 206 (eg, POWER7)",PPCF_ARCH206,0x00000100,PPC_FAWORD_HWCAP)
+PPC_FEATURE("arch_2_07","CPU supports ISA 207 (eg, POWER8)",PPCF_ARCH207,0x80000000,PPC_FAWORD_HWCAP2)
+PPC_FEATURE("arch_3_00","CPU supports ISA 30 (eg, POWER9)",PPCF_ARCH30,0x00800000,PPC_FAWORD_HWCAP2)
+PPC_FEATURE("arch_3_1","CPU supports ISA 31 (eg, POWER10)",PPCF_ARCH31,0x00040000,PPC_FAWORD_HWCAP2)
+PPC_FEATURE("archpmu","CPU supports the set of compatible performance monitoring events",PPCF_ARCHPMU,0x00000040,PPC_FAWORD_HWCAP)
+PPC_FEATURE("booke","CPU supports the Embedded ISA category",PPCF_BOOKE,0x00008000,PPC_FAWORD_HWCAP)
+PPC_FEATURE("cellbe","CPU has a CELL broadband engine",PPCF_CELLBE,0x00010000,PPC_FAWORD_HWCAP)
+PPC_FEATURE("darn","CPU supports the darn (deliver a random number) instruction",PPCF_DARN,0x00200000,PPC_FAWORD_HWCAP2)
+PPC_FEATURE("dfp","CPU has a decimal floating point unit",PPCF_DFP,0x00000400,PPC_FAWORD_HWCAP)
+PPC_FEATURE("dscr","CPU supports the data stream control register",PPCF_DSCR,0x20000000,PPC_FAWORD_HWCAP2)
+PPC_FEATURE("ebb","CPU supports event base branching",PPCF_EBB,0x10000000,PPC_FAWORD_HWCAP2)
+PPC_FEATURE("efpdouble","CPU has a SPE double precision floating point unit",PPCF_EFPDOUBLE,0x00200000,PPC_FAWORD_HWCAP)
+PPC_FEATURE("efpsingle","CPU has a SPE single precision floating point unit",PPCF_EFPSINGLE,0x00400000,PPC_FAWORD_HWCAP)
+PPC_FEATURE("fpu","CPU has a floating point unit",PPCF_FPU,0x08000000,PPC_FAWORD_HWCAP)
+PPC_FEATURE("htm","CPU has hardware transaction memory instructions",PPCF_HTM,0x40000000,PPC_FAWORD_HWCAP2)
+PPC_FEATURE("htm-nosc","Kernel aborts hardware transactions when a syscall is made",PPCF_HTM_NOSC,0x01000000,PPC_FAWORD_HWCAP2)
+PPC_FEATURE("htm-no-suspend","CPU supports hardware transaction memory but does not support the tsuspend instruction.",PPCF_HTM_NO_SUSPEND,0x00080000,PPC_FAWORD_HWCAP2)
+PPC_FEATURE("ic_snoop","CPU supports icache snooping capabilities",PPCF_IC_SNOOP,0x00002000,PPC_FAWORD_HWCAP)
+PPC_FEATURE("ieee128","CPU supports 128-bit IEEE binary floating point instructions",PPCF_IEEE128,0x00400000,PPC_FAWORD_HWCAP2)
+PPC_FEATURE("isel","CPU supports the integer select instruction",PPCF_ISEL,0x08000000,PPC_FAWORD_HWCAP2)
+PPC_FEATURE("mma","CPU supports the matrix-multiply assist instructions",PPCF_MMA,0x00020000,PPC_FAWORD_HWCAP2)
+PPC_FEATURE("mmu","CPU has a memory management unit",PPCF_MMU,0x04000000,PPC_FAWORD_HWCAP)
+PPC_FEATURE("notb","CPU does not have a timebase (eg, 601 and 403gx)",PPCF_NOTB,0x00100000,PPC_FAWORD_HWCAP)
+PPC_FEATURE("pa6t","CPU supports the PA Semi 6T CORE ISA",PPCF_PA6T,0x00000800,PPC_FAWORD_HWCAP)
+PPC_FEATURE("power4","CPU supports ISA 200 (eg, POWER4)",PPCF_POWER4,0x00080000,PPC_FAWORD_HWCAP)
+PPC_FEATURE("power5","CPU supports ISA 202 (eg, POWER5)",PPCF_POWER5,0x00040000,PPC_FAWORD_HWCAP)
+PPC_FEATURE("power5+","CPU supports ISA 203 (eg, POWER5+)",PPCF_POWER5P,0x00020000,PPC_FAWORD_HWCAP)
+PPC_FEATURE("power6x","CPU supports ISA 205 (eg, POWER6) extended opcodes mffgpr and mftgpr.",PPCF_POWER6X,0x00000200,PPC_FAWORD_HWCAP)
+PPC_FEATURE("ppc32","CPU supports 32-bit mode execution",PPCF_PPC32,0x80000000,PPC_FAWORD_HWCAP)
+PPC_FEATURE("ppc601","CPU supports the old POWER ISA (eg, 601)",PPCF_PPC601,0x20000000,PPC_FAWORD_HWCAP)
+PPC_FEATURE("ppc64","CPU supports 64-bit mode execution",PPCF_PPC64,0x40000000,PPC_FAWORD_HWCAP)
+PPC_FEATURE("ppcle","CPU supports a little-endian mode that uses address swizzling",PPCF_PPCLE,0x00000001,PPC_FAWORD_HWCAP)
+PPC_FEATURE("scv","Kernel supports system call vectored",PPCF_SCV,0x00100000,PPC_FAWORD_HWCAP2)
+PPC_FEATURE("smt","CPU support simultaneous multi-threading",PPCF_SMT,0x00004000,PPC_FAWORD_HWCAP)
+PPC_FEATURE("spe","CPU has a signal processing extension unit",PPCF_SPE,0x00800000,PPC_FAWORD_HWCAP)
+PPC_FEATURE("tar","CPU supports the target address register",PPCF_TAR,0x04000000,PPC_FAWORD_HWCAP2)
+PPC_FEATURE("true_le","CPU supports true little-endian mode",PPCF_TRUE_LE,0x00000002,PPC_FAWORD_HWCAP)
+PPC_FEATURE("ucache","CPU has unified I/D cache",PPCF_UCACHE,0x01000000,PPC_FAWORD_HWCAP)
+PPC_FEATURE("vcrypto","CPU supports the vector cryptography instructions",PPCF_VCRYPTO,0x02000000,PPC_FAWORD_HWCAP2)
+PPC_FEATURE("vsx","CPU supports the vector-scalar extension",PPCF_VSX,0x00000080,PPC_FAWORD_HWCAP)
+
+// PPC_CPU(Name, NumericID)
+PPC_CPU("power4",32)
+PPC_CPU("ppc970",33)
+PPC_CPU("power5",34)
+PPC_CPU("power5+",35)
+PPC_CPU("power6",36)
+PPC_CPU("ppc-cell-be",37)
+PPC_CPU("power6x",38)
+PPC_CPU("power7",39)
+PPC_CPU("ppca2",40)
+PPC_CPU("ppc405",41)
+PPC_CPU("ppc440",42)
+PPC_CPU("ppc464",43)
+PPC_CPU("ppc476",44)
+PPC_CPU("power8",45)
+PPC_CPU("power9",46)
+PPC_CPU("power10",47)
+#undef PPC_FEATURE
+#undef PPC_CPU
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 780b22b4fbe65e..46afb882d80c5d 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -1821,6 +1821,10 @@ void PPCLinuxAsmPrinter::emitEndOfAsmFile(Module &M) {
   PPCTargetStreamer *TS =
       static_cast<PPCTargetStreamer *>(OutStreamer->getTargetStreamer());
 
+  if (static_cast<const PPCTargetMachine &>(TM).hasGlibcHWCAPAccess())
+    OutStreamer->emitSymbolValue(
+        GetExternalSymbolSymbol("__parse_hwcap_and_convert_at_platform"),
+        MAI->getCodePointerSize());
   emitGNUAttributes(M);
 
   if (!TOC.empty()) {
diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
index 15f6b65dea83c4..77fe34a6cbbcb3 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
+++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
@@ -1079,6 +1079,7 @@ bool PPCInstrInfo::isReallyTriviallyReMaterializable(
   case PPC::ADDIStocHA8:
   case PPC::ADDItocL:
   case PPC::LOAD_STACK_GUARD:
+  case PPC::PPCLdFixedAddr:
   case PPC::XXLXORz:
   case PPC::XXLXORspz:
   case PPC::XXLXORdpz:
@@ -3099,6 +3100,38 @@ bool PPCInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
         .addReg(Reg);
     return true;
   }
+  case PPC::PPCLdFixedAddr: {
+    assert(Subtarget.isTargetLinux() &&
+           "Only Linux target is expected to contain PPCLdFixedAddr");
+    int64_t Offset = 0;
+    const unsigned Reg = Subtarget.isPPC64() ? PPC::X13 : PPC::R2;
+    MI.setDesc(get(PPC::LWZ));
+    uint64_t FAType = MI.getOperand(1).getImm();
+#undef PPC_FEATURE
+#undef PPC_CPU
+#include "llvm/TargetParser/PPCTargetParser.def"
+    // The HWCAP and HWCAP2 word offsets are reversed on big endian Linux.
+    if ((FAType == PPC_FAWORD_HWCAP && Subtarget.isLittleEndian()) ||
+        (FAType == PPC_FAWORD_HWCAP2 && !Subtarget.isLittleEndian()))
+      Offset = Subtarget.isPPC64() ? -0x7064 : -0x703C;
+    else if ((FAType == PPC_FAWORD_HWCAP2 &&
+              Subtarget.isLittleEndian()) ||
+             (FAType == PPC_FAWORD_HWCAP &&
+              !Subtarget.isLittleEndian()))
+      Offset = Subtarget.isPPC64() ? -0x7068 : -0x7040;
+    else if (FAType == PPC_FAWORD_CPUID)
+      Offset = Subtarget.isPPC64() ? -0x705C : -0x7034;
+    assert(Offset && "Do not know the offset for this fixed addr load");
+    MI.removeOperand(1);
+    Subtarget.getTargetMachine().setGlibcHWCAPAccess();
+    MachineInstrBuilder(*MI.getParent()->getParent(), MI)
+        .addImm(Offset)
+        .addReg(Reg);
+    return true;
+#undef PPC_FAWORD_HWCAP
+#undef PPC_FAWORD_HWCAP2
+#undef PPC_FAWORD_CPUID
+  }
   case PPC::DFLOADf32:
   case PPC::DFLOADf64:
   case PPC::DFSTOREf32:
diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.td b/llvm/lib/Target/PowerPC/PPCInstrInfo.td
index 5550ba4207392b..3abd97f2c38c09 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrInfo.td
+++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.td
@@ -4830,6 +4830,9 @@ def RLWNMbm : PPCAsmPseudo<"rlwnm $rA, $rS, $n, $b",
                           (ins g8rc:$rA, g8rc:$rS, u5imm:$n, i32imm:$b)>;
 def RLWNMbm_rec : PPCAsmPseudo<"rlwnm. $rA, $rS, $n, $b",
                            (ins g8rc:$rA, g8rc:$rS, u5imm:$n, i32imm:$b)>;
+def PPCLdFixedAddr :
+  PPCPostRAExpPseudo<(outs gprc:$rT), (ins i32imm:$imm), "#FA_LOAD",
+                     [(set i32:$rT, (int_ppc_fixed_addr_ld timm:$imm))]>;
 
 // These generic branch instruction forms are used for the assembler parser only.
 // Defs and Uses are conservative, since we don't know the BO value.
diff --git a/llvm/lib/Target/PowerPC/PPCTargetMachine.h b/llvm/lib/Target/PowerPC/PPCTargetMachine.h
index 56145a2eb39ce4..9d0d3e727170a3 100644
--- a/llvm/lib/Target/PowerPC/PPCTargetMachine.h
+++ b/llvm/lib/Target/PowerPC/PPCTargetMachine.h
@@ -32,6 +32,7 @@ class PPCTargetMachine final : public LLVMTargetMachine {
   std::unique_ptr<TargetLoweringObjectFile> TLOF;
   PPCABI TargetABI;
   Endian Endianness = Endian::NOT_DETECTED;
+  mutable bool HasGlibcHWCAPAccess = false;
 
   mutable StringMap<std::unique_ptr<PPCSubtarget>> SubtargetMap;
 
@@ -64,6 +65,8 @@ class PPCTargetMachine final : public LLVMTargetMachine {
                             const TargetSubtargetInfo *STI) const override;
 
   bool isELFv2ABI() const { return TargetABI == PPC_ABI_ELFv2; }
+  bool hasGlibcHWCAPAccess() const { return HasGlibcHWCAPAccess; }
+  void setGlibcHWCAPAccess(bool Val = true) const { HasGlibcHWCAPAccess = Val; }
   bool isPPC64() const {
     const Triple &TT = getTargetTriple();
     return (TT.getArch() == Triple::ppc64 || TT.getArch() == Triple::ppc64le);
diff --git a/llvm/test/CodeGen/PowerPC/cpu-supports.ll b/llvm/test/CodeGen/PowerPC/cpu-supports.ll
new file mode 100644
index 00000000000000..912d67e5c555e6
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/cpu-supports.ll
@@ -0,0 +1,111 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc -mcpu=pwr9 -ppc-asm-full-reg-names \
+; RUN:   -mtriple=powerpc64-linux-gnu < %s | FileCheck  %s \
+; RUN:   -check-prefix=BE64
+; RUN: llc -mcpu=pwr9 -ppc-asm-full-reg-names \
+; RUN:   -mtriple=powerpc-linux-gnu < %s | FileCheck  %s \
+; RUN:   -check-prefix=BE32
+; RUN: llc -mcpu=pwr9 -ppc-asm-full-reg-names \
+; RUN:   -mtriple=powerpc64le-linux-gnu < %s | FileCheck  %s \
+; RUN:   -check-prefix=LE
+define dso_local signext i32 @test(i32 noundef signext %a) local_unnamed_addr #0 {
+; BE64-LABEL: test:
+; BE64:       # %bb.0: # %entry
+; BE64-NEXT:    lwz r4, -28772(r13)
+; BE64-NEXT:    andis. r4, r4, 128
+; BE64-NEXT:    bne cr0, .LBB0_3
+; BE64-NEXT:  # %bb.1: # %if.else
+; BE64-NEXT:    lwz r4, -28776(r13)
+; BE64-NEXT:    andis. r4, r4, 1024
+; BE64-NEXT:    bne cr0, .LBB0_4
+; BE64-NEXT:  # %bb.2: # %if.else3
+; BE64-NEXT:    lwz r4, -28764(r13)
+; BE64-NEXT:    cmplwi r4, 39
+; BE64-NEXT:    addi r4, r3, 5
+; BE64-NEXT:    slwi r3, r3, 1
+; BE64-NEXT:    iseleq r3, r3, r4
+; BE64-NEXT:  .LBB0_3: # %return
+; BE64-NEXT:    extsw r3, r3
+; BE64-NEXT:    blr
+; BE64-NEXT:  .LBB0_4: # %if.then2
+; BE64-NEXT:    addi r3, r3, -5
+; BE64-NEXT:    extsw r3, r3
+; BE64-NEXT:    blr
+;
+; BE32-LABEL: test:
+; BE32:       # %bb.0: # %entry
+; BE32-NEXT:    lwz r4, -28732(r2)
+; BE32-NEXT:    andis. r4, r4, 128
+; BE32-NEXT:    bnelr cr0
+; BE32-NEXT:  # %bb.1: # %if.else
+; BE32-NEXT:    lwz r4, -28736(r2)
+; BE32-NEXT:    andis. r4, r4, 1024
+; BE32-NEXT:    bne cr0, .LBB0_3
+; BE32-NEXT:  # %bb.2: # %if.else3
+; BE32-NEXT:    lwz r4, -28724(r2)
+; BE32-NEXT:    cmplwi r4, 39
+; BE32-NEXT:    addi r4, r3, 5
+; BE32-NEXT:    slwi r3, r3, 1
+; BE32-NEXT:    iseleq r3, r3, r4
+; BE32-NEXT:    blr
+; BE32-NEXT:  .LBB0_3: # %if.then2
+; BE32-NEXT:    addi r3, r3, -5
+; BE32-NEXT:    blr
+;
+; LE-LABEL: test:
+; LE:       # %bb.0: # %entry
+; LE-NEXT:    lwz r4, -28776(r13)
+; LE-NEXT:    andis. r4, r4, 128
+; LE-NEXT:    bne cr0, .LBB0_3
+; LE-NEXT:  # %bb.1: # %if.else
+; LE-NEXT:    lwz r4, -28772(r13)
+; LE-NEXT:    andis. r4, r4, 1024
+; LE-NEXT:    bne cr0, .LBB0_4
+; LE-NEXT:  # %bb.2: # %if.else3
+; LE-NEXT:    lwz r4, -28764(r13)
+; LE-NEXT:    cmplwi r4, 39
+; LE-NEXT:    addi r4, r3, 5
+; LE-NEXT:    slwi r3, r3, 1
+; LE-NEXT:    iseleq r3, r3, r4
+; LE-NEXT:  .LBB0_3: # %return
+; LE-NEXT:    extsw r3, r3
+; LE-NEXT:    blr
+; LE-NEXT:  .LBB0_4: # %if.then2
+; LE-NEXT:    addi r3, r3, -5
+; LE-NEXT:    extsw r3, r3
+; LE-NEXT:    blr
+entry:
+  %cpu_supports = tail call i32 @llvm.ppc.fixed.addr.ld(i32 2)
+  %0 = and i32 %cpu_supports, 8388608
+  %.not = icmp eq i32 %0, 0
+  br i1 %.not, label %if.else, label %return
+
+if.else:                                          ; preds = %entry
+  %cpu_supports1 = tail call i32 @llvm.ppc.fixed.addr.ld(i32 1)
+  %1 = and i32 %cpu_supports1, 67108864
+  %.not12 = icmp eq i32 %1, 0
+  br i1 %.not12, label %if.else3, label %if.then2
+
+if.then2:                                         ; preds = %if.else
+  %sub = add nsw i32 %a, -5
+  br label %return
+
+if.else3:                                         ; preds = %if.else
+  %cpu_is = tail call i32 @llvm.ppc.fixed.addr.ld(i32 3)
+  %2 = icmp eq i32 %cpu_is, 39
+  br i1 %2, label %if.then4, label %if.end6
+
+if.then4:                                         ; preds = %if.else3
+  %add = shl nsw i32 %a, 1
+  br label %return
+
+if.end6:                                          ; preds = %if.else3
+  %add7 = add nsw i32 %a, 5
+  br label %return
+
+return:                                           ; preds = %entry, %if.end6, %if.then4, %if.then2
+  %retval.0 = phi i32 [ %sub, %if.then2 ], [ %add, %if.then4 ], [ %add7, %if.end6 ], [ %a, %entry ]
+  ret i32 %retval.0
+}
+
+declare i32 @llvm.ppc.fixed.addr.ld(i32 immarg) #1

>From 60e1aba57ad08d69349bb9fe768e6fd3abf832bc Mon Sep 17 00:00:00 2001
From: Nemanja Ivanovic <nemanjaivanovic at nemanjas-air.kpn>
Date: Thu, 12 Oct 2023 14:32:07 -0400
Subject: [PATCH 2/5] Run clang-format which I appear to have forgotten to run

---
 clang/lib/CodeGen/CGBuiltin.cpp          | 3 +--
 llvm/lib/Target/PowerPC/PPCInstrInfo.cpp | 6 ++----
 2 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 3c9d8155569fac..fa6859d6921585 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -16552,8 +16552,7 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
 #define PPC_CPU(Name, NumericID) .Case(Name, NumericID)
 #include "llvm/TargetParser/PPCTargetParser.def"
                             .Default(-1U);
-    Value *Op0 =
-        llvm::ConstantInt::get(Int32Ty, PPC_FAWORD_CPUID);
+    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,
diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
index 77fe34a6cbbcb3..34d41d05089586 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
+++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
@@ -3114,10 +3114,8 @@ bool PPCInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
     if ((FAType == PPC_FAWORD_HWCAP && Subtarget.isLittleEndian()) ||
         (FAType == PPC_FAWORD_HWCAP2 && !Subtarget.isLittleEndian()))
       Offset = Subtarget.isPPC64() ? -0x7064 : -0x703C;
-    else if ((FAType == PPC_FAWORD_HWCAP2 &&
-              Subtarget.isLittleEndian()) ||
-             (FAType == PPC_FAWORD_HWCAP &&
-              !Subtarget.isLittleEndian()))
+    else if ((FAType == PPC_FAWORD_HWCAP2 && Subtarget.isLittleEndian()) ||
+             (FAType == PPC_FAWORD_HWCAP && !Subtarget.isLittleEndian()))
       Offset = Subtarget.isPPC64() ? -0x7068 : -0x7040;
     else if (FAType == PPC_FAWORD_CPUID)
       Offset = Subtarget.isPPC64() ? -0x705C : -0x7034;

>From dd421e7e6aba4886b6d6d7231d5ec3e456640da8 Mon Sep 17 00:00:00 2001
From: Nemanja Ivanovic <nemanja at synopsys.com>
Date: Thu, 11 Jan 2024 13:23:28 +0100
Subject: [PATCH 3/5] Address comments

- Use script for generating test checks
- Clean up code and rename macros for clarity
- Remove magic number offsets
- Get rid of auxiliary targets in Sema checking
- Clarify some comments and add missing ones
- Add check for undefined symbol added for safety
---
 clang/lib/Basic/Targets/PPC.cpp               |   4 +-
 clang/lib/CodeGen/CGBuiltin.cpp               |   4 +-
 clang/lib/Sema/SemaChecking.cpp               |  71 ++-----
 clang/test/CodeGen/builtin-cpu-supports.c     | 149 +++++++++++---
 llvm/include/llvm/IR/IntrinsicsPowerPC.td     |   5 +-
 .../llvm/TargetParser/PPCTargetParser.def     | 183 +++++++++++-------
 llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp     |   4 +
 llvm/lib/Target/PowerPC/PPCInstrInfo.cpp      |  42 ++--
 llvm/test/CodeGen/PowerPC/cpu-supports.ll     |   3 +
 9 files changed, 294 insertions(+), 171 deletions(-)

diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp
index 2cf1bacd95fd95..c03350ceb6d965 100644
--- a/clang/lib/Basic/Targets/PPC.cpp
+++ b/clang/lib/Basic/Targets/PPC.cpp
@@ -880,14 +880,14 @@ ArrayRef<Builtin::Info> PPCTargetInfo::getTargetBuiltins() const {
 }
 
 bool PPCTargetInfo::validateCpuSupports(StringRef FeatureStr) const {
-#define PPC_FEATURE(NAME, DESC, ENUMNAME, ENUMVAL, HWCAPN) .Case(NAME, true)
+#define PPC_LNX_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)
+#define PPC_LNX_CPU(NAME, NUM) .Case(NAME, true)
   return llvm::StringSwitch<bool>(CPUName)
 #include "llvm/TargetParser/PPCTargetParser.def"
       .Default(false);
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index fa6859d6921585..e5b15a74da392b 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -16549,7 +16549,7 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
     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)
+#define PPC_LNX_CPU(Name, NumericID) .Case(Name, NumericID)
 #include "llvm/TargetParser/PPCTargetParser.def"
                             .Default(-1U);
     Value *Op0 = llvm::ConstantInt::get(Int32Ty, PPC_FAWORD_CPUID);
@@ -16565,7 +16565,7 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
     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)             \
+#define PPC_LNX_FEATURE(Name, Description, EnumName, Bitmask, FA_WORD)         \
   .Case(Name, {FA_WORD, Bitmask})
 #include "llvm/TargetParser/PPCTargetParser.def"
             .Default({0, 0});
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 36305eeac8c9de..9edf568ec95f05 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2143,61 +2143,35 @@ 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
+/// SemaBuiltinCpu{Supports|Is} - Handle __builtin_cpu_{supports|is}(char *).
+/// This checks that the target supports the builtin and that the string
+/// argument is constant and valid.
+static bool SemaBuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall,
+                           unsigned BuiltinID) {
+  assert((BuiltinID == Builtin::BI__builtin_cpu_supports ||
+          BuiltinID == Builtin::BI__builtin_cpu_is) &&
+         "Expecting __builtin_cpu_...");
+
+  bool IsCPUSupports = BuiltinID == Builtin::BI__builtin_cpu_supports;
+  if (IsCPUSupports && !TI.supportsCpuSupports())
     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
+  if (!IsCPUSupports && !TI.supportsCpuIs())
     return S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
            << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
 
+  Expr *Arg = TheCall->getArg(0)->IgnoreParenImpCasts();
   // Check if the argument is a string literal.
-  if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts()))
+  if (!isa<StringLiteral>(Arg))
     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))
+  StringRef Feature = cast<StringLiteral>(Arg)->getString();
+  if (IsCPUSupports && !TI.validateCpuSupports(Feature))
+    return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_supports)
+           << Arg->getSourceRange();
+  if (!IsCPUSupports && !TI.validateCpuIs(Feature))
     return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_is)
            << Arg->getSourceRange();
   return false;
@@ -2232,13 +2206,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
   FPOptions FPO;
   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))
+    if (SemaBuiltinCpu(*this, Context.getTargetInfo(), TheCall, BuiltinID))
       return ExprError();
     break;
   case Builtin::BI__builtin_cpu_init:
diff --git a/clang/test/CodeGen/builtin-cpu-supports.c b/clang/test/CodeGen/builtin-cpu-supports.c
index 42497d8845437a..88eb7b0fa786e5 100644
--- a/clang/test/CodeGen/builtin-cpu-supports.c
+++ b/clang/test/CodeGen/builtin-cpu-supports.c
@@ -1,6 +1,7 @@
-// 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 \
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 3
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s | \
+// RUN:   FileCheck %s --check-prefix=CHECK-X86
+// RUN: %clang_cc1 -triple ppc64le-linux-gnu -emit-llvm -o - %s | FileCheck %s \
 // RUN:   --check-prefix=CHECK-PPC
 
 #ifndef __PPC__
@@ -9,9 +10,33 @@
 // global, the bit grab, and the icmp correct.
 extern void a(const char *);
 
-// 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]
 
+// CHECK-X86-LABEL: define dso_local i32 @main(
+// CHECK-X86-SAME: ) #[[ATTR0:[0-9]+]] {
+// CHECK-X86-NEXT:  entry:
+// CHECK-X86-NEXT:    [[RETVAL:%.*]] = alloca i32, align 4
+// CHECK-X86-NEXT:    store i32 0, ptr [[RETVAL]], align 4
+// CHECK-X86-NEXT:    call void @__cpu_indicator_init()
+// CHECK-X86-NEXT:    [[TMP0:%.*]] = load i32, ptr getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, ptr @__cpu_model, i32 0, i32 3, i32 0), align 4
+// CHECK-X86-NEXT:    [[TMP1:%.*]] = and i32 [[TMP0]], 256
+// CHECK-X86-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 256
+// CHECK-X86-NEXT:    [[TMP3:%.*]] = and i1 true, [[TMP2]]
+// CHECK-X86-NEXT:    br i1 [[TMP3]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+// CHECK-X86:       if.then:
+// CHECK-X86-NEXT:    call void @a(ptr noundef @.str)
+// CHECK-X86-NEXT:    br label [[IF_END]]
+// CHECK-X86:       if.end:
+// CHECK-X86-NEXT:    [[TMP4:%.*]] = load i32, ptr @__cpu_features2, align 4
+// CHECK-X86-NEXT:    [[TMP5:%.*]] = and i32 [[TMP4]], 1
+// CHECK-X86-NEXT:    [[TMP6:%.*]] = icmp eq i32 [[TMP5]], 1
+// CHECK-X86-NEXT:    [[TMP7:%.*]] = and i1 true, [[TMP6]]
+// CHECK-X86-NEXT:    br i1 [[TMP7]], label [[IF_THEN1:%.*]], label [[IF_END2:%.*]]
+// CHECK-X86:       if.then1:
+// CHECK-X86-NEXT:    call void @a(ptr noundef @.str.1)
+// CHECK-X86-NEXT:    br label [[IF_END2]]
+// CHECK-X86:       if.end2:
+// CHECK-X86-NEXT:    ret i32 0
+//
 int main(void) {
   __builtin_cpu_init();
 
@@ -20,51 +45,111 @@ int main(void) {
   if (__builtin_cpu_supports("sse4.2"))
     a("sse4.2");
 
-  // 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-X86: [[LOAD:%[^ ]+]] = load i32, ptr @__cpu_features2
-  // CHECK-X86: [[AND:%[^ ]+]] = and i32 [[LOAD]], 1
-  // CHECK-X86: = icmp eq i32 [[AND]], 1
 
   return 0;
 }
 
-// CHECK-X86: declare dso_local void @__cpu_indicator_init()
 
-// 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
+// CHECK-X86-LABEL: define dso_local i32 @baseline(
+// CHECK-X86-SAME: ) #[[ATTR0]] {
+// CHECK-X86-NEXT:  entry:
+// CHECK-X86-NEXT:    [[TMP0:%.*]] = load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 1), align 4
+// CHECK-X86-NEXT:    [[TMP1:%.*]] = and i32 [[TMP0]], -2147483648
+// CHECK-X86-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], -2147483648
+// CHECK-X86-NEXT:    [[TMP3:%.*]] = and i1 true, [[TMP2]]
+// CHECK-X86-NEXT:    [[CONV:%.*]] = zext i1 [[TMP3]] to i32
+// CHECK-X86-NEXT:    ret i32 [[CONV]]
+//
 int baseline() { return __builtin_cpu_supports("x86-64"); }
 
-// 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
+// CHECK-X86-LABEL: define dso_local i32 @v2(
+// CHECK-X86-SAME: ) #[[ATTR0]] {
+// CHECK-X86-NEXT:  entry:
+// CHECK-X86-NEXT:    [[TMP0:%.*]] = load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 2), align 4
+// CHECK-X86-NEXT:    [[TMP1:%.*]] = and i32 [[TMP0]], 1
+// CHECK-X86-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 1
+// CHECK-X86-NEXT:    [[TMP3:%.*]] = and i1 true, [[TMP2]]
+// CHECK-X86-NEXT:    [[CONV:%.*]] = zext i1 [[TMP3]] to i32
+// CHECK-X86-NEXT:    ret i32 [[CONV]]
+//
 int v2() { return __builtin_cpu_supports("x86-64-v2"); }
 
-// 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
+// CHECK-X86-LABEL: define dso_local i32 @v3(
+// CHECK-X86-SAME: ) #[[ATTR0]] {
+// CHECK-X86-NEXT:  entry:
+// CHECK-X86-NEXT:    [[TMP0:%.*]] = load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 2), align 4
+// CHECK-X86-NEXT:    [[TMP1:%.*]] = and i32 [[TMP0]], 2
+// CHECK-X86-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 2
+// CHECK-X86-NEXT:    [[TMP3:%.*]] = and i1 true, [[TMP2]]
+// CHECK-X86-NEXT:    [[CONV:%.*]] = zext i1 [[TMP3]] to i32
+// CHECK-X86-NEXT:    ret i32 [[CONV]]
+//
 int v3() { return __builtin_cpu_supports("x86-64-v3"); }
 
-// 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
+// CHECK-X86-LABEL: define dso_local i32 @v4(
+// CHECK-X86-SAME: ) #[[ATTR0]] {
+// CHECK-X86-NEXT:  entry:
+// CHECK-X86-NEXT:    [[TMP0:%.*]] = load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 2), align 4
+// CHECK-X86-NEXT:    [[TMP1:%.*]] = and i32 [[TMP0]], 4
+// CHECK-X86-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 4
+// CHECK-X86-NEXT:    [[TMP3:%.*]] = and i1 true, [[TMP2]]
+// CHECK-X86-NEXT:    [[CONV:%.*]] = zext i1 [[TMP3]] to i32
+// CHECK-X86-NEXT:    ret i32 [[CONV]]
+//
 int v4() { return __builtin_cpu_supports("x86-64-v4"); }
 #else
+// CHECK-PPC-LABEL: define dso_local signext i32 @test(
+// CHECK-PPC-SAME: i32 noundef signext [[A:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-PPC-NEXT:  entry:
+// CHECK-PPC-NEXT:    [[RETVAL:%.*]] = alloca i32, align 4
+// CHECK-PPC-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-PPC-NEXT:    store i32 [[A]], ptr [[A_ADDR]], align 4
+// CHECK-PPC-NEXT:    [[CPU_SUPPORTS:%.*]] = call i32 @llvm.ppc.fixed.addr.ld(i32 2)
+// CHECK-PPC-NEXT:    [[TMP0:%.*]] = and i32 [[CPU_SUPPORTS]], 8388608
+// CHECK-PPC-NEXT:    [[TMP1:%.*]] = icmp ne i32 [[TMP0]], 0
+// CHECK-PPC-NEXT:    br i1 [[TMP1]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+// CHECK-PPC:       if.then:
+// CHECK-PPC-NEXT:    [[TMP2:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-PPC-NEXT:    store i32 [[TMP2]], ptr [[RETVAL]], align 4
+// CHECK-PPC-NEXT:    br label [[RETURN:%.*]]
+// CHECK-PPC:       if.else:
+// CHECK-PPC-NEXT:    [[CPU_SUPPORTS1:%.*]] = call i32 @llvm.ppc.fixed.addr.ld(i32 1)
+// CHECK-PPC-NEXT:    [[TMP3:%.*]] = and i32 [[CPU_SUPPORTS1]], 67108864
+// CHECK-PPC-NEXT:    [[TMP4:%.*]] = icmp ne i32 [[TMP3]], 0
+// CHECK-PPC-NEXT:    br i1 [[TMP4]], label [[IF_THEN2:%.*]], label [[IF_ELSE3:%.*]]
+// CHECK-PPC:       if.then2:
+// CHECK-PPC-NEXT:    [[TMP5:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-PPC-NEXT:    [[SUB:%.*]] = sub nsw i32 [[TMP5]], 5
+// CHECK-PPC-NEXT:    store i32 [[SUB]], ptr [[RETVAL]], align 4
+// CHECK-PPC-NEXT:    br label [[RETURN]]
+// CHECK-PPC:       if.else3:
+// CHECK-PPC-NEXT:    [[CPU_IS:%.*]] = call i32 @llvm.ppc.fixed.addr.ld(i32 3)
+// CHECK-PPC-NEXT:    [[TMP6:%.*]] = icmp eq i32 [[CPU_IS]], 39
+// CHECK-PPC-NEXT:    br i1 [[TMP6]], label [[IF_THEN4:%.*]], label [[IF_END:%.*]]
+// CHECK-PPC:       if.then4:
+// CHECK-PPC-NEXT:    [[TMP7:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-PPC-NEXT:    [[TMP8:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-PPC-NEXT:    [[ADD:%.*]] = add nsw i32 [[TMP7]], [[TMP8]]
+// CHECK-PPC-NEXT:    store i32 [[ADD]], ptr [[RETVAL]], align 4
+// CHECK-PPC-NEXT:    br label [[RETURN]]
+// CHECK-PPC:       if.end:
+// CHECK-PPC-NEXT:    br label [[IF_END5:%.*]]
+// CHECK-PPC:       if.end5:
+// CHECK-PPC-NEXT:    br label [[IF_END6:%.*]]
+// CHECK-PPC:       if.end6:
+// CHECK-PPC-NEXT:    [[TMP9:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-PPC-NEXT:    [[ADD7:%.*]] = add nsw i32 [[TMP9]], 5
+// CHECK-PPC-NEXT:    store i32 [[ADD7]], ptr [[RETVAL]], align 4
+// CHECK-PPC-NEXT:    br label [[RETURN]]
+// CHECK-PPC:       return:
+// CHECK-PPC-NEXT:    [[TMP10:%.*]] = load i32, ptr [[RETVAL]], align 4
+// CHECK-PPC-NEXT:    ret i32 [[TMP10]]
+//
 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
diff --git a/llvm/include/llvm/IR/IntrinsicsPowerPC.td b/llvm/include/llvm/IR/IntrinsicsPowerPC.td
index d1abc37e072f70..77dc4126c697ae 100644
--- a/llvm/include/llvm/IR/IntrinsicsPowerPC.td
+++ b/llvm/include/llvm/IR/IntrinsicsPowerPC.td
@@ -216,7 +216,10 @@ let TargetPrefix = "ppc" in {  // All intrinsics start with "llvm.ppc.".
             [llvm_float_ty, llvm_float_ty, llvm_float_ty, llvm_vararg_ty],
             [IntrNoMem]>;
   // Load of a value provided by the system library at a fixed address. Used for
-  // accessing things like HWCAP word provided by GLIBC.
+  // accessing things like HWCAP word provided by GLIBC. The immediate argument
+  // is not an address but a value defined in
+  // include/llvm/TargetParser/PPCTargetParser.def. Each of the values provided
+  // by Glibc is a 32-bit word.
   def int_ppc_fixed_addr_ld
       : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty],
                               [IntrInaccessibleMemOnly, ImmArg<ArgIndex<0>>]>;
diff --git a/llvm/include/llvm/TargetParser/PPCTargetParser.def b/llvm/include/llvm/TargetParser/PPCTargetParser.def
index e935e0112956fe..f2c44b46fa6730 100644
--- a/llvm/include/llvm/TargetParser/PPCTargetParser.def
+++ b/llvm/include/llvm/TargetParser/PPCTargetParser.def
@@ -1,8 +1,41 @@
-#ifndef PPC_FEATURE
-#define PPC_FEATURE(NAME, DESC, ENUMNAME, ENUMVAL, HWCAPN)
+//===- PPCTargetParser.def - PPC target parsing defines ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides defines to build up the PPC target parser's logic.
+//
+//===----------------------------------------------------------------------===//
+
+// NOTE: NO INCLUDE GUARD DESIRED!
+
+#ifdef PPC_TGT_PARSER_UNDEF_MACROS
+#undef PPC_LNX_FEATURE
+#undef PPC_LNX_CPU
+#undef PPC_FAWORD_HWCAP
+#undef PPC_FAWORD_HWCAP2
+#undef PPC_FAWORD_CPUID
+#undef PPC_HWCAP_OFFSET_LE32
+#undef PPC_HWCAP_OFFSET_LE64
+#undef PPC_HWCAP_OFFSET_BE32
+#undef PPC_HWCAP_OFFSET_BE64
+#undef PPC_HWCAP2_OFFSET_LE32
+#undef PPC_HWCAP2_OFFSET_LE64
+#undef PPC_HWCAP2_OFFSET_BE32
+#undef PPC_HWCAP2_OFFSET_BE64
+#undef PPC_CPUID_OFFSET_LE32
+#undef PPC_CPUID_OFFSET_LE64
+#undef PPC_CPUID_OFFSET_BE32
+#undef PPC_CPUID_OFFSET_BE64
+#else
+#ifndef PPC_LNX_FEATURE
+#define PPC_LNX_FEATURE(NAME, DESC, ENUMNAME, ENUMVAL, HWCAPN)
 #endif
-#ifndef PPC_CPU
-#define PPC_CPU(NAME, NUM)
+#ifndef PPC_LNX_CPU
+#define PPC_LNX_CPU(NAME, NUM)
 #endif
 #ifndef PPC_FAWORD_HWCAP
 #define PPC_FAWORD_HWCAP 1
@@ -14,67 +47,83 @@
 #define PPC_FAWORD_CPUID 3
 #endif
 
-// PPC_FEATURE(Name, Description, EnumName, BitMask, PPC_FAWORD_WORD)
-PPC_FEATURE("4xxmac","4xx CPU has a Multiply Accumulator",PPCF_4XXMAC,0x02000000,PPC_FAWORD_HWCAP)
-PPC_FEATURE("altivec","CPU has a SIMD/Vector Unit",PPCF_ALTIVEC,0x10000000,PPC_FAWORD_HWCAP)
-PPC_FEATURE("arch_2_05","CPU supports ISA 205 (eg, POWER6)",PPCF_ARCH205,0x00001000,PPC_FAWORD_HWCAP)
-PPC_FEATURE("arch_2_06","CPU supports ISA 206 (eg, POWER7)",PPCF_ARCH206,0x00000100,PPC_FAWORD_HWCAP)
-PPC_FEATURE("arch_2_07","CPU supports ISA 207 (eg, POWER8)",PPCF_ARCH207,0x80000000,PPC_FAWORD_HWCAP2)
-PPC_FEATURE("arch_3_00","CPU supports ISA 30 (eg, POWER9)",PPCF_ARCH30,0x00800000,PPC_FAWORD_HWCAP2)
-PPC_FEATURE("arch_3_1","CPU supports ISA 31 (eg, POWER10)",PPCF_ARCH31,0x00040000,PPC_FAWORD_HWCAP2)
-PPC_FEATURE("archpmu","CPU supports the set of compatible performance monitoring events",PPCF_ARCHPMU,0x00000040,PPC_FAWORD_HWCAP)
-PPC_FEATURE("booke","CPU supports the Embedded ISA category",PPCF_BOOKE,0x00008000,PPC_FAWORD_HWCAP)
-PPC_FEATURE("cellbe","CPU has a CELL broadband engine",PPCF_CELLBE,0x00010000,PPC_FAWORD_HWCAP)
-PPC_FEATURE("darn","CPU supports the darn (deliver a random number) instruction",PPCF_DARN,0x00200000,PPC_FAWORD_HWCAP2)
-PPC_FEATURE("dfp","CPU has a decimal floating point unit",PPCF_DFP,0x00000400,PPC_FAWORD_HWCAP)
-PPC_FEATURE("dscr","CPU supports the data stream control register",PPCF_DSCR,0x20000000,PPC_FAWORD_HWCAP2)
-PPC_FEATURE("ebb","CPU supports event base branching",PPCF_EBB,0x10000000,PPC_FAWORD_HWCAP2)
-PPC_FEATURE("efpdouble","CPU has a SPE double precision floating point unit",PPCF_EFPDOUBLE,0x00200000,PPC_FAWORD_HWCAP)
-PPC_FEATURE("efpsingle","CPU has a SPE single precision floating point unit",PPCF_EFPSINGLE,0x00400000,PPC_FAWORD_HWCAP)
-PPC_FEATURE("fpu","CPU has a floating point unit",PPCF_FPU,0x08000000,PPC_FAWORD_HWCAP)
-PPC_FEATURE("htm","CPU has hardware transaction memory instructions",PPCF_HTM,0x40000000,PPC_FAWORD_HWCAP2)
-PPC_FEATURE("htm-nosc","Kernel aborts hardware transactions when a syscall is made",PPCF_HTM_NOSC,0x01000000,PPC_FAWORD_HWCAP2)
-PPC_FEATURE("htm-no-suspend","CPU supports hardware transaction memory but does not support the tsuspend instruction.",PPCF_HTM_NO_SUSPEND,0x00080000,PPC_FAWORD_HWCAP2)
-PPC_FEATURE("ic_snoop","CPU supports icache snooping capabilities",PPCF_IC_SNOOP,0x00002000,PPC_FAWORD_HWCAP)
-PPC_FEATURE("ieee128","CPU supports 128-bit IEEE binary floating point instructions",PPCF_IEEE128,0x00400000,PPC_FAWORD_HWCAP2)
-PPC_FEATURE("isel","CPU supports the integer select instruction",PPCF_ISEL,0x08000000,PPC_FAWORD_HWCAP2)
-PPC_FEATURE("mma","CPU supports the matrix-multiply assist instructions",PPCF_MMA,0x00020000,PPC_FAWORD_HWCAP2)
-PPC_FEATURE("mmu","CPU has a memory management unit",PPCF_MMU,0x04000000,PPC_FAWORD_HWCAP)
-PPC_FEATURE("notb","CPU does not have a timebase (eg, 601 and 403gx)",PPCF_NOTB,0x00100000,PPC_FAWORD_HWCAP)
-PPC_FEATURE("pa6t","CPU supports the PA Semi 6T CORE ISA",PPCF_PA6T,0x00000800,PPC_FAWORD_HWCAP)
-PPC_FEATURE("power4","CPU supports ISA 200 (eg, POWER4)",PPCF_POWER4,0x00080000,PPC_FAWORD_HWCAP)
-PPC_FEATURE("power5","CPU supports ISA 202 (eg, POWER5)",PPCF_POWER5,0x00040000,PPC_FAWORD_HWCAP)
-PPC_FEATURE("power5+","CPU supports ISA 203 (eg, POWER5+)",PPCF_POWER5P,0x00020000,PPC_FAWORD_HWCAP)
-PPC_FEATURE("power6x","CPU supports ISA 205 (eg, POWER6) extended opcodes mffgpr and mftgpr.",PPCF_POWER6X,0x00000200,PPC_FAWORD_HWCAP)
-PPC_FEATURE("ppc32","CPU supports 32-bit mode execution",PPCF_PPC32,0x80000000,PPC_FAWORD_HWCAP)
-PPC_FEATURE("ppc601","CPU supports the old POWER ISA (eg, 601)",PPCF_PPC601,0x20000000,PPC_FAWORD_HWCAP)
-PPC_FEATURE("ppc64","CPU supports 64-bit mode execution",PPCF_PPC64,0x40000000,PPC_FAWORD_HWCAP)
-PPC_FEATURE("ppcle","CPU supports a little-endian mode that uses address swizzling",PPCF_PPCLE,0x00000001,PPC_FAWORD_HWCAP)
-PPC_FEATURE("scv","Kernel supports system call vectored",PPCF_SCV,0x00100000,PPC_FAWORD_HWCAP2)
-PPC_FEATURE("smt","CPU support simultaneous multi-threading",PPCF_SMT,0x00004000,PPC_FAWORD_HWCAP)
-PPC_FEATURE("spe","CPU has a signal processing extension unit",PPCF_SPE,0x00800000,PPC_FAWORD_HWCAP)
-PPC_FEATURE("tar","CPU supports the target address register",PPCF_TAR,0x04000000,PPC_FAWORD_HWCAP2)
-PPC_FEATURE("true_le","CPU supports true little-endian mode",PPCF_TRUE_LE,0x00000002,PPC_FAWORD_HWCAP)
-PPC_FEATURE("ucache","CPU has unified I/D cache",PPCF_UCACHE,0x01000000,PPC_FAWORD_HWCAP)
-PPC_FEATURE("vcrypto","CPU supports the vector cryptography instructions",PPCF_VCRYPTO,0x02000000,PPC_FAWORD_HWCAP2)
-PPC_FEATURE("vsx","CPU supports the vector-scalar extension",PPCF_VSX,0x00000080,PPC_FAWORD_HWCAP)
+// PPC_LNX_FEATURE(Name, Description, EnumName, BitMask, PPC_FAWORD_WORD)
+PPC_LNX_FEATURE("4xxmac","4xx CPU has a Multiply Accumulator",PPCF_4XXMAC,0x02000000,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("altivec","CPU has a SIMD/Vector Unit",PPCF_ALTIVEC,0x10000000,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("arch_2_05","CPU supports ISA 205 (eg, POWER6)",PPCF_ARCH205,0x00001000,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("arch_2_06","CPU supports ISA 206 (eg, POWER7)",PPCF_ARCH206,0x00000100,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("arch_2_07","CPU supports ISA 207 (eg, POWER8)",PPCF_ARCH207,0x80000000,PPC_FAWORD_HWCAP2)
+PPC_LNX_FEATURE("arch_3_00","CPU supports ISA 30 (eg, POWER9)",PPCF_ARCH30,0x00800000,PPC_FAWORD_HWCAP2)
+PPC_LNX_FEATURE("arch_3_1","CPU supports ISA 31 (eg, POWER10)",PPCF_ARCH31,0x00040000,PPC_FAWORD_HWCAP2)
+PPC_LNX_FEATURE("archpmu","CPU supports the set of compatible performance monitoring events",PPCF_ARCHPMU,0x00000040,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("booke","CPU supports the Embedded ISA category",PPCF_BOOKE,0x00008000,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("cellbe","CPU has a CELL broadband engine",PPCF_CELLBE,0x00010000,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("darn","CPU supports the darn (deliver a random number) instruction",PPCF_DARN,0x00200000,PPC_FAWORD_HWCAP2)
+PPC_LNX_FEATURE("dfp","CPU has a decimal floating point unit",PPCF_DFP,0x00000400,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("dscr","CPU supports the data stream control register",PPCF_DSCR,0x20000000,PPC_FAWORD_HWCAP2)
+PPC_LNX_FEATURE("ebb","CPU supports event base branching",PPCF_EBB,0x10000000,PPC_FAWORD_HWCAP2)
+PPC_LNX_FEATURE("efpdouble","CPU has a SPE double precision floating point unit",PPCF_EFPDOUBLE,0x00200000,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("efpsingle","CPU has a SPE single precision floating point unit",PPCF_EFPSINGLE,0x00400000,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("fpu","CPU has a floating point unit",PPCF_FPU,0x08000000,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("htm","CPU has hardware transaction memory instructions",PPCF_HTM,0x40000000,PPC_FAWORD_HWCAP2)
+PPC_LNX_FEATURE("htm-nosc","Kernel aborts hardware transactions when a syscall is made",PPCF_HTM_NOSC,0x01000000,PPC_FAWORD_HWCAP2)
+PPC_LNX_FEATURE("htm-no-suspend","CPU supports hardware transaction memory but does not support the tsuspend instruction.",PPCF_HTM_NO_SUSPEND,0x00080000,PPC_FAWORD_HWCAP2)
+PPC_LNX_FEATURE("ic_snoop","CPU supports icache snooping capabilities",PPCF_IC_SNOOP,0x00002000,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("ieee128","CPU supports 128-bit IEEE binary floating point instructions",PPCF_IEEE128,0x00400000,PPC_FAWORD_HWCAP2)
+PPC_LNX_FEATURE("isel","CPU supports the integer select instruction",PPCF_ISEL,0x08000000,PPC_FAWORD_HWCAP2)
+PPC_LNX_FEATURE("mma","CPU supports the matrix-multiply assist instructions",PPCF_MMA,0x00020000,PPC_FAWORD_HWCAP2)
+PPC_LNX_FEATURE("mmu","CPU has a memory management unit",PPCF_MMU,0x04000000,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("notb","CPU does not have a timebase (eg, 601 and 403gx)",PPCF_NOTB,0x00100000,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("pa6t","CPU supports the PA Semi 6T CORE ISA",PPCF_PA6T,0x00000800,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("power4","CPU supports ISA 200 (eg, POWER4)",PPCF_POWER4,0x00080000,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("power5","CPU supports ISA 202 (eg, POWER5)",PPCF_POWER5,0x00040000,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("power5+","CPU supports ISA 203 (eg, POWER5+)",PPCF_POWER5P,0x00020000,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("power6x","CPU supports ISA 205 (eg, POWER6) extended opcodes mffgpr and mftgpr.",PPCF_POWER6X,0x00000200,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("ppc32","CPU supports 32-bit mode execution",PPCF_PPC32,0x80000000,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("ppc601","CPU supports the old POWER ISA (eg, 601)",PPCF_PPC601,0x20000000,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("ppc64","CPU supports 64-bit mode execution",PPCF_PPC64,0x40000000,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("ppcle","CPU supports a little-endian mode that uses address swizzling",PPCF_PPCLE,0x00000001,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("scv","Kernel supports system call vectored",PPCF_SCV,0x00100000,PPC_FAWORD_HWCAP2)
+PPC_LNX_FEATURE("smt","CPU support simultaneous multi-threading",PPCF_SMT,0x00004000,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("spe","CPU has a signal processing extension unit",PPCF_SPE,0x00800000,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("tar","CPU supports the target address register",PPCF_TAR,0x04000000,PPC_FAWORD_HWCAP2)
+PPC_LNX_FEATURE("true_le","CPU supports true little-endian mode",PPCF_TRUE_LE,0x00000002,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("ucache","CPU has unified I/D cache",PPCF_UCACHE,0x01000000,PPC_FAWORD_HWCAP)
+PPC_LNX_FEATURE("vcrypto","CPU supports the vector cryptography instructions",PPCF_VCRYPTO,0x02000000,PPC_FAWORD_HWCAP2)
+PPC_LNX_FEATURE("vsx","CPU supports the vector-scalar extension",PPCF_VSX,0x00000080,PPC_FAWORD_HWCAP)
 
-// PPC_CPU(Name, NumericID)
-PPC_CPU("power4",32)
-PPC_CPU("ppc970",33)
-PPC_CPU("power5",34)
-PPC_CPU("power5+",35)
-PPC_CPU("power6",36)
-PPC_CPU("ppc-cell-be",37)
-PPC_CPU("power6x",38)
-PPC_CPU("power7",39)
-PPC_CPU("ppca2",40)
-PPC_CPU("ppc405",41)
-PPC_CPU("ppc440",42)
-PPC_CPU("ppc464",43)
-PPC_CPU("ppc476",44)
-PPC_CPU("power8",45)
-PPC_CPU("power9",46)
-PPC_CPU("power10",47)
-#undef PPC_FEATURE
-#undef PPC_CPU
+// PPC_LNX_CPU(Name, NumericID)
+PPC_LNX_CPU("power4",32)
+PPC_LNX_CPU("ppc970",33)
+PPC_LNX_CPU("power5",34)
+PPC_LNX_CPU("power5+",35)
+PPC_LNX_CPU("power6",36)
+PPC_LNX_CPU("ppc-cell-be",37)
+PPC_LNX_CPU("power6x",38)
+PPC_LNX_CPU("power7",39)
+PPC_LNX_CPU("ppca2",40)
+PPC_LNX_CPU("ppc405",41)
+PPC_LNX_CPU("ppc440",42)
+PPC_LNX_CPU("ppc464",43)
+PPC_LNX_CPU("ppc476",44)
+PPC_LNX_CPU("power8",45)
+PPC_LNX_CPU("power9",46)
+PPC_LNX_CPU("power10",47)
+#ifdef PPC_LNX_DEFINE_OFFSETS
+#  define PPC_HWCAP_OFFSET_LE32 -0x703C
+#  define PPC_HWCAP_OFFSET_LE64 -0x7064
+#  define PPC_HWCAP_OFFSET_BE32 -0x7040
+#  define PPC_HWCAP_OFFSET_BE64 -0x7068
+#  define PPC_HWCAP2_OFFSET_LE32 -0x7040
+#  define PPC_HWCAP2_OFFSET_LE64 -0x7068
+#  define PPC_HWCAP2_OFFSET_BE32 -0x703C
+#  define PPC_HWCAP2_OFFSET_BE64 -0x7064
+#  define PPC_CPUID_OFFSET_LE32 -0x7034
+#  define PPC_CPUID_OFFSET_LE64 -0x705C
+#  define PPC_CPUID_OFFSET_BE32 -0x7034
+#  define PPC_CPUID_OFFSET_BE64 -0x705C
+#endif
+#undef PPC_LNX_DEFINE_OFFSETS
+#undef PPC_LNX_FEATURE
+#undef PPC_LNX_CPU
+#endif // !PPC_TGT_PARSER_UNDEF_MACROS
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 46afb882d80c5d..528267cb013291 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -1821,6 +1821,10 @@ void PPCLinuxAsmPrinter::emitEndOfAsmFile(Module &M) {
   PPCTargetStreamer *TS =
       static_cast<PPCTargetStreamer *>(OutStreamer->getTargetStreamer());
 
+  // If we are using any values provided by Glibc at fixed addresses,
+  // we need to ensure that the Glibc used at link time actually provides
+  // those values. All versions of Glibc that do will define the symbol
+  // named "__parse_hwcap_and_convert_at_platform".
   if (static_cast<const PPCTargetMachine &>(TM).hasGlibcHWCAPAccess())
     OutStreamer->emitSymbolValue(
         GetExternalSymbolSymbol("__parse_hwcap_and_convert_at_platform"),
diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
index 34d41d05089586..38eeca0fbf821a 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
+++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
@@ -3101,24 +3101,34 @@ bool PPCInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
     return true;
   }
   case PPC::PPCLdFixedAddr: {
-    assert(Subtarget.isTargetLinux() &&
-           "Only Linux target is expected to contain PPCLdFixedAddr");
+    assert(Subtarget.getTargetTriple().isOSGlibc() &&
+           "Only targets with Glibc expected to contain PPCLdFixedAddr");
     int64_t Offset = 0;
     const unsigned Reg = Subtarget.isPPC64() ? PPC::X13 : PPC::R2;
     MI.setDesc(get(PPC::LWZ));
     uint64_t FAType = MI.getOperand(1).getImm();
-#undef PPC_FEATURE
-#undef PPC_CPU
+#undef PPC_LNX_FEATURE
+#undef PPC_LNX_CPU
+#define PPC_LNX_DEFINE_OFFSETS
 #include "llvm/TargetParser/PPCTargetParser.def"
-    // The HWCAP and HWCAP2 word offsets are reversed on big endian Linux.
-    if ((FAType == PPC_FAWORD_HWCAP && Subtarget.isLittleEndian()) ||
-        (FAType == PPC_FAWORD_HWCAP2 && !Subtarget.isLittleEndian()))
-      Offset = Subtarget.isPPC64() ? -0x7064 : -0x703C;
-    else if ((FAType == PPC_FAWORD_HWCAP2 && Subtarget.isLittleEndian()) ||
-             (FAType == PPC_FAWORD_HWCAP && !Subtarget.isLittleEndian()))
-      Offset = Subtarget.isPPC64() ? -0x7068 : -0x7040;
-    else if (FAType == PPC_FAWORD_CPUID)
-      Offset = Subtarget.isPPC64() ? -0x705C : -0x7034;
+    bool IsLE = Subtarget.isLittleEndian();
+    bool Is64 = Subtarget.isPPC64();
+    if (FAType == PPC_FAWORD_HWCAP) {
+      if (IsLE)
+        Offset = Is64 ? PPC_HWCAP_OFFSET_LE64 : PPC_HWCAP_OFFSET_LE32;
+      else
+        Offset = Is64 ? PPC_HWCAP_OFFSET_BE64 : PPC_HWCAP_OFFSET_BE32;
+    } else if (FAType == PPC_FAWORD_HWCAP2) {
+      if (IsLE)
+        Offset = Is64 ? PPC_HWCAP2_OFFSET_LE64 : PPC_HWCAP2_OFFSET_LE32;
+      else
+        Offset = Is64 ? PPC_HWCAP2_OFFSET_BE64 : PPC_HWCAP2_OFFSET_BE32;
+    } else if (FAType == PPC_FAWORD_CPUID) {
+      if (IsLE)
+        Offset = Is64 ? PPC_CPUID_OFFSET_LE64 : PPC_CPUID_OFFSET_LE32;
+      else
+        Offset = Is64 ? PPC_CPUID_OFFSET_BE64 : PPC_CPUID_OFFSET_BE32;
+    }
     assert(Offset && "Do not know the offset for this fixed addr load");
     MI.removeOperand(1);
     Subtarget.getTargetMachine().setGlibcHWCAPAccess();
@@ -3126,9 +3136,9 @@ bool PPCInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
         .addImm(Offset)
         .addReg(Reg);
     return true;
-#undef PPC_FAWORD_HWCAP
-#undef PPC_FAWORD_HWCAP2
-#undef PPC_FAWORD_CPUID
+#define PPC_TGT_PARSER_UNDEF_MACROS
+#include "llvm/TargetParser/PPCTargetParser.def"
+#undef PPC_TGT_PARSER_UNDEF_MACROS
   }
   case PPC::DFLOADf32:
   case PPC::DFLOADf64:
diff --git a/llvm/test/CodeGen/PowerPC/cpu-supports.ll b/llvm/test/CodeGen/PowerPC/cpu-supports.ll
index 912d67e5c555e6..82ceb15084f07b 100644
--- a/llvm/test/CodeGen/PowerPC/cpu-supports.ll
+++ b/llvm/test/CodeGen/PowerPC/cpu-supports.ll
@@ -31,6 +31,7 @@ define dso_local signext i32 @test(i32 noundef signext %a) local_unnamed_addr #0
 ; BE64-NEXT:    addi r3, r3, -5
 ; BE64-NEXT:    extsw r3, r3
 ; BE64-NEXT:    blr
+; BE64:       .quad   __parse_hwcap_and_convert_at_platform
 ;
 ; BE32-LABEL: test:
 ; BE32:       # %bb.0: # %entry
@@ -51,6 +52,7 @@ define dso_local signext i32 @test(i32 noundef signext %a) local_unnamed_addr #0
 ; BE32-NEXT:  .LBB0_3: # %if.then2
 ; BE32-NEXT:    addi r3, r3, -5
 ; BE32-NEXT:    blr
+; BE32:       .long   __parse_hwcap_and_convert_at_platform
 ;
 ; LE-LABEL: test:
 ; LE:       # %bb.0: # %entry
@@ -74,6 +76,7 @@ define dso_local signext i32 @test(i32 noundef signext %a) local_unnamed_addr #0
 ; LE-NEXT:    addi r3, r3, -5
 ; LE-NEXT:    extsw r3, r3
 ; LE-NEXT:    blr
+; LE:       .quad   __parse_hwcap_and_convert_at_platform
 entry:
   %cpu_supports = tail call i32 @llvm.ppc.fixed.addr.ld(i32 2)
   %0 = and i32 %cpu_supports, 8388608

>From eef7dd67ca7f0e2f87b7fc4483b8c6198364a29c Mon Sep 17 00:00:00 2001
From: Nemanja Ivanovic <nemanja at synopsys.com>
Date: Thu, 11 Jan 2024 21:56:12 +0100
Subject: [PATCH 4/5] Add the Auxiliary target checks back in for Sema.

---
 clang/lib/Sema/SemaChecking.cpp | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 9edf568ec95f05..299dc2ed7afc37 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2147,16 +2147,24 @@ static bool checkFPMathBuiltinElementType(Sema &S, SourceLocation Loc,
 /// This checks that the target supports the builtin and that the string
 /// argument is constant and valid.
 static bool SemaBuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall,
-                           unsigned BuiltinID) {
+                           const TargetInfo *AuxTI, unsigned BuiltinID) {
   assert((BuiltinID == Builtin::BI__builtin_cpu_supports ||
           BuiltinID == Builtin::BI__builtin_cpu_is) &&
          "Expecting __builtin_cpu_...");
 
   bool IsCPUSupports = BuiltinID == Builtin::BI__builtin_cpu_supports;
-  if (IsCPUSupports && !TI.supportsCpuSupports())
+  const TargetInfo *TheTI = &TI;
+  auto SupportsBI = [=](const TargetInfo *TInfo) {
+    return TInfo && ((IsCPUSupports && TInfo->supportsCpuSupports()) ||
+                     (!IsCPUSupports && TInfo->supportsCpuIs()));
+  };
+  if (!SupportsBI(&TI) && SupportsBI(AuxTI))
+    TheTI = AuxTI;
+
+  if (IsCPUSupports && !TheTI->supportsCpuSupports())
     return S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
            << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
-  if (!IsCPUSupports && !TI.supportsCpuIs())
+  if (!IsCPUSupports && !TheTI->supportsCpuIs())
     return S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
            << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
 
@@ -2168,10 +2176,10 @@ static bool SemaBuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall,
 
   // Check the contents of the string.
   StringRef Feature = cast<StringLiteral>(Arg)->getString();
-  if (IsCPUSupports && !TI.validateCpuSupports(Feature))
+  if (IsCPUSupports && !TheTI->validateCpuSupports(Feature))
     return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_supports)
            << Arg->getSourceRange();
-  if (!IsCPUSupports && !TI.validateCpuIs(Feature))
+  if (!IsCPUSupports && !TheTI->validateCpuIs(Feature))
     return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_is)
            << Arg->getSourceRange();
   return false;
@@ -2207,7 +2215,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
   switch (BuiltinID) {
   case Builtin::BI__builtin_cpu_supports:
   case Builtin::BI__builtin_cpu_is:
-    if (SemaBuiltinCpu(*this, Context.getTargetInfo(), TheCall, BuiltinID))
+    if (SemaBuiltinCpu(*this, Context.getTargetInfo(), TheCall,
+                       Context.getAuxTargetInfo(), BuiltinID))
       return ExprError();
     break;
   case Builtin::BI__builtin_cpu_init:

>From b1216646d375d840bbc81bff42558e9935ee3bb1 Mon Sep 17 00:00:00 2001
From: Nemanja Ivanovic <nemanja.i.ibm at gmail.com>
Date: Fri, 26 Jan 2024 07:42:02 +0100
Subject: [PATCH 5/5] Address last round of reviews and rebase

The way we define target-independent builtins has changed which
required a rebase. Also cleaned up some comments and improved
asserts as suggested in the review.
---
 clang/lib/Basic/Targets/PPC.h             | 2 +-
 clang/lib/CodeGen/CGBuiltin.cpp           | 2 ++
 llvm/include/llvm/IR/IntrinsicsPowerPC.td | 4 ++--
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h
index f700b625b79030..a91bdede53e40d 100644
--- a/clang/lib/Basic/Targets/PPC.h
+++ b/clang/lib/Basic/Targets/PPC.h
@@ -361,7 +361,7 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
   }
 
   // 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.
+  // 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;
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index e5b15a74da392b..f3ab5ad7b08ec8 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -16552,6 +16552,7 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
 #define PPC_LNX_CPU(Name, NumericID) .Case(Name, NumericID)
 #include "llvm/TargetParser/PPCTargetParser.def"
                             .Default(-1U);
+    assert(NumCPUID < -1U && "Invalid CPU name. Missed by SemaChecking?");
     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");
@@ -16569,6 +16570,7 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
   .Case(Name, {FA_WORD, Bitmask})
 #include "llvm/TargetParser/PPCTargetParser.def"
             .Default({0, 0});
+    assert(BitMask && "Invalid target feature string. Missed by SemaChecking?");
     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");
diff --git a/llvm/include/llvm/IR/IntrinsicsPowerPC.td b/llvm/include/llvm/IR/IntrinsicsPowerPC.td
index 77dc4126c697ae..bfc2b17043bc79 100644
--- a/llvm/include/llvm/IR/IntrinsicsPowerPC.td
+++ b/llvm/include/llvm/IR/IntrinsicsPowerPC.td
@@ -216,8 +216,8 @@ let TargetPrefix = "ppc" in {  // All intrinsics start with "llvm.ppc.".
             [llvm_float_ty, llvm_float_ty, llvm_float_ty, llvm_vararg_ty],
             [IntrNoMem]>;
   // Load of a value provided by the system library at a fixed address. Used for
-  // accessing things like HWCAP word provided by GLIBC. The immediate argument
-  // is not an address but a value defined in
+  // accessing things like the HWCAP word provided by Glibc. The immediate
+  // argument is not an address but a value defined in
   // include/llvm/TargetParser/PPCTargetParser.def. Each of the values provided
   // by Glibc is a 32-bit word.
   def int_ppc_fixed_addr_ld



More information about the cfe-commits mailing list