Skip to content

Commit c11b6b1

Browse files
authored
[RISCV] Support __builtin_cpu_is
We have defined `__riscv_cpu_model` variable in #101449. It contains `mvendorid`, `marchid` and `mimpid` fields which are read via system call `sys_riscv_hwprobe`. We can support `__builtin_cpu_is` via comparing values in compiler's CPU definitions and `__riscv_cpu_model`. This depends on #116202. Reviewers: lenary, BeMg, kito-cheng, preames, lukel97 Reviewed By: lenary Pull Request: #116231
1 parent 775148f commit c11b6b1

File tree

8 files changed

+116
-0
lines changed

8 files changed

+116
-0
lines changed

clang/lib/Basic/Targets/RISCV.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,3 +512,10 @@ bool RISCVTargetInfo::validateGlobalRegisterVariable(
512512
}
513513
return false;
514514
}
515+
516+
bool RISCVTargetInfo::validateCpuIs(StringRef CPUName) const {
517+
assert(getTriple().isOSLinux() &&
518+
"__builtin_cpu_is() is only supported for Linux.");
519+
520+
return llvm::RISCV::hasValidCPUModel(CPUName);
521+
}

clang/lib/Basic/Targets/RISCV.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,10 @@ class RISCVTargetInfo : public TargetInfo {
128128
}
129129

130130
bool supportsCpuSupports() const override { return getTriple().isOSLinux(); }
131+
bool supportsCpuIs() const override { return getTriple().isOSLinux(); }
131132
bool supportsCpuInit() const override { return getTriple().isOSLinux(); }
132133
bool validateCpuSupports(StringRef Feature) const override;
134+
bool validateCpuIs(StringRef CPUName) const override;
133135
bool isValidFeatureName(StringRef Name) const override;
134136

135137
bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize,

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
#include "llvm/Support/ScopedPrinter.h"
6767
#include "llvm/TargetParser/AArch64TargetParser.h"
6868
#include "llvm/TargetParser/RISCVISAInfo.h"
69+
#include "llvm/TargetParser/RISCVTargetParser.h"
6970
#include "llvm/TargetParser/X86TargetParser.h"
7071
#include <optional>
7172
#include <utility>
@@ -22693,6 +22694,47 @@ Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID,
2269322694
return nullptr;
2269422695
}
2269522696

22697+
Value *CodeGenFunction::EmitRISCVCpuIs(const CallExpr *E) {
22698+
const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts();
22699+
StringRef CPUStr = cast<clang::StringLiteral>(CPUExpr)->getString();
22700+
return EmitRISCVCpuIs(CPUStr);
22701+
}
22702+
22703+
Value *CodeGenFunction::EmitRISCVCpuIs(StringRef CPUStr) {
22704+
llvm::Type *Int32Ty = Builder.getInt32Ty();
22705+
llvm::Type *Int64Ty = Builder.getInt64Ty();
22706+
llvm::StructType *StructTy = llvm::StructType::get(Int32Ty, Int64Ty, Int64Ty);
22707+
llvm::Constant *RISCVCPUModel =
22708+
CGM.CreateRuntimeVariable(StructTy, "__riscv_cpu_model");
22709+
cast<llvm::GlobalValue>(RISCVCPUModel)->setDSOLocal(true);
22710+
22711+
auto loadRISCVCPUID = [&](unsigned Index) {
22712+
Value *Ptr = Builder.CreateStructGEP(StructTy, RISCVCPUModel, Index);
22713+
Value *CPUID = Builder.CreateAlignedLoad(StructTy->getTypeAtIndex(Index),
22714+
Ptr, llvm::MaybeAlign());
22715+
return CPUID;
22716+
};
22717+
22718+
const llvm::RISCV::CPUModel CPUModel = llvm::RISCV::getCPUModel(CPUStr);
22719+
22720+
// Compare mvendorid.
22721+
Value *VendorID = loadRISCVCPUID(0);
22722+
Value *Result =
22723+
Builder.CreateICmpEQ(VendorID, Builder.getInt32(CPUModel.MVendorID));
22724+
22725+
// Compare marchid.
22726+
Value *ArchID = loadRISCVCPUID(1);
22727+
Result = Builder.CreateAnd(
22728+
Result, Builder.CreateICmpEQ(ArchID, Builder.getInt64(CPUModel.MArchID)));
22729+
22730+
// Compare mimpid.
22731+
Value *ImpID = loadRISCVCPUID(2);
22732+
Result = Builder.CreateAnd(
22733+
Result, Builder.CreateICmpEQ(ImpID, Builder.getInt64(CPUModel.MImpID)));
22734+
22735+
return Result;
22736+
}
22737+
2269622738
Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
2269722739
const CallExpr *E,
2269822740
ReturnValueSlot ReturnValue) {
@@ -22701,6 +22743,8 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
2270122743
return EmitRISCVCpuSupports(E);
2270222744
if (BuiltinID == Builtin::BI__builtin_cpu_init)
2270322745
return EmitRISCVCpuInit();
22746+
if (BuiltinID == Builtin::BI__builtin_cpu_is)
22747+
return EmitRISCVCpuIs(E);
2270422748

2270522749
SmallVector<Value *, 4> Ops;
2270622750
llvm::Type *ResultType = ConvertType(E->getType());

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4730,6 +4730,8 @@ class CodeGenFunction : public CodeGenTypeCache {
47304730
llvm::Value *EmitRISCVCpuSupports(const CallExpr *E);
47314731
llvm::Value *EmitRISCVCpuSupports(ArrayRef<StringRef> FeaturesStrs);
47324732
llvm::Value *EmitRISCVCpuInit();
4733+
llvm::Value *EmitRISCVCpuIs(const CallExpr *E);
4734+
llvm::Value *EmitRISCVCpuIs(StringRef CPUStr);
47334735

47344736
void AddAMDGPUFenceAddressSpaceMMRA(llvm::Instruction *Inst,
47354737
const CallExpr *E);
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// RUN: not %clang_cc1 -triple riscv64-unknown-linux-gnu -emit-llvm %s -o - 2>&1 \
2+
// RUN: | FileCheck %s
3+
4+
// CHECK: error: invalid cpu name for builtin
5+
int test_cpu_is_invalid_cpu() {
6+
return __builtin_cpu_is("generic-rv64");
7+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
2+
// RUN: %clang_cc1 -triple riscv64-unknown-linux-gnu -disable-O0-optnone -emit-llvm %s -o - \
3+
// RUN: | opt -S -passes=mem2reg | FileCheck %s --check-prefix=CHECK-RV64
4+
5+
// CHECK-RV64-LABEL: define dso_local signext i32 @test_cpu_is_veyron_v1(
6+
// CHECK-RV64-SAME: ) #[[ATTR0:[0-9]+]] {
7+
// CHECK-RV64-NEXT: [[ENTRY:.*:]]
8+
// CHECK-RV64-NEXT: [[TMP0:%.*]] = load i32, ptr @__riscv_cpu_model, align 4
9+
// CHECK-RV64-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 1567
10+
// CHECK-RV64-NEXT: [[TMP2:%.*]] = load i64, ptr getelementptr inbounds nuw ({ i32, i64, i64 }, ptr @__riscv_cpu_model, i32 0, i32 1), align 8
11+
// CHECK-RV64-NEXT: [[TMP3:%.*]] = icmp eq i64 [[TMP2]], -9223372036854710272
12+
// CHECK-RV64-NEXT: [[TMP4:%.*]] = and i1 [[TMP1]], [[TMP3]]
13+
// CHECK-RV64-NEXT: [[TMP5:%.*]] = load i64, ptr getelementptr inbounds nuw ({ i32, i64, i64 }, ptr @__riscv_cpu_model, i32 0, i32 2), align 8
14+
// CHECK-RV64-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 273
15+
// CHECK-RV64-NEXT: [[TMP7:%.*]] = and i1 [[TMP4]], [[TMP6]]
16+
// CHECK-RV64-NEXT: [[CONV:%.*]] = zext i1 [[TMP7]] to i32
17+
// CHECK-RV64-NEXT: ret i32 [[CONV]]
18+
//
19+
int test_cpu_is_veyron_v1() {
20+
return __builtin_cpu_is("veyron-v1");
21+
}
22+
23+
// CHECK-RV64-LABEL: define dso_local signext i32 @test_cpu_is_spacemit_x60(
24+
// CHECK-RV64-SAME: ) #[[ATTR0]] {
25+
// CHECK-RV64-NEXT: [[ENTRY:.*:]]
26+
// CHECK-RV64-NEXT: [[TMP0:%.*]] = load i32, ptr @__riscv_cpu_model, align 4
27+
// CHECK-RV64-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 1808
28+
// CHECK-RV64-NEXT: [[TMP2:%.*]] = load i64, ptr getelementptr inbounds nuw ({ i32, i64, i64 }, ptr @__riscv_cpu_model, i32 0, i32 1), align 8
29+
// CHECK-RV64-NEXT: [[TMP3:%.*]] = icmp eq i64 [[TMP2]], -9223372035378380799
30+
// CHECK-RV64-NEXT: [[TMP4:%.*]] = and i1 [[TMP1]], [[TMP3]]
31+
// CHECK-RV64-NEXT: [[TMP5:%.*]] = load i64, ptr getelementptr inbounds nuw ({ i32, i64, i64 }, ptr @__riscv_cpu_model, i32 0, i32 2), align 8
32+
// CHECK-RV64-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 1152921505839391232
33+
// CHECK-RV64-NEXT: [[TMP7:%.*]] = and i1 [[TMP4]], [[TMP6]]
34+
// CHECK-RV64-NEXT: [[CONV:%.*]] = zext i1 [[TMP7]] to i32
35+
// CHECK-RV64-NEXT: ret i32 [[CONV]]
36+
//
37+
int test_cpu_is_spacemit_x60() {
38+
return __builtin_cpu_is("spacemit-x60");
39+
}

llvm/include/llvm/TargetParser/RISCVTargetParser.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64);
6060
void fillValidTuneCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64);
6161
bool hasFastScalarUnalignedAccess(StringRef CPU);
6262
bool hasFastVectorUnalignedAccess(StringRef CPU);
63+
bool hasValidCPUModel(StringRef CPU);
64+
CPUModel getCPUModel(StringRef CPU);
6365

6466
} // namespace RISCV
6567

llvm/lib/TargetParser/RISCVTargetParser.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,19 @@ bool hasFastVectorUnalignedAccess(StringRef CPU) {
5757
return Info && Info->FastVectorUnalignedAccess;
5858
}
5959

60+
bool hasValidCPUModel(StringRef CPU) {
61+
const CPUModel CPUModel = getCPUModel(CPU);
62+
return CPUModel.MVendorID != 0 && CPUModel.MArchID != 0 &&
63+
CPUModel.MImpID != 0;
64+
}
65+
66+
CPUModel getCPUModel(StringRef CPU) {
67+
const CPUInfo *Info = getCPUInfoByName(CPU);
68+
if (!Info)
69+
return {0, 0, 0};
70+
return Info->CPUModel;
71+
}
72+
6073
bool parseCPU(StringRef CPU, bool IsRV64) {
6174
const CPUInfo *Info = getCPUInfoByName(CPU);
6275

0 commit comments

Comments
 (0)