-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
[RISCV] Support __builtin_cpu_is #116231
Conversation
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1 [skip ci]
@llvm/pr-subscribers-backend-risc-v Author: Pengcheng Wang (wangpc-pp) ChangesWe have defined We can support This depends on #116202. Full diff: https://github.com/llvm/llvm-project/pull/116231.diff 7 Files Affected:
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);
|
@llvm/pr-subscribers-clang-codegen Author: Pengcheng Wang (wangpc-pp) ChangesWe have defined We can support This depends on #116202. Full diff: https://github.com/llvm/llvm-project/pull/116231.diff 7 Files Affected:
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);
|
@llvm/pr-subscribers-clang Author: Pengcheng Wang (wangpc-pp) ChangesWe have defined We can support This depends on #116202. Full diff: https://github.com/llvm/llvm-project/pull/116231.diff 7 Files Affected:
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);
|
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
clang/lib/CodeGen/CGBuiltin.cpp
Outdated
// 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)))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently we are using getVendorID
, getArchID
or getImplID
returning 0 to mean we have no IDs in LLVM for that CPU. On the CPU Core's side, the CSRs will also report 0 if they are not implemented (though I'm not sure what e.g. Linux reports to userspace in this case).
When we have no IDs, what comparisons should we be doing?
Maybe we should only support __builtin_cpu_is(...)
for CPUs where we have non-zero values for any of the three items? Otherwise either emit a compile-time error, or return false
because we don't have a way to actually know if we're on the CPU being asked for?
I don't know the right answer here, but I think this implementation isn't handling these cases right.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently this implementation just reports an error when there is no non-zero values in CPU definitions (done in validateCpuIs
). This should match PPC/X86. PPC supports CPUs with valid Linux_SUPPORT_METHOD
or AIX_SUPPORT_METHOD
value; X86 supports a set of defined CPUs.
Created using spr 1.3.6-beta.1 [skip ci]
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1 [skip ci]
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1 [skip ci]
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1 [skip ci]
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1 [skip ci]
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1 [skip ci]
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1 [skip ci]
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1 [skip ci]
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
Fails buildbot: https://lab.llvm.org/buildbot/#/builders/24/builds/2791/steps/10/logs/stdio
|
Thanks for reporting, it has been fixed now. |
We have defined
__riscv_cpu_model
variable in #101449. It containsmvendorid
,marchid
andmimpid
fields which are read via systemcall
sys_riscv_hwprobe
.We can support
__builtin_cpu_is
via comparing values in compiler'sCPU definitions and
__riscv_cpu_model
.This depends on #116202.