Skip to content
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

Merged
merged 26 commits into from
Jul 16, 2024

Conversation

dtcxzyw
Copy link
Member

@dtcxzyw dtcxzyw commented Jun 4, 2024

@tschuett
Copy link
Member

tschuett commented Jun 4, 2024

Do you offer an alternative/default implementation when __NR_riscv_hwprobe is not available, e.g., in docker containers?

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Jun 5, 2024

Do you offer an alternative/default implementation when __NR_riscv_hwprobe is not available, e.g., in docker containers?

Is /proc/cpuinfo available in containers? If so, I can provide a fallback implementation by reading the isa field from this file.

@cyyself
Copy link
Contributor

cyyself commented Jun 5, 2024

Do you offer an alternative/default implementation when __NR_riscv_hwprobe is not available, e.g., in docker containers?

Is /proc/cpuinfo available in containers? If so, I can provide a fallback implementation by reading the isa field from this file.

I think it is a bad idea. Some vendor custom kernels, such as t-head kernel, regard xtheadvector as v and printed in /proc/cpuinfo. A vast number of RISC-V devices still use these kernels.

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Jun 10, 2024

Ping.

@llvmbot llvmbot added clang Clang issues not falling into any other category backend:RISC-V clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' labels Jun 10, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Jun 10, 2024

@llvm/pr-subscribers-backend-risc-v
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-driver

Author: Yingwei Zheng (dtcxzyw)

Changes

This patch adds support for sys::getHostCPUFeatures using the RISC-V hardware probing interface.
References:

Co-authored-by: @cyyself


Full diff: https://github.com/llvm/llvm-project/pull/94352.diff

2 Files Affected:

  • (modified) clang/lib/Driver/ToolChains/Arch/RISCV.cpp (+7-1)
  • (modified) llvm/lib/TargetParser/Host.cpp (+69)
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))
Copy link
Contributor

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?

Copy link
Member Author

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.

Copy link
Collaborator

@topperc topperc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Jun 22, 2024

I have no idea about why it corrupts StringMap. Sad :(

image

Copy link

github-actions bot commented Jul 7, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Collaborator

@topperc topperc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Jul 13, 2024

I will rebase on the top of #97824.

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Jul 13, 2024

dtcxzyw@bananapif3:/data/llvm-build$ bin/clang -mcpu=native --print-enabled-extensions
clang version 19.0.0git
Target: riscv64-unknown-linux-gnu
Thread model: posix
InstalledDir: /data/llvm-build/bin
Build config: +assertions
Extensions enabled for the given RISC-V target

    Name                 Version   Description
    i                    2.1       'I' (Base Integer Instruction Set)
    m                    2.0       'M' (Integer Multiplication and Division)
    a                    2.1       'A' (Atomic Instructions)
    f                    2.2       'F' (Single-Precision Floating-Point)
    d                    2.2       'D' (Double-Precision Floating-Point)
    c                    2.0       'C' (Compressed Instructions)
    v                    1.0       'V' (Vector Extension for Application Processors)
    zicond               1.0       'Zicond' (Integer Conditional Operations)
    zicsr                2.0       'zicsr' (CSRs)
    zihintpause          2.0       'Zihintpause' (Pause Hint)
    zmmul                1.0       'Zmmul' (Integer Multiplication)
    zba                  1.0       'Zba' (Address Generation Instructions)
    zbb                  1.0       'Zbb' (Basic Bit-Manipulation)
    zbc                  1.0       'Zbc' (Carry-Less Multiplication)
    zbs                  1.0       'Zbs' (Single-Bit Instructions)
    zve32f               1.0       'Zve32f' (Vector Extensions for Embedded Processors with maximal 32 EEW and F extension)
    zve32x               1.0       'Zve32x' (Vector Extensions for Embedded Processors with maximal 32 EEW)
    zve64d               1.0       'Zve64d' (Vector Extensions for Embedded Processors with maximal 64 EEW, F and D extension)
    zve64f               1.0       'Zve64f' (Vector Extensions for Embedded Processors with maximal 64 EEW and F extension)
    zve64x               1.0       'Zve64x' (Vector Extensions for Embedded Processors with maximal 64 EEW)
    zvl128b              1.0       'Zvl' (Minimum Vector Length) 128
    zvl32b               1.0       'Zvl' (Minimum Vector Length) 32
    zvl64b               1.0       'Zvl' (Minimum Vector Length) 64

Experimental extensions

ISA String: rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_v1p0_zicond1p0_zicsr2p0_zihintpause2p0_zmmul1p0_zba1p0_zbb1p0_zbc1p0_zbs1p0_zve32f1p0_zve32x1p0_zve64d1p0_zve64f1p0_zve64x1p0_zvl128b1p0_zvl32b1p0_zvl64b1p0
dtcxzyw@bananapif3:/data/llvm-build$

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Jul 13, 2024

Ping @wangpc-pp @topperc @preames

aaryanshukla pushed a commit to aaryanshukla/llvm-project that referenced this pull request Jul 14, 2024
Copy link
Contributor

@wangpc-pp wangpc-pp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@dtcxzyw dtcxzyw merged commit 578cf72 into llvm:main Jul 16, 2024
8 checks passed
@dtcxzyw dtcxzyw deleted the rv-native-hwprobe branch July 16, 2024 02:11
yuxuanchen1997 pushed a commit that referenced this pull request Jul 25, 2024
Summary:
This patch adds support for `sys::getHostCPUFeatures` using the RISC-V
hardware probing interface.
References:
+ Loongarch patch:
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]>

Test Plan: 

Reviewers: 

Subscribers: 

Tasks: 

Tags: 


Differential Revision: https://phabricator.intern.facebook.com/D60251727
dtcxzyw added a commit that referenced this pull request Oct 5, 2024
This patch is the follow-up of
#94352 with some updates:
1. Add support for more extensions for `zve*`, `zimop`, `zc*`, `zcmop`
and `zawrs`.
2. Use `RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF` to check whether the
processor supports fast misaligned scalar memory access.
#108551 reminds me that the
patch
https://lore.kernel.org/all/[email protected]/T/
has been merged. Address comment
#94352 (comment).

References:
1. constants:
https://github.com/torvalds/linux/blame/v6.11-rc7/arch/riscv/include/uapi/asm/hwprobe.h
2. https://docs.kernel.org/arch/riscv/hwprobe.html
3. Related commits:
1. `zve*` support:
torvalds/linux@de8f828
2. `zimop` support:
torvalds/linux@36f8960
3. `zc*` support:
torvalds/linux@0ad70db
4. `zcmop` support:
torvalds/linux@fc078ea
5. `zawrs` support:
torvalds/linux@244c18f
6. scalar misaligned perf:
torvalds/linux@c42e2f0
and
torvalds/linux@1f52888
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:RISC-V clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants