[llvm] d1e28e2 - [RISCV] Support __builtin_cpu_init and __builtin_cpu_supports (#99700)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 23 08:48:32 PDT 2024


Author: Philip Reames
Date: 2024-07-23T08:48:28-07:00
New Revision: d1e28e2a7bd4642e6a5ec963a5ca2ad2ba1b2b59

URL: https://github.com/llvm/llvm-project/commit/d1e28e2a7bd4642e6a5ec963a5ca2ad2ba1b2b59
DIFF: https://github.com/llvm/llvm-project/commit/d1e28e2a7bd4642e6a5ec963a5ca2ad2ba1b2b59.diff

LOG: [RISCV] Support __builtin_cpu_init and __builtin_cpu_supports (#99700)

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.

I don't have an environment in which I can actually test this, but @BeMg
has been kind enough to report that this appears to work as expected.

Before this can make it into a release, we need a change such as
https://github.com/llvm/llvm-project/pull/99958. The gcc docs claim that
cpu_support can be called by "normal" code without calling the cpu_init
routine because the init routine will have been called by a high
priority constructor. Our current compiler-rt mechanism does not do
this.

Added: 
    

Modified: 
    clang/lib/Basic/Targets/RISCV.cpp
    clang/lib/Basic/Targets/RISCV.h
    clang/lib/CodeGen/CGBuiltin.cpp
    clang/lib/CodeGen/CodeGenFunction.h
    clang/test/CodeGen/builtin-cpu-supports.c
    clang/test/Preprocessor/has_builtin_cpuid.c
    clang/test/Sema/builtin-cpu-supports.c
    llvm/include/llvm/TargetParser/RISCVISAInfo.h
    llvm/lib/TargetParser/RISCVISAInfo.cpp

Removed: 
    


################################################################################
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 5639239359ab8..c199976956085 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -62,6 +62,7 @@
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/ScopedPrinter.h"
 #include "llvm/TargetParser/AArch64TargetParser.h"
+#include "llvm/TargetParser/RISCVISAInfo.h"
 #include "llvm/TargetParser/X86TargetParser.h"
 #include <optional>
 #include <sstream>
@@ -14308,6 +14309,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);
@@ -14360,6 +14371,42 @@ 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)
@@ -21854,6 +21901,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 ba7b565d97559..67e3019565cd0 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4697,6 +4697,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/clang/test/CodeGen/builtin-cpu-supports.c b/clang/test/CodeGen/builtin-cpu-supports.c
index f960040ab094b..26edc2c8fff08 100644
--- a/clang/test/CodeGen/builtin-cpu-supports.c
+++ b/clang/test/CodeGen/builtin-cpu-supports.c
@@ -3,8 +3,11 @@
 // 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__
+// RUN: %clang_cc1 -triple riscv32-linux-gnu -emit-llvm -o - %s | FileCheck %s \
+// RUN:   --check-prefix=CHECK-RV32
+// RUN: %clang_cc1 -triple riscv64-linux-gnu -emit-llvm -o - %s | FileCheck %s \
+// RUN:   --check-prefix=CHECK-RV64
+#ifdef __x86_64__
 
 // Test that we have the structure definition, the gep offsets, the name of the
 // global, the bit grab, and the icmp correct.
@@ -101,8 +104,10 @@ int v3() { return __builtin_cpu_supports("x86-64-v3"); }
 // 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(
+#endif
+
+#ifdef __PPC__
+// CHECK-PPC-LABEL: define dso_local signext i32 @test_ppc(
 // CHECK-PPC-SAME: i32 noundef signext [[A:%.*]]) #[[ATTR0:[0-9]+]] {
 // CHECK-PPC-NEXT:  entry:
 // CHECK-PPC-NEXT:    [[RETVAL:%.*]] = alloca i32, align 4
@@ -193,7 +198,7 @@ int v4() { return __builtin_cpu_supports("x86-64-v4"); }
 // CHECK-PPC-NEXT:    [[TMP18:%.*]] = load i32, ptr [[RETVAL]], align 4
 // CHECK-PPC-NEXT:    ret i32 [[TMP18]]
 //
-int test(int a) {
+int test_ppc(int a) {
   if (__builtin_cpu_supports("arch_3_00")) // HWCAP2
     return a;
   else if (__builtin_cpu_supports("mmu"))  // HWCAP
@@ -211,3 +216,98 @@ int test(int a) {
   return a + 5;
 }
 #endif
+
+#ifdef __riscv
+// CHECK-RV32-LABEL: define dso_local i32 @test_riscv(
+// CHECK-RV32-SAME: i32 noundef [[A:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[RETVAL:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    call void @__init_riscv_feature_bits()
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = and i64 [[TMP0]], 1
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1
+// CHECK-RV32-NEXT:    br i1 [[TMP2]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+// CHECK-RV32:       if.then:
+// CHECK-RV32-NEXT:    store i32 3, ptr [[RETVAL]], align 4
+// CHECK-RV32-NEXT:    br label [[RETURN:%.*]]
+// CHECK-RV32:       if.else:
+// CHECK-RV32-NEXT:    [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
+// CHECK-RV32-NEXT:    [[TMP4:%.*]] = and i64 [[TMP3]], 4
+// CHECK-RV32-NEXT:    [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 4
+// CHECK-RV32-NEXT:    br i1 [[TMP5]], label [[IF_THEN1:%.*]], label [[IF_ELSE2:%.*]]
+// CHECK-RV32:       if.then1:
+// CHECK-RV32-NEXT:    store i32 7, ptr [[RETVAL]], align 4
+// CHECK-RV32-NEXT:    br label [[RETURN]]
+// CHECK-RV32:       if.else2:
+// CHECK-RV32-NEXT:    [[TMP6:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
+// CHECK-RV32-NEXT:    [[TMP7:%.*]] = and i64 [[TMP6]], 2097152
+// CHECK-RV32-NEXT:    [[TMP8:%.*]] = icmp eq i64 [[TMP7]], 2097152
+// CHECK-RV32-NEXT:    br i1 [[TMP8]], label [[IF_THEN3:%.*]], label [[IF_END:%.*]]
+// CHECK-RV32:       if.then3:
+// CHECK-RV32-NEXT:    store i32 11, ptr [[RETVAL]], align 4
+// CHECK-RV32-NEXT:    br label [[RETURN]]
+// CHECK-RV32:       if.end:
+// CHECK-RV32-NEXT:    br label [[IF_END4:%.*]]
+// CHECK-RV32:       if.end4:
+// CHECK-RV32-NEXT:    br label [[IF_END5:%.*]]
+// CHECK-RV32:       if.end5:
+// CHECK-RV32-NEXT:    store i32 0, ptr [[RETVAL]], align 4
+// CHECK-RV32-NEXT:    br label [[RETURN]]
+// CHECK-RV32:       return:
+// CHECK-RV32-NEXT:    [[TMP9:%.*]] = load i32, ptr [[RETVAL]], align 4
+// CHECK-RV32-NEXT:    ret i32 [[TMP9]]
+//
+// CHECK-RV64-LABEL: define dso_local signext i32 @test_riscv(
+// CHECK-RV64-SAME: i32 noundef signext [[A:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[RETVAL:%.*]] = alloca i32, align 4
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV64-NEXT:    store i32 [[A]], ptr [[A_ADDR]], align 4
+// CHECK-RV64-NEXT:    call void @__init_riscv_feature_bits()
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = and i64 [[TMP0]], 1
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1
+// CHECK-RV64-NEXT:    br i1 [[TMP2]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+// CHECK-RV64:       if.then:
+// CHECK-RV64-NEXT:    store i32 3, ptr [[RETVAL]], align 4
+// CHECK-RV64-NEXT:    br label [[RETURN:%.*]]
+// CHECK-RV64:       if.else:
+// CHECK-RV64-NEXT:    [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
+// CHECK-RV64-NEXT:    [[TMP4:%.*]] = and i64 [[TMP3]], 4
+// CHECK-RV64-NEXT:    [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 4
+// CHECK-RV64-NEXT:    br i1 [[TMP5]], label [[IF_THEN1:%.*]], label [[IF_ELSE2:%.*]]
+// CHECK-RV64:       if.then1:
+// CHECK-RV64-NEXT:    store i32 7, ptr [[RETVAL]], align 4
+// CHECK-RV64-NEXT:    br label [[RETURN]]
+// CHECK-RV64:       if.else2:
+// CHECK-RV64-NEXT:    [[TMP6:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
+// CHECK-RV64-NEXT:    [[TMP7:%.*]] = and i64 [[TMP6]], 2097152
+// CHECK-RV64-NEXT:    [[TMP8:%.*]] = icmp eq i64 [[TMP7]], 2097152
+// CHECK-RV64-NEXT:    br i1 [[TMP8]], label [[IF_THEN3:%.*]], label [[IF_END:%.*]]
+// CHECK-RV64:       if.then3:
+// CHECK-RV64-NEXT:    store i32 11, ptr [[RETVAL]], align 4
+// CHECK-RV64-NEXT:    br label [[RETURN]]
+// CHECK-RV64:       if.end:
+// CHECK-RV64-NEXT:    br label [[IF_END4:%.*]]
+// CHECK-RV64:       if.end4:
+// CHECK-RV64-NEXT:    br label [[IF_END5:%.*]]
+// CHECK-RV64:       if.end5:
+// CHECK-RV64-NEXT:    store i32 0, ptr [[RETVAL]], align 4
+// CHECK-RV64-NEXT:    br label [[RETURN]]
+// CHECK-RV64:       return:
+// CHECK-RV64-NEXT:    [[TMP9:%.*]] = load i32, ptr [[RETVAL]], align 4
+// CHECK-RV64-NEXT:    ret i32 [[TMP9]]
+//
+int test_riscv(int a) {
+  __builtin_cpu_init();
+  if (__builtin_cpu_supports("a"))
+    return 3;
+  else if (__builtin_cpu_supports("c"))
+    return 7;
+  else if (__builtin_cpu_supports("v"))
+    return 11;
+  return 0;
+}
+#endif

diff  --git a/clang/test/Preprocessor/has_builtin_cpuid.c b/clang/test/Preprocessor/has_builtin_cpuid.c
index 35ef65ecdd9b9..e69f912ce688d 100644
--- a/clang/test/Preprocessor/has_builtin_cpuid.c
+++ b/clang/test/Preprocessor/has_builtin_cpuid.c
@@ -2,14 +2,29 @@
 // RUN: %clang_cc1 -fsyntax-only -triple x86_64-- -DX86 -verify %s
 // RUN: %clang_cc1 -fsyntax-only -triple powerpc64-unknown-linux-gnu -DPPC \
 // RUN:   -verify %s
+// RUN: %clang_cc1 -fsyntax-only -triple riscv32-unknown-linux-gnu -DRISCV \
+// RUN:   -verify %s
+// RUN: %clang_cc1 -fsyntax-only -triple riscv64-unknown-linux-gnu -DRISCV \
+// RUN:   -verify %s
 // expected-no-diagnostics
 #if __has_builtin(__builtin_cpu_is)
-# ifdef ARM
-#   error "ARM shouldn't have __builtin_cpu_is"
+# if defined(ARM) || defined(RISCV)
+#   error "ARM/RISCV shouldn't have __builtin_cpu_is"
 # endif
 #endif
+
 #if __has_builtin(__builtin_cpu_init)
 # if defined(ARM) || defined(PPC)
 #   error "ARM/PPC shouldn't have __builtin_cpu_init"
 # endif
+#else
+# ifdef RISCV
+#   error "RISCV should have __builtin_cpu_init"
+# endif
+#endif
+
+#if !__has_builtin(__builtin_cpu_supports)
+# if defined(ARM) || defined(X86) || defined(RISCV)
+#   error "ARM/X86/RISCV should have __builtin_cpu_supports"
+# endif
 #endif

diff  --git a/clang/test/Sema/builtin-cpu-supports.c b/clang/test/Sema/builtin-cpu-supports.c
index 51ee9661807f8..133410abaa711 100644
--- a/clang/test/Sema/builtin-cpu-supports.c
+++ b/clang/test/Sema/builtin-cpu-supports.c
@@ -1,5 +1,7 @@
 // RUN: %clang_cc1 -fsyntax-only -triple x86_64-pc-linux-gnu -verify %s
 // RUN: %clang_cc1 -fsyntax-only -triple aarch64-linux-gnu -verify %s
+// RUN: %clang_cc1 -fsyntax-only -triple riscv32-linux-gnu -verify %s
+// RUN: %clang_cc1 -fsyntax-only -triple riscv64-linux-gnu -verify %s
 
 extern void a(const char *);
 
@@ -26,7 +28,9 @@ int main(void) {
   (void)__builtin_cpu_supports("x86-64-v3");
   (void)__builtin_cpu_supports("x86-64-v4");
   (void)__builtin_cpu_supports("x86-64-v5"); // expected-warning {{invalid cpu feature string for builtin}}
-#else
+#endif
+
+#ifdef __aarch64__
   if (__builtin_cpu_supports("neon")) // expected-warning {{invalid cpu feature string for builtin}}
     a("vsx");
 
@@ -36,5 +40,10 @@ int main(void) {
   __builtin_cpu_init(); // expected-error {{builtin is not supported on this target}}
 #endif
 
+#ifdef __riscv
+  if (__builtin_cpu_supports("garbage")) // expected-warning {{invalid cpu feature string for builtin}}
+    a("vsx");
+#endif
+
   return 0;
 }

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..9f650b87f2b39 100644
--- a/llvm/lib/TargetParser/RISCVISAInfo.cpp
+++ b/llvm/lib/TargetParser/RISCVISAInfo.cpp
@@ -1020,3 +1020,43 @@ std::string RISCVISAInfo::getTargetFeatureForExtension(StringRef Ext) {
   return isExperimentalExtension(Name) ? "experimental-" + Name.str()
                                        : Name.str();
 }
+
+struct RISCVExtBit {
+  const StringLiteral ext;
+  uint8_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.
+constexpr 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;
+}


        


More information about the llvm-commits mailing list