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