-
Notifications
You must be signed in to change notification settings - Fork 11k
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] Add support for getHostCPUFeatures using hwprobe #94352
base: main
Are you sure you want to change the base?
Conversation
Co-authored-by: Yangyu Chen <cyy@cyyself.name>
Do you offer an alternative/default implementation when __NR_riscv_hwprobe is not available, e.g., in docker containers? |
Is |
I think it is a bad idea. Some vendor custom kernels, such as t-head kernel, regard |
Ping. |
@llvm/pr-subscribers-backend-risc-v @llvm/pr-subscribers-clang-driver Author: Yingwei Zheng (dtcxzyw) ChangesThis patch adds support for
Co-authored-by: @cyyself Full diff: https://github.com/llvm/llvm-project/pull/94352.diff 2 Files Affected:
diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
index 2e2bce8494672..bf34b6e3f2ea4 100644
--- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
@@ -86,8 +86,14 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
// and other features (ex. mirco architecture feature) from mcpu
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
StringRef CPU = A->getValue();
- if (CPU == "native")
+ if (CPU == "native") {
CPU = llvm::sys::getHostCPUName();
+ llvm::StringMap<bool> HostFeatures;
+ if (llvm::sys::getHostCPUFeatures(HostFeatures))
+ for (auto &F : HostFeatures)
+ Features.push_back(
+ Args.MakeArgString((F.second ? "+" : "-") + F.first()));
+ }
getRISCFeaturesFromMcpu(D, A, Triple, CPU, Features);
}
diff --git a/llvm/lib/TargetParser/Host.cpp b/llvm/lib/TargetParser/Host.cpp
index 68155acd9e5bc..b99e1443ef5e5 100644
--- a/llvm/lib/TargetParser/Host.cpp
+++ b/llvm/lib/TargetParser/Host.cpp
@@ -1998,6 +1998,75 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
return true;
}
+#elif defined(__linux__) && defined(__riscv)
+// struct riscv_hwprobe
+struct RISCVHwProbe {
+ int64_t Key;
+ uint64_t Value;
+};
+bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
+ RISCVHwProbe Query[]{{/*RISCV_HWPROBE_KEY_BASE_BEHAVIOR=*/3, 0},
+ {/*RISCV_HWPROBE_KEY_IMA_EXT_0=*/4, 0}};
+ int Ret = syscall(/*__NR_riscv_hwprobe=*/258, /*pairs=*/Query,
+ /*pair_count=*/std::size(Query), /*cpu_count=*/0,
+ /*cpus=*/0, /*flags=*/0);
+ if (Ret != 0)
+ return false;
+
+ uint64_t BaseMask = Query[0].Value;
+ // Check whether RISCV_HWPROBE_BASE_BEHAVIOR_IMA is set.
+ if (BaseMask & 1) {
+ Features["i"] = true;
+ Features["m"] = true;
+ Features["a"] = true;
+ }
+
+ uint64_t ExtMask = Query[1].Value;
+ Features["f"] = ExtMask & (1 << 0); // RISCV_HWPROBE_IMA_FD
+ Features["d"] = ExtMask & (1 << 0); // RISCV_HWPROBE_IMA_FD
+ Features["c"] = ExtMask & (1 << 1); // RISCV_HWPROBE_IMA_C
+ Features["v"] = ExtMask & (1 << 2); // RISCV_HWPROBE_IMA_V
+ Features["zba"] = ExtMask & (1 << 3); // RISCV_HWPROBE_EXT_ZBA
+ Features["zbb"] = ExtMask & (1 << 4); // RISCV_HWPROBE_EXT_ZBB
+ Features["zbs"] = ExtMask & (1 << 5); // RISCV_HWPROBE_EXT_ZBS
+ Features["zicboz"] = ExtMask & (1 << 6); // RISCV_HWPROBE_EXT_ZICBOZ
+ Features["zbc"] = ExtMask & (1 << 7); // RISCV_HWPROBE_EXT_ZBC
+ Features["zbkb"] = ExtMask & (1 << 8); // RISCV_HWPROBE_EXT_ZBKB
+ Features["zbkc"] = ExtMask & (1 << 9); // RISCV_HWPROBE_EXT_ZBKC
+ Features["zbkx"] = ExtMask & (1 << 10); // RISCV_HWPROBE_EXT_ZBKX
+ Features["zknd"] = ExtMask & (1 << 11); // RISCV_HWPROBE_EXT_ZKND
+ Features["zkne"] = ExtMask & (1 << 12); // RISCV_HWPROBE_EXT_ZKNE
+ Features["zknh"] = ExtMask & (1 << 13); // RISCV_HWPROBE_EXT_ZKNH
+ Features["zksed"] = ExtMask & (1 << 14); // RISCV_HWPROBE_EXT_ZKSED
+ Features["zksh"] = ExtMask & (1 << 15); // RISCV_HWPROBE_EXT_ZKSH
+ Features["zkt"] = ExtMask & (1 << 16); // RISCV_HWPROBE_EXT_ZKT
+ Features["zvbb"] = ExtMask & (1 << 17); // RISCV_HWPROBE_EXT_ZVBB
+ Features["zvbc"] = ExtMask & (1 << 18); // RISCV_HWPROBE_EXT_ZVBC
+ Features["zvkb"] = ExtMask & (1 << 19); // RISCV_HWPROBE_EXT_ZVKB
+ Features["zvkg"] = ExtMask & (1 << 20); // RISCV_HWPROBE_EXT_ZVKG
+ Features["zvkned"] = ExtMask & (1 << 21); // RISCV_HWPROBE_EXT_ZVKNED
+ Features["zvknha"] = ExtMask & (1 << 22); // RISCV_HWPROBE_EXT_ZVKNHA
+ Features["zvknhb"] = ExtMask & (1 << 23); // RISCV_HWPROBE_EXT_ZVKNHB
+ Features["zvksed"] = ExtMask & (1 << 24); // RISCV_HWPROBE_EXT_ZVKSED
+ Features["zvksh"] = ExtMask & (1 << 25); // RISCV_HWPROBE_EXT_ZVKSH
+ Features["zvkt"] = ExtMask & (1 << 26); // RISCV_HWPROBE_EXT_ZVKT
+ Features["zfh"] = ExtMask & (1 << 27); // RISCV_HWPROBE_EXT_ZFH
+ Features["zfhmin"] = ExtMask & (1 << 28); // RISCV_HWPROBE_EXT_ZFHMIN
+ Features["zihintntl"] = ExtMask & (1 << 29); // RISCV_HWPROBE_EXT_ZIHINTNTL
+ Features["zvfh"] = ExtMask & (1 << 30); // RISCV_HWPROBE_EXT_ZVFH
+ Features["zvfhmin"] = ExtMask & (1ULL << 31); // RISCV_HWPROBE_EXT_ZVFHMIN
+ Features["zfa"] = ExtMask & (1ULL << 32); // RISCV_HWPROBE_EXT_ZFA
+ Features["ztso"] = ExtMask & (1ULL << 33); // RISCV_HWPROBE_EXT_ZTSO
+ Features["zacas"] = ExtMask & (1ULL << 34); // RISCV_HWPROBE_EXT_ZACAS
+ Features["zicond"] = ExtMask & (1ULL << 35); // RISCV_HWPROBE_EXT_ZICOND
+ Features["zihintpause"] =
+ ExtMask & (1ULL << 36); // RISCV_HWPROBE_EXT_ZIHINTPAUSE
+
+ // TODO: set unaligned-scalar-mem if RISCV_HWPROBE_KEY_MISALIGNED_PERF returns
+ // RISCV_HWPROBE_MISALIGNED_FAST.
+
+ return true;
+}
#else
bool sys::getHostCPUFeatures(StringMap<bool> &Features) { return false; }
#endif
|
CPU = llvm::sys::getHostCPUName(); | ||
llvm::StringMap<bool> HostFeatures; | ||
if (llvm::sys::getHostCPUFeatures(HostFeatures)) |
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.
Open discussion here: CPU
may fail and return generic
. Should we failback to use getHostCPUFeatures
if getHostCPUName
fails? Or we should use getHostCPUFeatures
all the time?
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.
I think hwprobe is more reliable than cpu name because some RV cpus are not recognized by LLVM (e.g., T-head's cores). However, cpu name is still useful even if getHostCPUFeatures
returns true because it may provide scheduling model.
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.
LGTM
See #96465 |
Any thoughts? Hopefully I can catch up with the 19 release :) |
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.
LGTM
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.
LGTM w/minor comments
bool sys::getHostCPUFeatures(StringMap<bool> &Features) { | ||
RISCVHwProbe Query[]{{/*RISCV_HWPROBE_KEY_BASE_BEHAVIOR=*/3, 0}, | ||
{/*RISCV_HWPROBE_KEY_IMA_EXT_0=*/4, 0}}; | ||
int Ret = syscall(/*__NR_riscv_hwprobe=*/258, /*pairs=*/Query, |
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.
Consider this a purely stylistic comment.
We should probably be using either the vDSO symbol or the glibc shim. In either case, we'd have a weak symbol which could possibly be nullptr, and need to return early.
In this use case, the difference likely doesn't matter, but if we reuse this code, the lack of caching provided by vDSO could be problematic.
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 sys::getHostCPUFeatures
has three callers:
- clang ->
riscv::getRISCVTargetFeatures
- llvm-tools ->
codegen::getFeaturesStr
- JIT users ->
JITTargetMachineBuilder::detectHost
I don't think there are any opportunities to reuse the result.
BTW, #85790 may benefit from the vDSO symbol, but it implements caching itself.
I didn't use the glibc call __riscv_hwprobe
since sys/hwprobe.h
was unavailable on my RV board :(
for (auto &F : HostFeatures) | ||
Features.push_back( | ||
Args.MakeArgString((F.second ? "+" : "-") + F.first())); | ||
} |
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.
Do we also need to update riscv::getRISCVArch? There's analogous logic there for getting features from mcpu native.
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.
@wangpc-pp @topperc
Are there any equivalents of the helper printMArch
?
llvm-project/llvm/utils/TableGen/RISCVTargetDefEmitter.cpp
Lines 90 to 123 in ba60d8a
// We can generate march string from target features as what has been described | |
// in RISC-V ISA specification (version 20191213) 'Chapter 27. ISA Extension | |
// Naming Conventions'. | |
// | |
// This is almost the same as RISCVFeatures::parseFeatureBits, except that we | |
// get feature name from feature records instead of feature bits. | |
static void printMArch(raw_ostream &OS, const std::vector<Record *> &Features) { | |
RISCVISAUtils::OrderedExtensionMap Extensions; | |
unsigned XLen = 0; | |
// Convert features to FeatureVector. | |
for (auto *Feature : Features) { | |
StringRef FeatureName = getExtensionName(Feature); | |
if (Feature->isSubClassOf("RISCVExtension")) { | |
unsigned Major = Feature->getValueAsInt("MajorVersion"); | |
unsigned Minor = Feature->getValueAsInt("MinorVersion"); | |
Extensions[FeatureName.str()] = {Major, Minor}; | |
} else if (FeatureName == "64bit") { | |
assert(XLen == 0 && "Already determined XLen"); | |
XLen = 64; | |
} else if (FeatureName == "32bit") { | |
assert(XLen == 0 && "Already determined XLen"); | |
XLen = 32; | |
} | |
} | |
assert(XLen != 0 && "Unable to determine XLen"); | |
OS << "rv" << XLen; | |
ListSeparator LS("_"); | |
for (auto const &Ext : Extensions) | |
OS << LS << Ext.first << Ext.second.Major << 'p' << Ext.second.Minor; | |
} |
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.
@wangpc-pp @topperc Are there any equivalents of the helper
printMArch
?
No, I think there isn't. You may need to write a helper via RISCVISAInfo::parseFeatures
and RISCVISAInfo::toString()
.
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.
Done.
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.
See
llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
Lines 72 to 78 in 0f5fa35
void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, | |
const ArgList &Args, | |
std::vector<StringRef> &Features) { | |
StringRef MArch = getRISCVArch(Args, Triple); | |
if (!getArchFeatures(D, MArch, Features, Args)) | |
return; |
This reverts commit 7563384.
✅ With the latest revision this PR passed the C/C++ code formatter. |
…`. NFC. (#97965) See the discussion in #94352 (comment)
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.
LGTM
I will rebase on the top of #97824. |
|
Ping @wangpc-pp @topperc @preames |
This patch adds support for
sys::getHostCPUFeatures
using the RISC-V hardware probing interface.References:
Co-authored-by: @cyyself