[clang] c11b6b1 - [RISCV] Support __builtin_cpu_is

via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 22 04:05:00 PST 2024


Author: Pengcheng Wang
Date: 2024-11-22T20:04:57+08:00
New Revision: c11b6b1b8af7454b35eef342162dc2cddf54b4de

URL: https://github.com/llvm/llvm-project/commit/c11b6b1b8af7454b35eef342162dc2cddf54b4de
DIFF: https://github.com/llvm/llvm-project/commit/c11b6b1b8af7454b35eef342162dc2cddf54b4de.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
    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..caf5e40429838b 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 CPUModel = llvm::RISCV::getCPUModel(CPUStr);
+
+  // Compare mvendorid.
+  Value *VendorID = loadRISCVCPUID(0);
+  Value *Result =
+      Builder.CreateICmpEQ(VendorID, Builder.getInt32(CPUModel.MVendorID));
+
+  // Compare marchid.
+  Value *ArchID = loadRISCVCPUID(1);
+  Result = Builder.CreateAnd(
+      Result, Builder.CreateICmpEQ(ArchID, Builder.getInt64(CPUModel.MArchID)));
+
+  // Compare mimpid.
+  Value *ImpID = loadRISCVCPUID(2);
+  Result = Builder.CreateAnd(
+      Result, Builder.CreateICmpEQ(ImpID, Builder.getInt64(CPUModel.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/llvm/include/llvm/TargetParser/RISCVTargetParser.h b/llvm/include/llvm/TargetParser/RISCVTargetParser.h
index a365205ba2ecb6..71035dbe10e5e0 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..3442f74fb7f249 100644
--- a/llvm/lib/TargetParser/RISCVTargetParser.cpp
+++ b/llvm/lib/TargetParser/RISCVTargetParser.cpp
@@ -57,6 +57,19 @@ bool hasFastVectorUnalignedAccess(StringRef CPU) {
   return Info && Info->FastVectorUnalignedAccess;
 }
 
+bool hasValidCPUModel(StringRef CPU) {
+  const CPUModel CPUModel = getCPUModel(CPU);
+  return CPUModel.MVendorID != 0 && CPUModel.MArchID != 0 &&
+         CPUModel.MImpID != 0;
+}
+
+CPUModel getCPUModel(StringRef CPU) {
+  const CPUInfo *Info = getCPUInfoByName(CPU);
+  if (!Info)
+    return {0, 0, 0};
+  return Info->CPUModel;
+}
+
 bool parseCPU(StringRef CPU, bool IsRV64) {
   const CPUInfo *Info = getCPUInfoByName(CPU);
 


        


More information about the cfe-commits mailing list