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; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits