[clang] [llvm] [WIP][RISCV] Support __builtin_cpu_init and __builtin_cpu_supports (PR #99700)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 19 13:28:19 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-codegen
Author: Philip Reames (preames)
<details>
<summary>Changes</summary>
This implements the __builtin_cpu_init and __builtin_cpu_supports builtin routines based on the compiler runtime changes in https://github.com/llvm/llvm-project/pull/85790.
This is inspired by https://github.com/llvm/llvm-project/pull/85786. Major changes are a) a restriction in scope to only the builtins (which have a much narrower user interface), and the avoidance of false generality. This change deliberately only handles group 0 extensions (which happen to be all defined ones today), and avoids the tblgen changes from that review.
This is still a WIP. It is posted for initial feedback on whether this makes sense to try to get into 19.x release. Major items left undone:
* Updating clang tests to exercise this logic.
* Actually running it at all. I did not build compiler-rt, and thus all my checking was of generated asm/IR.
* Investigate claims from gcc docs that __builtin_cpu_init is called early in process lifetime with high priority constructor. I did not find this with some quick searching.
---
Full diff: https://github.com/llvm/llvm-project/pull/99700.diff
6 Files Affected:
- (modified) clang/lib/Basic/Targets/RISCV.cpp (+6)
- (modified) clang/lib/Basic/Targets/RISCV.h (+4)
- (modified) clang/lib/CodeGen/CGBuiltin.cpp (+55)
- (modified) clang/lib/CodeGen/CodeGenFunction.h (+3)
- (modified) llvm/include/llvm/TargetParser/RISCVISAInfo.h (+4)
- (modified) llvm/lib/TargetParser/RISCVISAInfo.cpp (+61)
``````````diff
diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp
index 9159162f01d1b..41d836330b38c 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -479,3 +479,9 @@ RISCVTargetInfo::checkCallingConvention(CallingConv CC) const {
return CCCR_OK;
}
}
+
+bool RISCVTargetInfo::validateCpuSupports(StringRef Feature) const {
+ // Only allow extensions we have a known bit position for in the
+ // __riscv_feature_bits structure.
+ return -1 != llvm::RISCVISAInfo::getRISCVFeaturesBitPosition(Feature);
+}
diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h
index d5df6344bedc0..626274b8fc437 100644
--- a/clang/lib/Basic/Targets/RISCV.h
+++ b/clang/lib/Basic/Targets/RISCV.h
@@ -126,6 +126,10 @@ class RISCVTargetInfo : public TargetInfo {
std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
return std::make_pair(32, 32);
}
+
+ bool supportsCpuSupports() const override { return getTriple().isOSLinux(); }
+ bool supportsCpuInit() const override { return getTriple().isOSLinux(); }
+ bool validateCpuSupports(StringRef Feature) const override;
};
class LLVM_LIBRARY_VISIBILITY RISCV32TargetInfo : public RISCVTargetInfo {
public:
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 2ad62d6ee0bb2..71c947776adf2 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -62,6 +62,8 @@
#include "llvm/Support/MathExtras.h"
#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>
@@ -14215,6 +14217,16 @@ Value *CodeGenFunction::EmitAArch64CpuInit() {
return Builder.CreateCall(Func);
}
+Value *CodeGenFunction::EmitRISCVCpuInit() {
+ llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
+ llvm::FunctionCallee Func =
+ CGM.CreateRuntimeFunction(FTy, "__init_riscv_feature_bits");
+ auto *CalleeGV = cast<llvm::GlobalValue>(Func.getCallee());
+ CalleeGV->setDSOLocal(true);
+ CalleeGV->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
+ return Builder.CreateCall(Func);
+}
+
Value *CodeGenFunction::EmitX86CpuInit() {
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy,
/*Variadic*/ false);
@@ -14267,6 +14279,43 @@ CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) {
return Result;
}
+Value *CodeGenFunction::EmitRISCVCpuSupports(const CallExpr *E) {
+
+ const Expr *FeatureExpr = E->getArg(0)->IgnoreParenCasts();
+ StringRef FeatureStr = cast<StringLiteral>(FeatureExpr)->getString();
+ if (!getContext().getTargetInfo().validateCpuSupports(FeatureStr))
+ return Builder.getFalse();
+
+ // Note: We are making an unchecked assumption that the size of the
+ // feature array is >= 1. This holds for any version of compiler-rt
+ // which defines this interface.
+ llvm::ArrayType *ArrayOfInt64Ty =
+ llvm::ArrayType::get(Int64Ty, 1);
+ llvm::Type *StructTy = llvm::StructType::get(Int32Ty, ArrayOfInt64Ty);
+ llvm::Constant *RISCVFeaturesBits =
+ CGM.CreateRuntimeVariable(StructTy, "__riscv_feature_bits");
+ auto *GV = cast<llvm::GlobalValue>(RISCVFeaturesBits);
+ GV->setDSOLocal(true);
+
+ auto LoadFeatureBit = [&](unsigned Index) {
+ // Create GEP then load.
+ Value *IndexVal = llvm::ConstantInt::get(Int32Ty, Index);
+ llvm::Value *GEPIndices[] = {Builder.getInt32(0), Builder.getInt32(1),
+ IndexVal};
+ Value *Ptr =
+ Builder.CreateInBoundsGEP(StructTy, RISCVFeaturesBits, GEPIndices);
+ Value *FeaturesBit =
+ Builder.CreateAlignedLoad(Int64Ty, Ptr, CharUnits::fromQuantity(8));
+ return FeaturesBit;
+ };
+
+ int BitPos = RISCVISAInfo::getRISCVFeaturesBitPosition(FeatureStr);
+ assert(BitPos != -1 && "validation should have rejected this feature");
+ Value *MaskV = Builder.getInt64(1ULL << BitPos);
+ Value *Bitset = Builder.CreateAnd(LoadFeatureBit(0), MaskV);
+ return Builder.CreateICmpEQ(Bitset, MaskV);
+}
+
Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
if (BuiltinID == Builtin::BI__builtin_cpu_is)
@@ -21728,6 +21777,12 @@ Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID,
Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
const CallExpr *E,
ReturnValueSlot ReturnValue) {
+
+ if (BuiltinID == Builtin::BI__builtin_cpu_supports)
+ return EmitRISCVCpuSupports(E);
+ if (BuiltinID == Builtin::BI__builtin_cpu_init)
+ return EmitRISCVCpuInit();
+
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 d83e38cab8e2d..1ee45a1f1f99d 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4695,6 +4695,9 @@ class CodeGenFunction : public CodeGenTypeCache {
llvm::Value *EmitRISCVBuiltinExpr(unsigned BuiltinID, const CallExpr *E,
ReturnValueSlot ReturnValue);
+ llvm::Value *EmitRISCVCpuSupports(const CallExpr *E);
+ llvm::Value *EmitRISCVCpuInit();
+
void AddAMDGPUFenceAddressSpaceMMRA(llvm::Instruction *Inst,
const CallExpr *E);
void ProcessOrderScopeAMDGCN(llvm::Value *Order, llvm::Value *Scope,
diff --git a/llvm/include/llvm/TargetParser/RISCVISAInfo.h b/llvm/include/llvm/TargetParser/RISCVISAInfo.h
index d7a08013fa6ac..d71ff174bf0d2 100644
--- a/llvm/include/llvm/TargetParser/RISCVISAInfo.h
+++ b/llvm/include/llvm/TargetParser/RISCVISAInfo.h
@@ -80,6 +80,10 @@ class RISCVISAInfo {
std::set<StringRef> &EnabledFeatureNames,
StringMap<StringRef> &DescMap);
+ /// Return the bit position (in group 0) of __riscv_feature_bits. Returns
+ /// -1 if not supported.
+ static int getRISCVFeaturesBitPosition(StringRef Ext);
+
private:
RISCVISAInfo(unsigned XLen) : XLen(XLen) {}
diff --git a/llvm/lib/TargetParser/RISCVISAInfo.cpp b/llvm/lib/TargetParser/RISCVISAInfo.cpp
index e6ddbb4dc28d5..3ff1b325793e6 100644
--- a/llvm/lib/TargetParser/RISCVISAInfo.cpp
+++ b/llvm/lib/TargetParser/RISCVISAInfo.cpp
@@ -1020,3 +1020,64 @@ std::string RISCVISAInfo::getTargetFeatureForExtension(StringRef Ext) {
return isExperimentalExtension(Name) ? "experimental-" + Name.str()
: Name.str();
}
+
+struct RISCVExtBit {
+ const StringRef ext;
+ uint64_t bitpos;
+};
+
+/// Maps extensions with assigned bit positions within group 0 of
+/// __riscv_features_bits to their respective bit position. At the
+/// moment all extensions are within group 0.
+static RISCVExtBit RISCVGroup0BitPositions[] = {
+ {"a", 0},
+ {"c", 2},
+ {"d", 3},
+ {"f", 5},
+ {"i", 8},
+ {"m", 12},
+ {"v", 21},
+ {"zacas", 26},
+ {"zba", 27},
+ {"zbb", 28},
+ {"zbc", 29},
+ {"zbkb", 30},
+ {"zbkc", 31},
+ {"zbkx", 32},
+ {"zbs", 33},
+ {"zfa", 34},
+ {"zfh", 35},
+ {"zfhmin", 36},
+ {"zicboz", 37},
+ {"zicond", 38},
+ {"zihintntl", 39},
+ {"zihintpause", 40},
+ {"zknd", 41},
+ {"zkne", 42},
+ {"zknh", 43},
+ {"zksed", 44},
+ {"zksh", 45},
+ {"zkt", 46},
+ {"ztso", 47},
+ {"zvbb", 48},
+ {"zvbc", 49},
+ {"zvfh", 50},
+ {"zvfhmin", 51},
+ {"zvkb", 52},
+ {"zvkg", 53},
+ {"zvkned", 54},
+ {"zvknha", 55},
+ {"zvknhb", 56},
+ {"zvksed", 57},
+ {"zvksh", 58},
+ {"zvkt", 59}
+};
+int RISCVISAInfo::getRISCVFeaturesBitPosition(StringRef Ext) {
+ // Note that this code currently accepts mixed case extension names, but
+ // does not handle extension versions at all. That's probably fine because
+ // there's only one extension version in the __riscv_feature_bits vector.
+ for (auto E : RISCVGroup0BitPositions)
+ if (E.ext.equals_insensitive(Ext))
+ return E.bitpos;
+ return -1;
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/99700
More information about the llvm-commits
mailing list