[clang] [llvm] [WIP][RISCV] Support __builtin_cpu_init and __builtin_cpu_supports (PR #99700)

Philip Reames via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 22 07:29:45 PDT 2024


https://github.com/preames updated https://github.com/llvm/llvm-project/pull/99700

>From ddf2c58a864576586b89cc611e2bea15b8cf18ba Mon Sep 17 00:00:00 2001
From: Philip Reames <preames at rivosinc.com>
Date: Fri, 19 Jul 2024 10:46:19 -0700
Subject: [PATCH 1/3] [WIP][RISCV] Support __builtin_cpu_init and
 __builtin_cpu_supports

This implements the __builtin_cpu_init and __builtin_cpu_supports
builtin routines based on the compiler runtime changes in https://github.com/llvm/llvm-project/pull/85790.

This is inspired by https://github.com/llvm/llvm-project/pull/85786.
Major changes are a) a restriction in scope to only the builtins
(which have a much narrower user interface), and the avoidance of
false generality.  This change deliberately only handles group 0
extensions (which happen to be all defined ones today), and avoids
the tblgen changes from that review.

This is still a WIP.  It is posted for initial feedback on whether
this makes sense to try to get into 19.x release. Major items left
undone:

* Updating clang tests to exercise this logic.
* Actually running it at all.  I did not build compiler-rt, and thus
  all my checking was of generated asm/IR.
* Investigate claims from gcc docs that __builtin_cpu_init is called
  early in process lifetime with high priority constructor.  I did
  not find this with some quick searching.
---
 clang/lib/Basic/Targets/RISCV.cpp             |  6 ++
 clang/lib/Basic/Targets/RISCV.h               |  4 ++
 clang/lib/CodeGen/CGBuiltin.cpp               | 55 +++++++++++++++++
 clang/lib/CodeGen/CodeGenFunction.h           |  3 +
 llvm/include/llvm/TargetParser/RISCVISAInfo.h |  4 ++
 llvm/lib/TargetParser/RISCVISAInfo.cpp        | 61 +++++++++++++++++++
 6 files changed, 133 insertions(+)

diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp
index 9159162f01d1b..41d836330b38c 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -479,3 +479,9 @@ RISCVTargetInfo::checkCallingConvention(CallingConv CC) const {
     return CCCR_OK;
   }
 }
+
+bool RISCVTargetInfo::validateCpuSupports(StringRef Feature) const {
+  // Only allow extensions we have a known bit position for in the
+  // __riscv_feature_bits structure.
+  return -1 != llvm::RISCVISAInfo::getRISCVFeaturesBitPosition(Feature);
+}
diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h
index d5df6344bedc0..626274b8fc437 100644
--- a/clang/lib/Basic/Targets/RISCV.h
+++ b/clang/lib/Basic/Targets/RISCV.h
@@ -126,6 +126,10 @@ class RISCVTargetInfo : public TargetInfo {
   std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
     return std::make_pair(32, 32);
   }
+
+  bool supportsCpuSupports() const override { return getTriple().isOSLinux(); }
+  bool supportsCpuInit() const override { return getTriple().isOSLinux(); }
+  bool validateCpuSupports(StringRef Feature) const override;
 };
 class LLVM_LIBRARY_VISIBILITY RISCV32TargetInfo : public RISCVTargetInfo {
 public:
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 2ad62d6ee0bb2..71c947776adf2 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -62,6 +62,8 @@
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/ScopedPrinter.h"
 #include "llvm/TargetParser/AArch64TargetParser.h"
+#include "llvm/TargetParser/RISCVISAInfo.h"
+#include "llvm/TargetParser/RISCVTargetParser.h"
 #include "llvm/TargetParser/X86TargetParser.h"
 #include <optional>
 #include <sstream>
@@ -14215,6 +14217,16 @@ Value *CodeGenFunction::EmitAArch64CpuInit() {
   return Builder.CreateCall(Func);
 }
 
+Value *CodeGenFunction::EmitRISCVCpuInit() {
+  llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
+  llvm::FunctionCallee Func =
+      CGM.CreateRuntimeFunction(FTy, "__init_riscv_feature_bits");
+  auto *CalleeGV = cast<llvm::GlobalValue>(Func.getCallee());
+  CalleeGV->setDSOLocal(true);
+  CalleeGV->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
+  return Builder.CreateCall(Func);
+}
+
 Value *CodeGenFunction::EmitX86CpuInit() {
   llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy,
                                                     /*Variadic*/ false);
@@ -14267,6 +14279,43 @@ CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) {
   return Result;
 }
 
+Value *CodeGenFunction::EmitRISCVCpuSupports(const CallExpr *E) {
+
+  const Expr *FeatureExpr = E->getArg(0)->IgnoreParenCasts();
+  StringRef FeatureStr = cast<StringLiteral>(FeatureExpr)->getString();
+  if (!getContext().getTargetInfo().validateCpuSupports(FeatureStr))
+    return Builder.getFalse();
+
+  // Note: We are making an unchecked assumption that the size of the
+  // feature array is >= 1.  This holds for any version of compiler-rt
+  // which defines this interface.
+  llvm::ArrayType *ArrayOfInt64Ty =
+      llvm::ArrayType::get(Int64Ty, 1);
+  llvm::Type *StructTy = llvm::StructType::get(Int32Ty, ArrayOfInt64Ty);
+  llvm::Constant *RISCVFeaturesBits =
+      CGM.CreateRuntimeVariable(StructTy, "__riscv_feature_bits");
+  auto *GV = cast<llvm::GlobalValue>(RISCVFeaturesBits);
+  GV->setDSOLocal(true);
+
+  auto LoadFeatureBit = [&](unsigned Index) {
+    // Create GEP then load.
+    Value *IndexVal = llvm::ConstantInt::get(Int32Ty, Index);
+    llvm::Value *GEPIndices[] = {Builder.getInt32(0), Builder.getInt32(1),
+                                 IndexVal};
+    Value *Ptr =
+        Builder.CreateInBoundsGEP(StructTy, RISCVFeaturesBits, GEPIndices);
+    Value *FeaturesBit =
+        Builder.CreateAlignedLoad(Int64Ty, Ptr, CharUnits::fromQuantity(8));
+    return FeaturesBit;
+  };
+
+  int BitPos = RISCVISAInfo::getRISCVFeaturesBitPosition(FeatureStr);
+  assert(BitPos != -1 && "validation should have rejected this feature");
+  Value *MaskV = Builder.getInt64(1ULL << BitPos);
+  Value *Bitset = Builder.CreateAnd(LoadFeatureBit(0), MaskV);
+  return Builder.CreateICmpEQ(Bitset, MaskV);
+}
+
 Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
                                            const CallExpr *E) {
   if (BuiltinID == Builtin::BI__builtin_cpu_is)
@@ -21728,6 +21777,12 @@ Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID,
 Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
                                              const CallExpr *E,
                                              ReturnValueSlot ReturnValue) {
+
+  if (BuiltinID == Builtin::BI__builtin_cpu_supports)
+    return EmitRISCVCpuSupports(E);
+  if (BuiltinID == Builtin::BI__builtin_cpu_init)
+    return EmitRISCVCpuInit();
+
   SmallVector<Value *, 4> Ops;
   llvm::Type *ResultType = ConvertType(E->getType());
 
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index d83e38cab8e2d..1ee45a1f1f99d 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4695,6 +4695,9 @@ class CodeGenFunction : public CodeGenTypeCache {
   llvm::Value *EmitRISCVBuiltinExpr(unsigned BuiltinID, const CallExpr *E,
                                     ReturnValueSlot ReturnValue);
 
+  llvm::Value *EmitRISCVCpuSupports(const CallExpr *E);
+  llvm::Value *EmitRISCVCpuInit();
+
   void AddAMDGPUFenceAddressSpaceMMRA(llvm::Instruction *Inst,
                                       const CallExpr *E);
   void ProcessOrderScopeAMDGCN(llvm::Value *Order, llvm::Value *Scope,
diff --git a/llvm/include/llvm/TargetParser/RISCVISAInfo.h b/llvm/include/llvm/TargetParser/RISCVISAInfo.h
index d7a08013fa6ac..d71ff174bf0d2 100644
--- a/llvm/include/llvm/TargetParser/RISCVISAInfo.h
+++ b/llvm/include/llvm/TargetParser/RISCVISAInfo.h
@@ -80,6 +80,10 @@ class RISCVISAInfo {
                                      std::set<StringRef> &EnabledFeatureNames,
                                      StringMap<StringRef> &DescMap);
 
+  /// Return the bit position (in group 0) of __riscv_feature_bits.  Returns
+  /// -1 if not supported.
+  static int getRISCVFeaturesBitPosition(StringRef Ext);
+
 private:
   RISCVISAInfo(unsigned XLen) : XLen(XLen) {}
 
diff --git a/llvm/lib/TargetParser/RISCVISAInfo.cpp b/llvm/lib/TargetParser/RISCVISAInfo.cpp
index e6ddbb4dc28d5..3ff1b325793e6 100644
--- a/llvm/lib/TargetParser/RISCVISAInfo.cpp
+++ b/llvm/lib/TargetParser/RISCVISAInfo.cpp
@@ -1020,3 +1020,64 @@ std::string RISCVISAInfo::getTargetFeatureForExtension(StringRef Ext) {
   return isExperimentalExtension(Name) ? "experimental-" + Name.str()
                                        : Name.str();
 }
+
+struct RISCVExtBit {
+  const StringRef ext;
+  uint64_t bitpos;
+};
+
+/// Maps extensions with assigned bit positions within group 0 of
+/// __riscv_features_bits to their respective bit position.  At the
+/// moment all extensions are within group 0.
+static RISCVExtBit RISCVGroup0BitPositions[] = {
+  {"a", 0},
+  {"c", 2},
+  {"d", 3},
+  {"f", 5},
+  {"i", 8},
+  {"m", 12},
+  {"v", 21},
+  {"zacas", 26},
+  {"zba", 27},
+  {"zbb", 28},
+  {"zbc", 29},
+  {"zbkb", 30},
+  {"zbkc", 31},
+  {"zbkx", 32},
+  {"zbs", 33},
+  {"zfa", 34},
+  {"zfh", 35},
+  {"zfhmin", 36},
+  {"zicboz", 37},
+  {"zicond", 38},
+  {"zihintntl", 39},
+  {"zihintpause", 40},
+  {"zknd", 41},
+  {"zkne", 42},
+  {"zknh", 43},
+  {"zksed", 44},
+  {"zksh", 45},
+  {"zkt", 46},
+  {"ztso", 47},
+  {"zvbb", 48},
+  {"zvbc", 49},
+  {"zvfh", 50},
+  {"zvfhmin", 51},
+  {"zvkb", 52},
+  {"zvkg", 53},
+  {"zvkned", 54},
+  {"zvknha", 55},
+  {"zvknhb", 56},
+  {"zvksed", 57},
+  {"zvksh", 58},
+  {"zvkt", 59}
+};
+int RISCVISAInfo::getRISCVFeaturesBitPosition(StringRef Ext) {
+  // Note that this code currently accepts mixed case extension names, but
+  // does not handle extension versions at all.  That's probably fine because
+  // there's only one extension version in the __riscv_feature_bits vector.
+  for (auto E : RISCVGroup0BitPositions)
+    if (E.ext.equals_insensitive(Ext))
+      return E.bitpos;
+  return -1;
+}

>From 1be1e5e3fb4b191de78a3d9176036b066476129c Mon Sep 17 00:00:00 2001
From: Philip Reames <preames at rivosinc.com>
Date: Fri, 19 Jul 2024 13:32:29 -0700
Subject: [PATCH 2/3] Clang format fix

---
 clang/lib/CodeGen/CGBuiltin.cpp        |  3 +-
 llvm/lib/TargetParser/RISCVISAInfo.cpp | 63 +++++++++-----------------
 2 files changed, 22 insertions(+), 44 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 71c947776adf2..25dbe221325cc 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -14289,8 +14289,7 @@ Value *CodeGenFunction::EmitRISCVCpuSupports(const CallExpr *E) {
   // Note: We are making an unchecked assumption that the size of the
   // feature array is >= 1.  This holds for any version of compiler-rt
   // which defines this interface.
-  llvm::ArrayType *ArrayOfInt64Ty =
-      llvm::ArrayType::get(Int64Ty, 1);
+  llvm::ArrayType *ArrayOfInt64Ty = llvm::ArrayType::get(Int64Ty, 1);
   llvm::Type *StructTy = llvm::StructType::get(Int32Ty, ArrayOfInt64Ty);
   llvm::Constant *RISCVFeaturesBits =
       CGM.CreateRuntimeVariable(StructTy, "__riscv_feature_bits");
diff --git a/llvm/lib/TargetParser/RISCVISAInfo.cpp b/llvm/lib/TargetParser/RISCVISAInfo.cpp
index 3ff1b325793e6..7a5b10a877ebe 100644
--- a/llvm/lib/TargetParser/RISCVISAInfo.cpp
+++ b/llvm/lib/TargetParser/RISCVISAInfo.cpp
@@ -1030,48 +1030,27 @@ struct RISCVExtBit {
 /// __riscv_features_bits to their respective bit position.  At the
 /// moment all extensions are within group 0.
 static RISCVExtBit RISCVGroup0BitPositions[] = {
-  {"a", 0},
-  {"c", 2},
-  {"d", 3},
-  {"f", 5},
-  {"i", 8},
-  {"m", 12},
-  {"v", 21},
-  {"zacas", 26},
-  {"zba", 27},
-  {"zbb", 28},
-  {"zbc", 29},
-  {"zbkb", 30},
-  {"zbkc", 31},
-  {"zbkx", 32},
-  {"zbs", 33},
-  {"zfa", 34},
-  {"zfh", 35},
-  {"zfhmin", 36},
-  {"zicboz", 37},
-  {"zicond", 38},
-  {"zihintntl", 39},
-  {"zihintpause", 40},
-  {"zknd", 41},
-  {"zkne", 42},
-  {"zknh", 43},
-  {"zksed", 44},
-  {"zksh", 45},
-  {"zkt", 46},
-  {"ztso", 47},
-  {"zvbb", 48},
-  {"zvbc", 49},
-  {"zvfh", 50},
-  {"zvfhmin", 51},
-  {"zvkb", 52},
-  {"zvkg", 53},
-  {"zvkned", 54},
-  {"zvknha", 55},
-  {"zvknhb", 56},
-  {"zvksed", 57},
-  {"zvksh", 58},
-  {"zvkt", 59}
-};
+    {"a", 0},          {"c", 2},
+    {"d", 3},          {"f", 5},
+    {"i", 8},          {"m", 12},
+    {"v", 21},         {"zacas", 26},
+    {"zba", 27},       {"zbb", 28},
+    {"zbc", 29},       {"zbkb", 30},
+    {"zbkc", 31},      {"zbkx", 32},
+    {"zbs", 33},       {"zfa", 34},
+    {"zfh", 35},       {"zfhmin", 36},
+    {"zicboz", 37},    {"zicond", 38},
+    {"zihintntl", 39}, {"zihintpause", 40},
+    {"zknd", 41},      {"zkne", 42},
+    {"zknh", 43},      {"zksed", 44},
+    {"zksh", 45},      {"zkt", 46},
+    {"ztso", 47},      {"zvbb", 48},
+    {"zvbc", 49},      {"zvfh", 50},
+    {"zvfhmin", 51},   {"zvkb", 52},
+    {"zvkg", 53},      {"zvkned", 54},
+    {"zvknha", 55},    {"zvknhb", 56},
+    {"zvksed", 57},    {"zvksh", 58},
+    {"zvkt", 59}};
 int RISCVISAInfo::getRISCVFeaturesBitPosition(StringRef Ext) {
   // Note that this code currently accepts mixed case extension names, but
   // does not handle extension versions at all.  That's probably fine because

>From 2f261105201bae7166eefd3fc67e3e864cd7df31 Mon Sep 17 00:00:00 2001
From: Philip Reames <preames at rivosinc.com>
Date: Mon, 22 Jul 2024 07:29:31 -0700
Subject: [PATCH 3/3] Address review comments

---
 clang/lib/CodeGen/CGBuiltin.cpp        | 1 -
 llvm/lib/TargetParser/RISCVISAInfo.cpp | 2 +-
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 25dbe221325cc..96a0887284c21 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -63,7 +63,6 @@
 #include "llvm/Support/ScopedPrinter.h"
 #include "llvm/TargetParser/AArch64TargetParser.h"
 #include "llvm/TargetParser/RISCVISAInfo.h"
-#include "llvm/TargetParser/RISCVTargetParser.h"
 #include "llvm/TargetParser/X86TargetParser.h"
 #include <optional>
 #include <sstream>
diff --git a/llvm/lib/TargetParser/RISCVISAInfo.cpp b/llvm/lib/TargetParser/RISCVISAInfo.cpp
index 7a5b10a877ebe..48b0536f3b886 100644
--- a/llvm/lib/TargetParser/RISCVISAInfo.cpp
+++ b/llvm/lib/TargetParser/RISCVISAInfo.cpp
@@ -1023,7 +1023,7 @@ std::string RISCVISAInfo::getTargetFeatureForExtension(StringRef Ext) {
 
 struct RISCVExtBit {
   const StringRef ext;
-  uint64_t bitpos;
+  uint8_t bitpos;
 };
 
 /// Maps extensions with assigned bit positions within group 0 of



More information about the llvm-commits mailing list