[llvm-branch-commits] [RISCV] Support __builtin_cpu_is (PR #116231)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Nov 14 06:02:29 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-risc-v
Author: Pengcheng Wang (wangpc-pp)
<details>
<summary>Changes</summary>
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.
---
Full diff: https://github.com/llvm/llvm-project/pull/116231.diff
7 Files Affected:
- (modified) clang/lib/Basic/Targets/RISCV.cpp (+8)
- (modified) clang/lib/Basic/Targets/RISCV.h (+2)
- (modified) clang/lib/CodeGen/CGBuiltin.cpp (+54)
- (modified) clang/lib/CodeGen/CodeGenFunction.h (+2)
- (modified) clang/test/CodeGen/builtin-cpu-is.c (+110-1)
- (modified) llvm/include/llvm/TargetParser/RISCVTargetParser.h (+4)
- (modified) llvm/lib/TargetParser/RISCVTargetParser.cpp (+26)
``````````diff
diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp
index eaaba7642bd7b2..15e489a6a1288f 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -508,3 +508,11 @@ bool RISCVTargetInfo::validateGlobalRegisterVariable(
}
return false;
}
+
+bool RISCVTargetInfo::validateCpuIs(StringRef CPUName) const {
+ llvm::Triple Triple = getTriple();
+ assert(Triple.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 9e0c0bff0125c0..82e21d105fcc0e 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -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) {
+ llvm::Value *GEPIndices[] = {Builder.getInt32(0),
+ llvm::ConstantInt::get(Int32Ty, Index)};
+ Value *Ptr = Builder.CreateInBoundsGEP(StructTy, RISCVCPUModel, GEPIndices);
+ Value *CPUID = Builder.CreateAlignedLoad(
+ ValueTy, Ptr,
+ CharUnits::fromQuantity(ValueTy->getScalarSizeInBits() / 8));
+ 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.
+ 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());
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/builtin-cpu-is.c b/clang/test/CodeGen/builtin-cpu-is.c
index dab6d2f9d11aec..e4a2071cf46795 100644
--- a/clang/test/CodeGen/builtin-cpu-is.c
+++ b/clang/test/CodeGen/builtin-cpu-is.c
@@ -1,11 +1,26 @@
-// 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__
// 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");
@@ -14,6 +29,18 @@ void intel(void) {
// 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");
@@ -22,6 +49,18 @@ void amd(void) {
// 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");
@@ -30,6 +69,18 @@ void atom(void) {
// 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");
@@ -38,6 +89,18 @@ void amdfam10h(void) {
// 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");
@@ -46,6 +109,18 @@ void barcelona(void) {
// 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");
@@ -53,3 +128,37 @@ void nehalem(void) {
// 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
}
+#endif
+
+#ifdef __riscv
+// 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: [[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: br i1 [[TMP7]], label %[[IF_THEN:.*]], label %[[IF_END:.*]]
+// CHECK-RV64: [[IF_THEN]]:
+// CHECK-RV64-NEXT: store i32 3, ptr [[RETVAL]], align 4
+// CHECK-RV64-NEXT: br label %[[RETURN:.*]]
+// CHECK-RV64: [[IF_END]]:
+// CHECK-RV64-NEXT: store i32 0, ptr [[RETVAL]], align 4
+// CHECK-RV64-NEXT: br label %[[RETURN]]
+// CHECK-RV64: [[RETURN]]:
+// CHECK-RV64-NEXT: [[TMP8:%.*]] = load i32, ptr [[RETVAL]], align 4
+// CHECK-RV64-NEXT: ret i32 [[TMP8]]
+//
+int test_riscv(int a) {
+ if (__builtin_cpu_is("veyron-v1"))
+ return 3;
+ return 0;
+}
+#endif
diff --git a/llvm/include/llvm/TargetParser/RISCVTargetParser.h b/llvm/include/llvm/TargetParser/RISCVTargetParser.h
index c75778952e0f51..23a30425e95616 100644
--- a/llvm/include/llvm/TargetParser/RISCVTargetParser.h
+++ b/llvm/include/llvm/TargetParser/RISCVTargetParser.h
@@ -45,6 +45,10 @@ 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);
+uint32_t getVendorID(StringRef CPU);
+uint64_t getArchID(StringRef CPU);
+uint64_t getImplID(StringRef CPU);
} // namespace RISCV
diff --git a/llvm/lib/TargetParser/RISCVTargetParser.cpp b/llvm/lib/TargetParser/RISCVTargetParser.cpp
index 62fbd3458112e2..d62e1ba25cd94d 100644
--- a/llvm/lib/TargetParser/RISCVTargetParser.cpp
+++ b/llvm/lib/TargetParser/RISCVTargetParser.cpp
@@ -71,6 +71,32 @@ bool hasFastVectorUnalignedAccess(StringRef CPU) {
return Info && Info->FastVectorUnalignedAccess;
}
+bool hasValidCPUModel(StringRef CPU) {
+ const CPUInfo *Info = getCPUInfoByName(CPU);
+ return Info && Info->MVendorID && Info->MArchID && Info->MImpID;
+}
+
+uint32_t getVendorID(StringRef CPU) {
+ const CPUInfo *Info = getCPUInfoByName(CPU);
+ if (!Info)
+ return false;
+ return Info->MVendorID;
+}
+
+uint64_t getArchID(StringRef CPU) {
+ const CPUInfo *Info = getCPUInfoByName(CPU);
+ if (!Info)
+ return false;
+ return Info->MArchID;
+}
+
+uint64_t getImplID(StringRef CPU) {
+ const CPUInfo *Info = getCPUInfoByName(CPU);
+ if (!Info)
+ return false;
+ return Info->MImpID;
+}
+
bool parseCPU(StringRef CPU, bool IsRV64) {
const CPUInfo *Info = getCPUInfoByName(CPU);
``````````
</details>
https://github.com/llvm/llvm-project/pull/116231
More information about the llvm-branch-commits
mailing list