Skip to content

Commit 578cf72

Browse files
dtcxzywcyyself
andauthored
[RISCV] Add support for getHostCPUFeatures using hwprobe (llvm#94352)
This patch adds support for `sys::getHostCPUFeatures` using the RISC-V hardware probing interface. References: + Loongarch patch: llvm@e53f41c + asm/hwprobe.h: https://github.com/torvalds/linux/blob/2ab79514109578fc4b6df90633d500cf281eb689/arch/riscv/include/uapi/asm/hwprobe.h + glibc support: https://inbox.sourceware.org/glibc-cvs/[email protected]/T/#Z2e.:..:20240301151728.AD5963858C53::40sourceware.org:1sysdeps:unix:sysv:linux:riscv:sys:hwprobe.h + __NR_riscv_hwprobe syscall tutorial: https://github.com/cyyself/hwprobe + hwprobe docs: https://docs.kernel.org/arch/riscv/hwprobe.html --------- Co-authored-by: Yangyu Chen <[email protected]>
1 parent bddab51 commit 578cf72

File tree

3 files changed

+93
-5
lines changed

3 files changed

+93
-5
lines changed

clang/lib/Driver/ToolChains/Arch/RISCV.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,24 @@ std::string riscv::getRISCVArch(const llvm::opt::ArgList &Args,
310310
// 2. Get march (isa string) based on `-mcpu=`
311311
if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
312312
StringRef CPU = A->getValue();
313-
if (CPU == "native")
313+
if (CPU == "native") {
314314
CPU = llvm::sys::getHostCPUName();
315+
// If the target cpu is unrecognized, use target features.
316+
if (CPU.starts_with("generic")) {
317+
auto FeatureMap = llvm::sys::getHostCPUFeatures();
318+
// hwprobe may be unavailable on older Linux versions.
319+
if (!FeatureMap.empty()) {
320+
std::vector<std::string> Features;
321+
for (auto &F : FeatureMap)
322+
Features.push_back(((F.second ? "+" : "-") + F.first()).str());
323+
auto ParseResult = llvm::RISCVISAInfo::parseFeatures(
324+
Triple.isRISCV32() ? 32 : 64, Features);
325+
if (ParseResult)
326+
return (*ParseResult)->toString();
327+
}
328+
}
329+
}
330+
315331
StringRef MArch = llvm::RISCV::getMArchFromMcpu(CPU);
316332
// Bypass if target cpu's default march is empty.
317333
if (MArch != "")

llvm/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ Changes to the RISC-V Backend
203203
* Ztso is no longer experimental.
204204
* The WCH / Nanjing Qinheng Microelectronics QingKe "XW" compressed opcodes are
205205
supported under the name "Xwchc".
206+
* ``-mcpu=native`` now detects available features with hwprobe (RISC-V Hardware Probing Interface) on Linux 6.4 or later.
206207

207208
Changes to the WebAssembly Backend
208209
----------------------------------

llvm/lib/TargetParser/Host.cpp

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ StringRef sys::detail::getHostCPUNameForRISCV(StringRef ProcCpuinfoContent) {
452452
return StringSwitch<const char *>(UArch)
453453
.Case("sifive,u74-mc", "sifive-u74")
454454
.Case("sifive,bullet0", "sifive-u74")
455-
.Default("generic");
455+
.Default("");
456456
}
457457

458458
StringRef sys::detail::getHostCPUNameForBPF() {
@@ -1573,16 +1573,17 @@ StringRef sys::getHostCPUName() {
15731573
#if defined(__linux__)
15741574
std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent();
15751575
StringRef Content = P ? P->getBuffer() : "";
1576-
return detail::getHostCPUNameForRISCV(Content);
1577-
#else
1576+
StringRef Name = detail::getHostCPUNameForRISCV(Content);
1577+
if (!Name.empty())
1578+
return Name;
1579+
#endif
15781580
#if __riscv_xlen == 64
15791581
return "generic-rv64";
15801582
#elif __riscv_xlen == 32
15811583
return "generic-rv32";
15821584
#else
15831585
#error "Unhandled value of __riscv_xlen"
15841586
#endif
1585-
#endif
15861587
}
15871588
#elif defined(__sparc__)
15881589
#if defined(__linux__)
@@ -2006,6 +2007,76 @@ const StringMap<bool> sys::getHostCPUFeatures() {
20062007

20072008
return Features;
20082009
}
2010+
#elif defined(__linux__) && defined(__riscv)
2011+
// struct riscv_hwprobe
2012+
struct RISCVHwProbe {
2013+
int64_t Key;
2014+
uint64_t Value;
2015+
};
2016+
const StringMap<bool> sys::getHostCPUFeatures() {
2017+
RISCVHwProbe Query[]{{/*RISCV_HWPROBE_KEY_BASE_BEHAVIOR=*/3, 0},
2018+
{/*RISCV_HWPROBE_KEY_IMA_EXT_0=*/4, 0}};
2019+
int Ret = syscall(/*__NR_riscv_hwprobe=*/258, /*pairs=*/Query,
2020+
/*pair_count=*/std::size(Query), /*cpu_count=*/0,
2021+
/*cpus=*/0, /*flags=*/0);
2022+
if (Ret != 0)
2023+
return {};
2024+
2025+
StringMap<bool> Features;
2026+
uint64_t BaseMask = Query[0].Value;
2027+
// Check whether RISCV_HWPROBE_BASE_BEHAVIOR_IMA is set.
2028+
if (BaseMask & 1) {
2029+
Features["i"] = true;
2030+
Features["m"] = true;
2031+
Features["a"] = true;
2032+
}
2033+
2034+
uint64_t ExtMask = Query[1].Value;
2035+
Features["f"] = ExtMask & (1 << 0); // RISCV_HWPROBE_IMA_FD
2036+
Features["d"] = ExtMask & (1 << 0); // RISCV_HWPROBE_IMA_FD
2037+
Features["c"] = ExtMask & (1 << 1); // RISCV_HWPROBE_IMA_C
2038+
Features["v"] = ExtMask & (1 << 2); // RISCV_HWPROBE_IMA_V
2039+
Features["zba"] = ExtMask & (1 << 3); // RISCV_HWPROBE_EXT_ZBA
2040+
Features["zbb"] = ExtMask & (1 << 4); // RISCV_HWPROBE_EXT_ZBB
2041+
Features["zbs"] = ExtMask & (1 << 5); // RISCV_HWPROBE_EXT_ZBS
2042+
Features["zicboz"] = ExtMask & (1 << 6); // RISCV_HWPROBE_EXT_ZICBOZ
2043+
Features["zbc"] = ExtMask & (1 << 7); // RISCV_HWPROBE_EXT_ZBC
2044+
Features["zbkb"] = ExtMask & (1 << 8); // RISCV_HWPROBE_EXT_ZBKB
2045+
Features["zbkc"] = ExtMask & (1 << 9); // RISCV_HWPROBE_EXT_ZBKC
2046+
Features["zbkx"] = ExtMask & (1 << 10); // RISCV_HWPROBE_EXT_ZBKX
2047+
Features["zknd"] = ExtMask & (1 << 11); // RISCV_HWPROBE_EXT_ZKND
2048+
Features["zkne"] = ExtMask & (1 << 12); // RISCV_HWPROBE_EXT_ZKNE
2049+
Features["zknh"] = ExtMask & (1 << 13); // RISCV_HWPROBE_EXT_ZKNH
2050+
Features["zksed"] = ExtMask & (1 << 14); // RISCV_HWPROBE_EXT_ZKSED
2051+
Features["zksh"] = ExtMask & (1 << 15); // RISCV_HWPROBE_EXT_ZKSH
2052+
Features["zkt"] = ExtMask & (1 << 16); // RISCV_HWPROBE_EXT_ZKT
2053+
Features["zvbb"] = ExtMask & (1 << 17); // RISCV_HWPROBE_EXT_ZVBB
2054+
Features["zvbc"] = ExtMask & (1 << 18); // RISCV_HWPROBE_EXT_ZVBC
2055+
Features["zvkb"] = ExtMask & (1 << 19); // RISCV_HWPROBE_EXT_ZVKB
2056+
Features["zvkg"] = ExtMask & (1 << 20); // RISCV_HWPROBE_EXT_ZVKG
2057+
Features["zvkned"] = ExtMask & (1 << 21); // RISCV_HWPROBE_EXT_ZVKNED
2058+
Features["zvknha"] = ExtMask & (1 << 22); // RISCV_HWPROBE_EXT_ZVKNHA
2059+
Features["zvknhb"] = ExtMask & (1 << 23); // RISCV_HWPROBE_EXT_ZVKNHB
2060+
Features["zvksed"] = ExtMask & (1 << 24); // RISCV_HWPROBE_EXT_ZVKSED
2061+
Features["zvksh"] = ExtMask & (1 << 25); // RISCV_HWPROBE_EXT_ZVKSH
2062+
Features["zvkt"] = ExtMask & (1 << 26); // RISCV_HWPROBE_EXT_ZVKT
2063+
Features["zfh"] = ExtMask & (1 << 27); // RISCV_HWPROBE_EXT_ZFH
2064+
Features["zfhmin"] = ExtMask & (1 << 28); // RISCV_HWPROBE_EXT_ZFHMIN
2065+
Features["zihintntl"] = ExtMask & (1 << 29); // RISCV_HWPROBE_EXT_ZIHINTNTL
2066+
Features["zvfh"] = ExtMask & (1 << 30); // RISCV_HWPROBE_EXT_ZVFH
2067+
Features["zvfhmin"] = ExtMask & (1ULL << 31); // RISCV_HWPROBE_EXT_ZVFHMIN
2068+
Features["zfa"] = ExtMask & (1ULL << 32); // RISCV_HWPROBE_EXT_ZFA
2069+
Features["ztso"] = ExtMask & (1ULL << 33); // RISCV_HWPROBE_EXT_ZTSO
2070+
Features["zacas"] = ExtMask & (1ULL << 34); // RISCV_HWPROBE_EXT_ZACAS
2071+
Features["zicond"] = ExtMask & (1ULL << 35); // RISCV_HWPROBE_EXT_ZICOND
2072+
Features["zihintpause"] =
2073+
ExtMask & (1ULL << 36); // RISCV_HWPROBE_EXT_ZIHINTPAUSE
2074+
2075+
// TODO: set unaligned-scalar-mem if RISCV_HWPROBE_KEY_MISALIGNED_PERF returns
2076+
// RISCV_HWPROBE_MISALIGNED_FAST.
2077+
2078+
return Features;
2079+
}
20092080
#else
20102081
const StringMap<bool> sys::getHostCPUFeatures() { return {}; }
20112082
#endif

0 commit comments

Comments
 (0)