-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[RISCV] Support __builtin_cpu_is #116231
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RISCV] Support __builtin_cpu_is #116231
Changes from 6 commits
fb18dcb
42b7aa6
9686a2c
2bb2d50
8afe59f
0e88278
e7fd10e
b735205
c3f0a1b
00e09c7
e120a24
3120c27
c476b98
7cadf6f
c181e12
5f5a642
e6be218
dbd589b
5aaf32c
e92f9c2
4feaa9d
f2412e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -67,6 +67,7 @@ | |
| #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> | ||
|
|
@@ -22505,6 +22506,57 @@ Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID, | |
| return nullptr; | ||
| } | ||
|
|
||
| Value *CodeGenFunction::EmitRISCVCpuIs(const CallExpr *E) { | ||
| const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts(); | ||
| StringRef CPUStr = cast<clang::StringLiteral>(CPUExpr)->getString(); | ||
| return EmitRISCVCpuIs(CPUStr); | ||
| } | ||
|
|
||
| Value *CodeGenFunction::EmitRISCVCpuIs(StringRef CPUStr) { | ||
| llvm::Type *Int32Ty = Builder.getInt32Ty(); | ||
| llvm::Type *Int64Ty = Builder.getInt64Ty(); | ||
| llvm::Type *MXLenType = | ||
| CGM.getTarget().getTriple().isArch32Bit() ? Int32Ty : Int64Ty; | ||
|
|
||
| llvm::Type *StructTy = llvm::StructType::get(Int32Ty, MXLenType, MXLenType); | ||
| llvm::Constant *RISCVCPUModel = | ||
| CGM.CreateRuntimeVariable(StructTy, "__riscv_cpu_model"); | ||
| cast<llvm::GlobalValue>(RISCVCPUModel)->setDSOLocal(true); | ||
|
|
||
| auto loadRISCVCPUID = [&](unsigned Index, llvm::Type *ValueTy, | ||
| CGBuilderTy &Builder, CodeGenModule &CGM) { | ||
wangpc-pp marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| llvm::Value *GEPIndices[] = {Builder.getInt32(0), | ||
| llvm::ConstantInt::get(Int32Ty, Index)}; | ||
| Value *Ptr = Builder.CreateInBoundsGEP(StructTy, RISCVCPUModel, GEPIndices); | ||
wangpc-pp marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Value *CPUID = Builder.CreateAlignedLoad( | ||
| ValueTy, Ptr, | ||
| CharUnits::fromQuantity(ValueTy->getScalarSizeInBits() / 8)); | ||
wangpc-pp marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return CPUID; | ||
| }; | ||
|
|
||
| // Compare mvendorid. | ||
| Value *VendorID = loadRISCVCPUID(0, Int32Ty, Builder, CGM); | ||
| Value *Result = Builder.CreateICmpEQ( | ||
| VendorID, | ||
| llvm::ConstantInt::get(Int32Ty, llvm::RISCV::getVendorID(CPUStr))); | ||
|
|
||
| // Compare marchid. | ||
| Value *ArchID = loadRISCVCPUID(1, MXLenType, Builder, CGM); | ||
| Result = Builder.CreateAnd( | ||
| Result, Builder.CreateICmpEQ( | ||
| ArchID, llvm::ConstantInt::get( | ||
| MXLenType, llvm::RISCV::getArchID(CPUStr)))); | ||
|
|
||
| // Compare mimplid. | ||
wangpc-pp marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Value *ImplID = loadRISCVCPUID(2, MXLenType, Builder, CGM); | ||
| Result = Builder.CreateAnd( | ||
| Result, Builder.CreateICmpEQ( | ||
| ImplID, llvm::ConstantInt::get( | ||
| MXLenType, llvm::RISCV::getImplID(CPUStr)))); | ||
|
||
|
|
||
| return Result; | ||
| } | ||
|
|
||
| Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID, | ||
| const CallExpr *E, | ||
| ReturnValueSlot ReturnValue) { | ||
|
|
@@ -22513,6 +22565,8 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID, | |
| return EmitRISCVCpuSupports(E); | ||
| if (BuiltinID == Builtin::BI__builtin_cpu_init) | ||
| return EmitRISCVCpuInit(); | ||
| if (BuiltinID == Builtin::BI__builtin_cpu_is) | ||
| return EmitRISCVCpuIs(E); | ||
|
|
||
| SmallVector<Value *, 4> Ops; | ||
| llvm::Type *ResultType = ConvertType(E->getType()); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,55 +1,131 @@ | ||
| // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm < %s| FileCheck %s | ||
| // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 | ||
| // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-X86 | ||
| // RUN: %clang_cc1 -triple riscv64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-RV64 | ||
|
|
||
| #ifdef __x86_64__ | ||
wangpc-pp marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // 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-X86-LABEL: define dso_local void @intel( | ||
| // CHECK-X86-SAME: ) #[[ATTR0:[0-9]+]] { | ||
| // CHECK-X86-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-X86-NEXT: [[TMP0:%.*]] = load i32, ptr @__cpu_model, align 4 | ||
| // CHECK-X86-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 1 | ||
| // CHECK-X86-NEXT: br i1 [[TMP1]], 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: ret void | ||
| // | ||
| void intel(void) { | ||
| if (__builtin_cpu_is("intel")) | ||
| a("intel"); | ||
|
|
||
| // CHECK: [[LOAD:%[^ ]+]] = load i32, ptr @__cpu_model | ||
| // CHECK: = icmp eq i32 [[LOAD]], 1 | ||
| } | ||
|
|
||
| // CHECK-X86-LABEL: define dso_local void @amd( | ||
| // CHECK-X86-SAME: ) #[[ATTR0]] { | ||
| // CHECK-X86-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-X86-NEXT: [[TMP0:%.*]] = load i32, ptr @__cpu_model, align 4 | ||
| // CHECK-X86-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 2 | ||
| // CHECK-X86-NEXT: br i1 [[TMP1]], label %[[IF_THEN:.*]], label %[[IF_END:.*]] | ||
| // CHECK-X86: [[IF_THEN]]: | ||
| // CHECK-X86-NEXT: call void @a(ptr noundef @.str.1) | ||
| // CHECK-X86-NEXT: br label %[[IF_END]] | ||
| // CHECK-X86: [[IF_END]]: | ||
| // CHECK-X86-NEXT: ret void | ||
| // | ||
| void amd(void) { | ||
| if (__builtin_cpu_is("amd")) | ||
| a("amd"); | ||
|
|
||
| // CHECK: [[LOAD:%[^ ]+]] = load i32, ptr @__cpu_model | ||
| // CHECK: = icmp eq i32 [[LOAD]], 2 | ||
| } | ||
|
|
||
| // CHECK-X86-LABEL: define dso_local void @atom( | ||
| // CHECK-X86-SAME: ) #[[ATTR0]] { | ||
| // CHECK-X86-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-X86-NEXT: [[TMP0:%.*]] = load i32, ptr getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, ptr @__cpu_model, i32 0, i32 1), align 4 | ||
| // CHECK-X86-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 1 | ||
| // CHECK-X86-NEXT: br i1 [[TMP1]], label %[[IF_THEN:.*]], label %[[IF_END:.*]] | ||
| // CHECK-X86: [[IF_THEN]]: | ||
| // CHECK-X86-NEXT: call void @a(ptr noundef @.str.2) | ||
| // CHECK-X86-NEXT: br label %[[IF_END]] | ||
| // CHECK-X86: [[IF_END]]: | ||
| // CHECK-X86-NEXT: ret void | ||
| // | ||
| void atom(void) { | ||
| if (__builtin_cpu_is("atom")) | ||
| a("atom"); | ||
|
|
||
| // CHECK: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, ptr @__cpu_model, i32 0, i32 1) | ||
| // CHECK: = icmp eq i32 [[LOAD]], 1 | ||
| } | ||
|
|
||
| // CHECK-X86-LABEL: define dso_local void @amdfam10h( | ||
| // CHECK-X86-SAME: ) #[[ATTR0]] { | ||
| // CHECK-X86-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-X86-NEXT: [[TMP0:%.*]] = load i32, ptr getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, ptr @__cpu_model, i32 0, i32 1), align 4 | ||
| // CHECK-X86-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 4 | ||
| // CHECK-X86-NEXT: br i1 [[TMP1]], label %[[IF_THEN:.*]], label %[[IF_END:.*]] | ||
| // CHECK-X86: [[IF_THEN]]: | ||
| // CHECK-X86-NEXT: call void @a(ptr noundef @.str.3) | ||
| // CHECK-X86-NEXT: br label %[[IF_END]] | ||
| // CHECK-X86: [[IF_END]]: | ||
| // CHECK-X86-NEXT: ret void | ||
| // | ||
| void amdfam10h(void) { | ||
| if (__builtin_cpu_is("amdfam10h")) | ||
| a("amdfam10h"); | ||
|
|
||
| // CHECK: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, ptr @__cpu_model, i32 0, i32 1) | ||
| // CHECK: = icmp eq i32 [[LOAD]], 4 | ||
| } | ||
|
|
||
| // CHECK-X86-LABEL: define dso_local void @barcelona( | ||
| // CHECK-X86-SAME: ) #[[ATTR0]] { | ||
| // CHECK-X86-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-X86-NEXT: [[TMP0:%.*]] = load i32, ptr getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, ptr @__cpu_model, i32 0, i32 2), align 4 | ||
| // CHECK-X86-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 4 | ||
| // CHECK-X86-NEXT: br i1 [[TMP1]], label %[[IF_THEN:.*]], label %[[IF_END:.*]] | ||
| // CHECK-X86: [[IF_THEN]]: | ||
| // CHECK-X86-NEXT: call void @a(ptr noundef @.str.4) | ||
| // CHECK-X86-NEXT: br label %[[IF_END]] | ||
| // CHECK-X86: [[IF_END]]: | ||
| // CHECK-X86-NEXT: ret void | ||
| // | ||
| void barcelona(void) { | ||
| if (__builtin_cpu_is("barcelona")) | ||
| a("barcelona"); | ||
|
|
||
| // CHECK: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, ptr @__cpu_model, i32 0, i32 2) | ||
| // CHECK: = icmp eq i32 [[LOAD]], 4 | ||
| } | ||
|
|
||
| // CHECK-X86-LABEL: define dso_local void @nehalem( | ||
| // CHECK-X86-SAME: ) #[[ATTR0]] { | ||
| // CHECK-X86-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-X86-NEXT: [[TMP0:%.*]] = load i32, ptr getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, ptr @__cpu_model, i32 0, i32 2), align 4 | ||
| // CHECK-X86-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 1 | ||
| // CHECK-X86-NEXT: br i1 [[TMP1]], label %[[IF_THEN:.*]], label %[[IF_END:.*]] | ||
| // CHECK-X86: [[IF_THEN]]: | ||
| // CHECK-X86-NEXT: call void @a(ptr noundef @.str.5) | ||
| // CHECK-X86-NEXT: br label %[[IF_END]] | ||
| // CHECK-X86: [[IF_END]]: | ||
| // CHECK-X86-NEXT: ret void | ||
| // | ||
| void nehalem(void) { | ||
| if (__builtin_cpu_is("nehalem")) | ||
| a("nehalem"); | ||
| } | ||
| #endif | ||
|
|
||
| // CHECK: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, ptr @__cpu_model, i32 0, i32 2) | ||
| // CHECK: = icmp eq i32 [[LOAD]], 1 | ||
| #ifdef __riscv | ||
| // CHECK-RV64-LABEL: define dso_local signext i32 @test_cpu_is_veyron_v1( | ||
| // CHECK-RV64-SAME: ) #[[ATTR0:[0-9]+]] { | ||
| // CHECK-RV64-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-RV64-NEXT: [[TMP0:%.*]] = load i32, ptr @__riscv_cpu_model, align 4 | ||
| // CHECK-RV64-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 1567 | ||
| // CHECK-RV64-NEXT: [[TMP2:%.*]] = load i64, ptr getelementptr inbounds ({ i32, i64, i64 }, ptr @__riscv_cpu_model, i32 0, i32 1), align 8 | ||
| // CHECK-RV64-NEXT: [[TMP3:%.*]] = icmp eq i64 [[TMP2]], -9223372036854710272 | ||
| // CHECK-RV64-NEXT: [[TMP4:%.*]] = and i1 [[TMP1]], [[TMP3]] | ||
| // CHECK-RV64-NEXT: [[TMP5:%.*]] = load i64, ptr getelementptr inbounds ({ i32, i64, i64 }, ptr @__riscv_cpu_model, i32 0, i32 2), align 8 | ||
| // CHECK-RV64-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 273 | ||
| // CHECK-RV64-NEXT: [[TMP7:%.*]] = and i1 [[TMP4]], [[TMP6]] | ||
| // CHECK-RV64-NEXT: [[CONV:%.*]] = zext i1 [[TMP7]] to i32 | ||
| // CHECK-RV64-NEXT: ret i32 [[CONV]] | ||
| // | ||
| int test_cpu_is_veyron_v1() { | ||
| return __builtin_cpu_is("veyron-v1"); | ||
| } | ||
| #endif | ||
Uh oh!
There was an error while loading. Please reload this page.