[clang] 875b10f - [RISCV] Support __builtin_cpu_is
Wang Pengcheng via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 22 06:59:48 PST 2024
Author: Pengcheng Wang
Date: 2024-11-22T22:58:54+08:00
New Revision: 875b10f7d0888ca7e53f527f4c30531bd6b50bfb
URL: https://github.com/llvm/llvm-project/commit/875b10f7d0888ca7e53f527f4c30531bd6b50bfb
DIFF: https://github.com/llvm/llvm-project/commit/875b10f7d0888ca7e53f527f4c30531bd6b50bfb.diff
LOG: [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: https://github.com/llvm/llvm-project/pull/116231
Added:
clang/test/CodeGen/RISCV/builtin-cpu-is-error.c
clang/test/CodeGen/RISCV/builtin-cpu-is.c
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/Preprocessor/has_builtin_cpuid.c
llvm/include/llvm/TargetParser/RISCVTargetParser.h
llvm/lib/TargetParser/RISCVTargetParser.cpp
Removed:
################################################################################
diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp
index c61ee7ee203923..2384b322c50f92 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -512,3 +512,10 @@ bool RISCVTargetInfo::validateGlobalRegisterVariable(
}
return false;
}
+
+bool RISCVTargetInfo::validateCpuIs(StringRef CPUName) const {
+ assert(getTriple().isOSLinux() &&
+ "__builtin_cpu_is() is only supported for Linux.");
+
+ return llvm::RISCV::hasValidCPUModel(CPUName);
+}
diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h
index 3b418585ab4a39..3544ea64cb5e77 100644
--- a/clang/lib/Basic/Targets/RISCV.h
+++ b/clang/lib/Basic/Targets/RISCV.h
@@ -128,8 +128,10 @@ class RISCVTargetInfo : public TargetInfo {
}
bool supportsCpuSupports() const override { return getTriple().isOSLinux(); }
+ bool supportsCpuIs() const override { return getTriple().isOSLinux(); }
bool supportsCpuInit() const override { return getTriple().isOSLinux(); }
bool validateCpuSupports(StringRef Feature) const override;
+ bool validateCpuIs(StringRef CPUName) const override;
bool isValidFeatureName(StringRef Name) const override;
bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize,
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index ff7132fd8bc1e7..4b96bdb709c777 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -66,6 +66,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 <utility>
@@ -22693,6 +22694,47 @@ 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::StructType *StructTy = llvm::StructType::get(Int32Ty, Int64Ty, Int64Ty);
+ llvm::Constant *RISCVCPUModel =
+ CGM.CreateRuntimeVariable(StructTy, "__riscv_cpu_model");
+ cast<llvm::GlobalValue>(RISCVCPUModel)->setDSOLocal(true);
+
+ auto loadRISCVCPUID = [&](unsigned Index) {
+ Value *Ptr = Builder.CreateStructGEP(StructTy, RISCVCPUModel, Index);
+ Value *CPUID = Builder.CreateAlignedLoad(StructTy->getTypeAtIndex(Index),
+ Ptr, llvm::MaybeAlign());
+ return CPUID;
+ };
+
+ const llvm::RISCV::CPUModel Model = llvm::RISCV::getCPUModel(CPUStr);
+
+ // Compare mvendorid.
+ Value *VendorID = loadRISCVCPUID(0);
+ Value *Result =
+ Builder.CreateICmpEQ(VendorID, Builder.getInt32(Model.MVendorID));
+
+ // Compare marchid.
+ Value *ArchID = loadRISCVCPUID(1);
+ Result = Builder.CreateAnd(
+ Result, Builder.CreateICmpEQ(ArchID, Builder.getInt64(Model.MArchID)));
+
+ // Compare mimpid.
+ Value *ImpID = loadRISCVCPUID(2);
+ Result = Builder.CreateAnd(
+ Result, Builder.CreateICmpEQ(ImpID, Builder.getInt64(Model.MImpID)));
+
+ return Result;
+}
+
Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
const CallExpr *E,
ReturnValueSlot ReturnValue) {
@@ -22701,6 +22743,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());
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index fcc1013d7361ec..5c4d76c2267a77 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4730,6 +4730,8 @@ class CodeGenFunction : public CodeGenTypeCache {
llvm::Value *EmitRISCVCpuSupports(const CallExpr *E);
llvm::Value *EmitRISCVCpuSupports(ArrayRef<StringRef> FeaturesStrs);
llvm::Value *EmitRISCVCpuInit();
+ llvm::Value *EmitRISCVCpuIs(const CallExpr *E);
+ llvm::Value *EmitRISCVCpuIs(StringRef CPUStr);
void AddAMDGPUFenceAddressSpaceMMRA(llvm::Instruction *Inst,
const CallExpr *E);
diff --git a/clang/test/CodeGen/RISCV/builtin-cpu-is-error.c b/clang/test/CodeGen/RISCV/builtin-cpu-is-error.c
new file mode 100644
index 00000000000000..ce5e1420f7f456
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/builtin-cpu-is-error.c
@@ -0,0 +1,7 @@
+// RUN: not %clang_cc1 -triple riscv64-unknown-linux-gnu -emit-llvm %s -o - 2>&1 \
+// RUN: | FileCheck %s
+
+// CHECK: error: invalid cpu name for builtin
+int test_cpu_is_invalid_cpu() {
+ return __builtin_cpu_is("generic-rv64");
+}
diff --git a/clang/test/CodeGen/RISCV/builtin-cpu-is.c b/clang/test/CodeGen/RISCV/builtin-cpu-is.c
new file mode 100644
index 00000000000000..3cb3558a751ae3
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/builtin-cpu-is.c
@@ -0,0 +1,39 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -triple riscv64-unknown-linux-gnu -disable-O0-optnone -emit-llvm %s -o - \
+// RUN: | opt -S -passes=mem2reg | FileCheck %s --check-prefix=CHECK-RV64
+
+// 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 nuw ({ 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 nuw ({ 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");
+}
+
+// CHECK-RV64-LABEL: define dso_local signext i32 @test_cpu_is_spacemit_x60(
+// CHECK-RV64-SAME: ) #[[ATTR0]] {
+// CHECK-RV64-NEXT: [[ENTRY:.*:]]
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = load i32, ptr @__riscv_cpu_model, align 4
+// CHECK-RV64-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 1808
+// CHECK-RV64-NEXT: [[TMP2:%.*]] = load i64, ptr getelementptr inbounds nuw ({ i32, i64, i64 }, ptr @__riscv_cpu_model, i32 0, i32 1), align 8
+// CHECK-RV64-NEXT: [[TMP3:%.*]] = icmp eq i64 [[TMP2]], -9223372035378380799
+// CHECK-RV64-NEXT: [[TMP4:%.*]] = and i1 [[TMP1]], [[TMP3]]
+// CHECK-RV64-NEXT: [[TMP5:%.*]] = load i64, ptr getelementptr inbounds nuw ({ i32, i64, i64 }, ptr @__riscv_cpu_model, i32 0, i32 2), align 8
+// CHECK-RV64-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 1152921505839391232
+// 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_spacemit_x60() {
+ return __builtin_cpu_is("spacemit-x60");
+}
diff --git a/clang/test/Preprocessor/has_builtin_cpuid.c b/clang/test/Preprocessor/has_builtin_cpuid.c
index e69f912ce688dd..86cbc6d378a074 100644
--- a/clang/test/Preprocessor/has_builtin_cpuid.c
+++ b/clang/test/Preprocessor/has_builtin_cpuid.c
@@ -8,8 +8,8 @@
// RUN: -verify %s
// expected-no-diagnostics
#if __has_builtin(__builtin_cpu_is)
-# if defined(ARM) || defined(RISCV)
-# error "ARM/RISCV shouldn't have __builtin_cpu_is"
+# if defined(ARM)
+# error "ARM shouldn't have __builtin_cpu_is"
# endif
#endif
diff --git a/llvm/include/llvm/TargetParser/RISCVTargetParser.h b/llvm/include/llvm/TargetParser/RISCVTargetParser.h
index 4a0a602fd80e20..c237e1ddd6b381 100644
--- a/llvm/include/llvm/TargetParser/RISCVTargetParser.h
+++ b/llvm/include/llvm/TargetParser/RISCVTargetParser.h
@@ -60,6 +60,8 @@ void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64);
void fillValidTuneCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64);
bool hasFastScalarUnalignedAccess(StringRef CPU);
bool hasFastVectorUnalignedAccess(StringRef CPU);
+bool hasValidCPUModel(StringRef CPU);
+CPUModel getCPUModel(StringRef CPU);
} // namespace RISCV
diff --git a/llvm/lib/TargetParser/RISCVTargetParser.cpp b/llvm/lib/TargetParser/RISCVTargetParser.cpp
index f4d09d1e302408..625645a99e12fc 100644
--- a/llvm/lib/TargetParser/RISCVTargetParser.cpp
+++ b/llvm/lib/TargetParser/RISCVTargetParser.cpp
@@ -57,6 +57,18 @@ bool hasFastVectorUnalignedAccess(StringRef CPU) {
return Info && Info->FastVectorUnalignedAccess;
}
+bool hasValidCPUModel(StringRef CPU) {
+ const CPUModel Model = getCPUModel(CPU);
+ return Model.MVendorID != 0 && Model.MArchID != 0 && Model.MImpID != 0;
+}
+
+CPUModel getCPUModel(StringRef CPU) {
+ const CPUInfo *Info = getCPUInfoByName(CPU);
+ if (!Info)
+ return {0, 0, 0};
+ return Info->Model;
+}
+
bool parseCPU(StringRef CPU, bool IsRV64) {
const CPUInfo *Info = getCPUInfoByName(CPU);
More information about the cfe-commits
mailing list