Skip to content

Commit d1e28e2

Browse files
authored
[RISCV] Support __builtin_cpu_init and __builtin_cpu_supports (llvm#99700)
This implements the __builtin_cpu_init and __builtin_cpu_supports builtin routines based on the compiler runtime changes in llvm#85790. This is inspired by llvm#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 llvm#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.
1 parent 0cf92b1 commit d1e28e2

File tree

9 files changed

+242
-8
lines changed

9 files changed

+242
-8
lines changed

clang/lib/Basic/Targets/RISCV.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,3 +479,9 @@ RISCVTargetInfo::checkCallingConvention(CallingConv CC) const {
479479
return CCCR_OK;
480480
}
481481
}
482+
483+
bool RISCVTargetInfo::validateCpuSupports(StringRef Feature) const {
484+
// Only allow extensions we have a known bit position for in the
485+
// __riscv_feature_bits structure.
486+
return -1 != llvm::RISCVISAInfo::getRISCVFeaturesBitPosition(Feature);
487+
}

clang/lib/Basic/Targets/RISCV.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ class RISCVTargetInfo : public TargetInfo {
126126
std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
127127
return std::make_pair(32, 32);
128128
}
129+
130+
bool supportsCpuSupports() const override { return getTriple().isOSLinux(); }
131+
bool supportsCpuInit() const override { return getTriple().isOSLinux(); }
132+
bool validateCpuSupports(StringRef Feature) const override;
129133
};
130134
class LLVM_LIBRARY_VISIBILITY RISCV32TargetInfo : public RISCVTargetInfo {
131135
public:

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
#include "llvm/Support/MathExtras.h"
6363
#include "llvm/Support/ScopedPrinter.h"
6464
#include "llvm/TargetParser/AArch64TargetParser.h"
65+
#include "llvm/TargetParser/RISCVISAInfo.h"
6566
#include "llvm/TargetParser/X86TargetParser.h"
6667
#include <optional>
6768
#include <sstream>
@@ -14308,6 +14309,16 @@ Value *CodeGenFunction::EmitAArch64CpuInit() {
1430814309
return Builder.CreateCall(Func);
1430914310
}
1431014311

14312+
Value *CodeGenFunction::EmitRISCVCpuInit() {
14313+
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
14314+
llvm::FunctionCallee Func =
14315+
CGM.CreateRuntimeFunction(FTy, "__init_riscv_feature_bits");
14316+
auto *CalleeGV = cast<llvm::GlobalValue>(Func.getCallee());
14317+
CalleeGV->setDSOLocal(true);
14318+
CalleeGV->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
14319+
return Builder.CreateCall(Func);
14320+
}
14321+
1431114322
Value *CodeGenFunction::EmitX86CpuInit() {
1431214323
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy,
1431314324
/*Variadic*/ false);
@@ -14360,6 +14371,42 @@ CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) {
1436014371
return Result;
1436114372
}
1436214373

14374+
Value *CodeGenFunction::EmitRISCVCpuSupports(const CallExpr *E) {
14375+
14376+
const Expr *FeatureExpr = E->getArg(0)->IgnoreParenCasts();
14377+
StringRef FeatureStr = cast<StringLiteral>(FeatureExpr)->getString();
14378+
if (!getContext().getTargetInfo().validateCpuSupports(FeatureStr))
14379+
return Builder.getFalse();
14380+
14381+
// Note: We are making an unchecked assumption that the size of the
14382+
// feature array is >= 1. This holds for any version of compiler-rt
14383+
// which defines this interface.
14384+
llvm::ArrayType *ArrayOfInt64Ty = llvm::ArrayType::get(Int64Ty, 1);
14385+
llvm::Type *StructTy = llvm::StructType::get(Int32Ty, ArrayOfInt64Ty);
14386+
llvm::Constant *RISCVFeaturesBits =
14387+
CGM.CreateRuntimeVariable(StructTy, "__riscv_feature_bits");
14388+
auto *GV = cast<llvm::GlobalValue>(RISCVFeaturesBits);
14389+
GV->setDSOLocal(true);
14390+
14391+
auto LoadFeatureBit = [&](unsigned Index) {
14392+
// Create GEP then load.
14393+
Value *IndexVal = llvm::ConstantInt::get(Int32Ty, Index);
14394+
llvm::Value *GEPIndices[] = {Builder.getInt32(0), Builder.getInt32(1),
14395+
IndexVal};
14396+
Value *Ptr =
14397+
Builder.CreateInBoundsGEP(StructTy, RISCVFeaturesBits, GEPIndices);
14398+
Value *FeaturesBit =
14399+
Builder.CreateAlignedLoad(Int64Ty, Ptr, CharUnits::fromQuantity(8));
14400+
return FeaturesBit;
14401+
};
14402+
14403+
int BitPos = RISCVISAInfo::getRISCVFeaturesBitPosition(FeatureStr);
14404+
assert(BitPos != -1 && "validation should have rejected this feature");
14405+
Value *MaskV = Builder.getInt64(1ULL << BitPos);
14406+
Value *Bitset = Builder.CreateAnd(LoadFeatureBit(0), MaskV);
14407+
return Builder.CreateICmpEQ(Bitset, MaskV);
14408+
}
14409+
1436314410
Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
1436414411
const CallExpr *E) {
1436514412
if (BuiltinID == Builtin::BI__builtin_cpu_is)
@@ -21854,6 +21901,12 @@ Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID,
2185421901
Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
2185521902
const CallExpr *E,
2185621903
ReturnValueSlot ReturnValue) {
21904+
21905+
if (BuiltinID == Builtin::BI__builtin_cpu_supports)
21906+
return EmitRISCVCpuSupports(E);
21907+
if (BuiltinID == Builtin::BI__builtin_cpu_init)
21908+
return EmitRISCVCpuInit();
21909+
2185721910
SmallVector<Value *, 4> Ops;
2185821911
llvm::Type *ResultType = ConvertType(E->getType());
2185921912

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4697,6 +4697,9 @@ class CodeGenFunction : public CodeGenTypeCache {
46974697
llvm::Value *EmitRISCVBuiltinExpr(unsigned BuiltinID, const CallExpr *E,
46984698
ReturnValueSlot ReturnValue);
46994699

4700+
llvm::Value *EmitRISCVCpuSupports(const CallExpr *E);
4701+
llvm::Value *EmitRISCVCpuInit();
4702+
47004703
void AddAMDGPUFenceAddressSpaceMMRA(llvm::Instruction *Inst,
47014704
const CallExpr *E);
47024705
void ProcessOrderScopeAMDGCN(llvm::Value *Order, llvm::Value *Scope,

clang/test/CodeGen/builtin-cpu-supports.c

Lines changed: 105 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
// RUN: FileCheck %s --check-prefix=CHECK-X86
44
// RUN: %clang_cc1 -triple ppc64le-linux-gnu -emit-llvm -o - %s | FileCheck %s \
55
// RUN: --check-prefix=CHECK-PPC
6-
7-
#ifndef __PPC__
6+
// RUN: %clang_cc1 -triple riscv32-linux-gnu -emit-llvm -o - %s | FileCheck %s \
7+
// RUN: --check-prefix=CHECK-RV32
8+
// RUN: %clang_cc1 -triple riscv64-linux-gnu -emit-llvm -o - %s | FileCheck %s \
9+
// RUN: --check-prefix=CHECK-RV64
10+
#ifdef __x86_64__
811

912
// Test that we have the structure definition, the gep offsets, the name of the
1013
// global, the bit grab, and the icmp correct.
@@ -101,8 +104,10 @@ int v3() { return __builtin_cpu_supports("x86-64-v3"); }
101104
// CHECK-X86-NEXT: ret i32 [[CONV]]
102105
//
103106
int v4() { return __builtin_cpu_supports("x86-64-v4"); }
104-
#else
105-
// CHECK-PPC-LABEL: define dso_local signext i32 @test(
107+
#endif
108+
109+
#ifdef __PPC__
110+
// CHECK-PPC-LABEL: define dso_local signext i32 @test_ppc(
106111
// CHECK-PPC-SAME: i32 noundef signext [[A:%.*]]) #[[ATTR0:[0-9]+]] {
107112
// CHECK-PPC-NEXT: entry:
108113
// CHECK-PPC-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
@@ -193,7 +198,7 @@ int v4() { return __builtin_cpu_supports("x86-64-v4"); }
193198
// CHECK-PPC-NEXT: [[TMP18:%.*]] = load i32, ptr [[RETVAL]], align 4
194199
// CHECK-PPC-NEXT: ret i32 [[TMP18]]
195200
//
196-
int test(int a) {
201+
int test_ppc(int a) {
197202
if (__builtin_cpu_supports("arch_3_00")) // HWCAP2
198203
return a;
199204
else if (__builtin_cpu_supports("mmu")) // HWCAP
@@ -211,3 +216,98 @@ int test(int a) {
211216
return a + 5;
212217
}
213218
#endif
219+
220+
#ifdef __riscv
221+
// CHECK-RV32-LABEL: define dso_local i32 @test_riscv(
222+
// CHECK-RV32-SAME: i32 noundef [[A:%.*]]) #[[ATTR0:[0-9]+]] {
223+
// CHECK-RV32-NEXT: entry:
224+
// CHECK-RV32-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
225+
// CHECK-RV32-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
226+
// CHECK-RV32-NEXT: store i32 [[A]], ptr [[A_ADDR]], align 4
227+
// CHECK-RV32-NEXT: call void @__init_riscv_feature_bits()
228+
// 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
229+
// CHECK-RV32-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1
230+
// CHECK-RV32-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1
231+
// CHECK-RV32-NEXT: br i1 [[TMP2]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
232+
// CHECK-RV32: if.then:
233+
// CHECK-RV32-NEXT: store i32 3, ptr [[RETVAL]], align 4
234+
// CHECK-RV32-NEXT: br label [[RETURN:%.*]]
235+
// CHECK-RV32: if.else:
236+
// 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
237+
// CHECK-RV32-NEXT: [[TMP4:%.*]] = and i64 [[TMP3]], 4
238+
// CHECK-RV32-NEXT: [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 4
239+
// CHECK-RV32-NEXT: br i1 [[TMP5]], label [[IF_THEN1:%.*]], label [[IF_ELSE2:%.*]]
240+
// CHECK-RV32: if.then1:
241+
// CHECK-RV32-NEXT: store i32 7, ptr [[RETVAL]], align 4
242+
// CHECK-RV32-NEXT: br label [[RETURN]]
243+
// CHECK-RV32: if.else2:
244+
// 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
245+
// CHECK-RV32-NEXT: [[TMP7:%.*]] = and i64 [[TMP6]], 2097152
246+
// CHECK-RV32-NEXT: [[TMP8:%.*]] = icmp eq i64 [[TMP7]], 2097152
247+
// CHECK-RV32-NEXT: br i1 [[TMP8]], label [[IF_THEN3:%.*]], label [[IF_END:%.*]]
248+
// CHECK-RV32: if.then3:
249+
// CHECK-RV32-NEXT: store i32 11, ptr [[RETVAL]], align 4
250+
// CHECK-RV32-NEXT: br label [[RETURN]]
251+
// CHECK-RV32: if.end:
252+
// CHECK-RV32-NEXT: br label [[IF_END4:%.*]]
253+
// CHECK-RV32: if.end4:
254+
// CHECK-RV32-NEXT: br label [[IF_END5:%.*]]
255+
// CHECK-RV32: if.end5:
256+
// CHECK-RV32-NEXT: store i32 0, ptr [[RETVAL]], align 4
257+
// CHECK-RV32-NEXT: br label [[RETURN]]
258+
// CHECK-RV32: return:
259+
// CHECK-RV32-NEXT: [[TMP9:%.*]] = load i32, ptr [[RETVAL]], align 4
260+
// CHECK-RV32-NEXT: ret i32 [[TMP9]]
261+
//
262+
// CHECK-RV64-LABEL: define dso_local signext i32 @test_riscv(
263+
// CHECK-RV64-SAME: i32 noundef signext [[A:%.*]]) #[[ATTR0:[0-9]+]] {
264+
// CHECK-RV64-NEXT: entry:
265+
// CHECK-RV64-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
266+
// CHECK-RV64-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
267+
// CHECK-RV64-NEXT: store i32 [[A]], ptr [[A_ADDR]], align 4
268+
// CHECK-RV64-NEXT: call void @__init_riscv_feature_bits()
269+
// 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
270+
// CHECK-RV64-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1
271+
// CHECK-RV64-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1
272+
// CHECK-RV64-NEXT: br i1 [[TMP2]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
273+
// CHECK-RV64: if.then:
274+
// CHECK-RV64-NEXT: store i32 3, ptr [[RETVAL]], align 4
275+
// CHECK-RV64-NEXT: br label [[RETURN:%.*]]
276+
// CHECK-RV64: if.else:
277+
// 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
278+
// CHECK-RV64-NEXT: [[TMP4:%.*]] = and i64 [[TMP3]], 4
279+
// CHECK-RV64-NEXT: [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 4
280+
// CHECK-RV64-NEXT: br i1 [[TMP5]], label [[IF_THEN1:%.*]], label [[IF_ELSE2:%.*]]
281+
// CHECK-RV64: if.then1:
282+
// CHECK-RV64-NEXT: store i32 7, ptr [[RETVAL]], align 4
283+
// CHECK-RV64-NEXT: br label [[RETURN]]
284+
// CHECK-RV64: if.else2:
285+
// 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
286+
// CHECK-RV64-NEXT: [[TMP7:%.*]] = and i64 [[TMP6]], 2097152
287+
// CHECK-RV64-NEXT: [[TMP8:%.*]] = icmp eq i64 [[TMP7]], 2097152
288+
// CHECK-RV64-NEXT: br i1 [[TMP8]], label [[IF_THEN3:%.*]], label [[IF_END:%.*]]
289+
// CHECK-RV64: if.then3:
290+
// CHECK-RV64-NEXT: store i32 11, ptr [[RETVAL]], align 4
291+
// CHECK-RV64-NEXT: br label [[RETURN]]
292+
// CHECK-RV64: if.end:
293+
// CHECK-RV64-NEXT: br label [[IF_END4:%.*]]
294+
// CHECK-RV64: if.end4:
295+
// CHECK-RV64-NEXT: br label [[IF_END5:%.*]]
296+
// CHECK-RV64: if.end5:
297+
// CHECK-RV64-NEXT: store i32 0, ptr [[RETVAL]], align 4
298+
// CHECK-RV64-NEXT: br label [[RETURN]]
299+
// CHECK-RV64: return:
300+
// CHECK-RV64-NEXT: [[TMP9:%.*]] = load i32, ptr [[RETVAL]], align 4
301+
// CHECK-RV64-NEXT: ret i32 [[TMP9]]
302+
//
303+
int test_riscv(int a) {
304+
__builtin_cpu_init();
305+
if (__builtin_cpu_supports("a"))
306+
return 3;
307+
else if (__builtin_cpu_supports("c"))
308+
return 7;
309+
else if (__builtin_cpu_supports("v"))
310+
return 11;
311+
return 0;
312+
}
313+
#endif

clang/test/Preprocessor/has_builtin_cpuid.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,29 @@
22
// RUN: %clang_cc1 -fsyntax-only -triple x86_64-- -DX86 -verify %s
33
// RUN: %clang_cc1 -fsyntax-only -triple powerpc64-unknown-linux-gnu -DPPC \
44
// RUN: -verify %s
5+
// RUN: %clang_cc1 -fsyntax-only -triple riscv32-unknown-linux-gnu -DRISCV \
6+
// RUN: -verify %s
7+
// RUN: %clang_cc1 -fsyntax-only -triple riscv64-unknown-linux-gnu -DRISCV \
8+
// RUN: -verify %s
59
// expected-no-diagnostics
610
#if __has_builtin(__builtin_cpu_is)
7-
# ifdef ARM
8-
# error "ARM shouldn't have __builtin_cpu_is"
11+
# if defined(ARM) || defined(RISCV)
12+
# error "ARM/RISCV shouldn't have __builtin_cpu_is"
913
# endif
1014
#endif
15+
1116
#if __has_builtin(__builtin_cpu_init)
1217
# if defined(ARM) || defined(PPC)
1318
# error "ARM/PPC shouldn't have __builtin_cpu_init"
1419
# endif
20+
#else
21+
# ifdef RISCV
22+
# error "RISCV should have __builtin_cpu_init"
23+
# endif
24+
#endif
25+
26+
#if !__has_builtin(__builtin_cpu_supports)
27+
# if defined(ARM) || defined(X86) || defined(RISCV)
28+
# error "ARM/X86/RISCV should have __builtin_cpu_supports"
29+
# endif
1530
#endif

clang/test/Sema/builtin-cpu-supports.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// RUN: %clang_cc1 -fsyntax-only -triple x86_64-pc-linux-gnu -verify %s
22
// RUN: %clang_cc1 -fsyntax-only -triple aarch64-linux-gnu -verify %s
3+
// RUN: %clang_cc1 -fsyntax-only -triple riscv32-linux-gnu -verify %s
4+
// RUN: %clang_cc1 -fsyntax-only -triple riscv64-linux-gnu -verify %s
35

46
extern void a(const char *);
57

@@ -26,7 +28,9 @@ int main(void) {
2628
(void)__builtin_cpu_supports("x86-64-v3");
2729
(void)__builtin_cpu_supports("x86-64-v4");
2830
(void)__builtin_cpu_supports("x86-64-v5"); // expected-warning {{invalid cpu feature string for builtin}}
29-
#else
31+
#endif
32+
33+
#ifdef __aarch64__
3034
if (__builtin_cpu_supports("neon")) // expected-warning {{invalid cpu feature string for builtin}}
3135
a("vsx");
3236

@@ -36,5 +40,10 @@ int main(void) {
3640
__builtin_cpu_init(); // expected-error {{builtin is not supported on this target}}
3741
#endif
3842

43+
#ifdef __riscv
44+
if (__builtin_cpu_supports("garbage")) // expected-warning {{invalid cpu feature string for builtin}}
45+
a("vsx");
46+
#endif
47+
3948
return 0;
4049
}

llvm/include/llvm/TargetParser/RISCVISAInfo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ class RISCVISAInfo {
8080
std::set<StringRef> &EnabledFeatureNames,
8181
StringMap<StringRef> &DescMap);
8282

83+
/// Return the bit position (in group 0) of __riscv_feature_bits. Returns
84+
/// -1 if not supported.
85+
static int getRISCVFeaturesBitPosition(StringRef Ext);
86+
8387
private:
8488
RISCVISAInfo(unsigned XLen) : XLen(XLen) {}
8589

llvm/lib/TargetParser/RISCVISAInfo.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,3 +1020,43 @@ std::string RISCVISAInfo::getTargetFeatureForExtension(StringRef Ext) {
10201020
return isExperimentalExtension(Name) ? "experimental-" + Name.str()
10211021
: Name.str();
10221022
}
1023+
1024+
struct RISCVExtBit {
1025+
const StringLiteral ext;
1026+
uint8_t bitpos;
1027+
};
1028+
1029+
/// Maps extensions with assigned bit positions within group 0 of
1030+
/// __riscv_features_bits to their respective bit position. At the
1031+
/// moment all extensions are within group 0.
1032+
constexpr static RISCVExtBit RISCVGroup0BitPositions[] = {
1033+
{"a", 0}, {"c", 2},
1034+
{"d", 3}, {"f", 5},
1035+
{"i", 8}, {"m", 12},
1036+
{"v", 21}, {"zacas", 26},
1037+
{"zba", 27}, {"zbb", 28},
1038+
{"zbc", 29}, {"zbkb", 30},
1039+
{"zbkc", 31}, {"zbkx", 32},
1040+
{"zbs", 33}, {"zfa", 34},
1041+
{"zfh", 35}, {"zfhmin", 36},
1042+
{"zicboz", 37}, {"zicond", 38},
1043+
{"zihintntl", 39}, {"zihintpause", 40},
1044+
{"zknd", 41}, {"zkne", 42},
1045+
{"zknh", 43}, {"zksed", 44},
1046+
{"zksh", 45}, {"zkt", 46},
1047+
{"ztso", 47}, {"zvbb", 48},
1048+
{"zvbc", 49}, {"zvfh", 50},
1049+
{"zvfhmin", 51}, {"zvkb", 52},
1050+
{"zvkg", 53}, {"zvkned", 54},
1051+
{"zvknha", 55}, {"zvknhb", 56},
1052+
{"zvksed", 57}, {"zvksh", 58},
1053+
{"zvkt", 59}};
1054+
int RISCVISAInfo::getRISCVFeaturesBitPosition(StringRef Ext) {
1055+
// Note that this code currently accepts mixed case extension names, but
1056+
// does not handle extension versions at all. That's probably fine because
1057+
// there's only one extension version in the __riscv_feature_bits vector.
1058+
for (auto E : RISCVGroup0BitPositions)
1059+
if (E.ext.equals_insensitive(Ext))
1060+
return E.bitpos;
1061+
return -1;
1062+
}

0 commit comments

Comments
 (0)