Skip to content

Commit f4513d5

Browse files
authored
RISC-V feature and detect macro (#1263)
1 parent 43b4556 commit f4513d5

File tree

9 files changed

+365
-4
lines changed

9 files changed

+365
-4
lines changed

crates/simd-test-macro/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ pub fn simd_test(
6464
"i686" | "x86_64" | "i586" => "is_x86_feature_detected",
6565
"arm" | "armv7" => "is_arm_feature_detected",
6666
"aarch64" => "is_aarch64_feature_detected",
67+
maybe_riscv if maybe_riscv.starts_with("riscv") => "is_riscv_feature_detected",
6768
"powerpc" | "powerpcle" => "is_powerpc_feature_detected",
6869
"powerpc64" | "powerpc64le" => "is_powerpc64_feature_detected",
6970
"mips" | "mipsel" | "mipsisa32r6" | "mipsisa32r6el" => {
+205
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
//! Run-time feature detection on RISC-V.
2+
3+
features! {
4+
@TARGET: riscv;
5+
@MACRO_NAME: is_riscv_feature_detected;
6+
@MACRO_ATTRS:
7+
/// A macro to test at *runtime* whether instruction sets are available on
8+
/// RISC-V platforms.
9+
///
10+
/// RISC-V standard defined the base sets and the extension sets.
11+
/// The base sets are RV32I, RV64I, RV32E or RV128I. Any RISC-V platform
12+
/// must support one base set and/or multiple extension sets.
13+
///
14+
/// Any RISC-V standard instruction sets can be in state of either ratified,
15+
/// frozen or draft. The version and status of current standard instruction
16+
/// sets can be checked out from preface section of the [ISA manual].
17+
///
18+
/// Platform may define and support their own custom instruction sets with
19+
/// ISA prefix X. These sets are highly platform specific and should be
20+
/// detected with their own platform support crates.
21+
///
22+
/// # Unprivileged Specification
23+
///
24+
/// The supported ratified RISC-V instruction sets are as follows:
25+
///
26+
/// * RV32I: `"rv32i"`
27+
/// * Zifencei: `"zifencei"`
28+
/// * Zihintpause: `"zihintpause"`
29+
/// * RV64I: `"rv64i"`
30+
/// * M: `"m"`
31+
/// * A: `"a"`
32+
/// * Zicsr: `"zicsr"`
33+
/// * Zicntr: `"zicntr"`
34+
/// * Zihpm: `"zihpm"`
35+
/// * F: `"f"`
36+
/// * D: `"d"`
37+
/// * Q: `"q"`
38+
/// * C: `"c"`
39+
///
40+
/// There's also bases and extensions marked as standard instruction set,
41+
/// but they are in frozen or draft state. These instruction sets are also
42+
/// reserved by this macro and can be detected in the future platforms.
43+
///
44+
/// Frozen RISC-V instruction sets:
45+
///
46+
/// * Zfinx: `"zfinx"`
47+
/// * Zdinx: `"zdinx"`
48+
/// * Zhinx: `"zhinx"`
49+
/// * Zhinxmin: `"zhinxmin"`
50+
/// * Ztso: `"ztso"`
51+
///
52+
/// Draft RISC-V instruction sets:
53+
///
54+
/// * RV32E: `"rv32e"`
55+
/// * RV128I: `"rv128i"`
56+
/// * Zfh: `"zfh"`
57+
/// * Zfhmin: `"zfhmin"`
58+
/// * B: `"b"`
59+
/// * J: `"j"`
60+
/// * P: `"p"`
61+
/// * V: `"v"`
62+
/// * Zam: `"zam"`
63+
///
64+
/// Defined by Privileged Specification:
65+
///
66+
/// * Supervisor: `"s"`
67+
/// * Svnapot: `"svnapot"`
68+
/// * Svpbmt: `"svpbmt"`
69+
/// * Svinval: `"svinval"`
70+
/// * Hypervisor: `"h"`
71+
///
72+
/// # RISC-V Bit-Manipulation ISA-extensions
73+
///
74+
/// This document defined the following extensions:
75+
///
76+
/// * Zba: `"zba"`
77+
/// * Zbb: `"zbb"`
78+
/// * Zbc: `"zbc"`
79+
/// * Zbs: `"zbs"`
80+
///
81+
/// # RISC-V Cryptography Extensions
82+
///
83+
/// These extensions are defined in Volume I, Scalar & Entropy Source
84+
/// Instructions:
85+
///
86+
/// * Zbkb: `"zbkb"`
87+
/// * Zbkc: `"zbkc"`
88+
/// * Zbkx: `"zbkx"`
89+
/// * Zknd: `"zknd"`
90+
/// * Zkne: `"zkne"`
91+
/// * Zknh: `"zknh"`
92+
/// * Zksed: `"zksed"`
93+
/// * Zksh: `"zksh"`
94+
/// * Zkr: `"zkr"`
95+
/// * Zkn: `"zkn"`
96+
/// * Zks: `"zks"`
97+
/// * Zk: `"zk"`
98+
/// * Zkt: `"zkt"`
99+
///
100+
/// [ISA manual]: https://github.com/riscv/riscv-isa-manual/
101+
#[unstable(feature = "stdsimd", issue = "27731")]
102+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] rv32i: "rv32i";
103+
/// RV32I Base Integer Instruction Set
104+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zifencei: "zifencei";
105+
/// "Zifencei" Instruction-Fetch Fence
106+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zihintpause: "zihintpause";
107+
/// "Zihintpause" Pause Hint
108+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] rv64i: "rv64i";
109+
/// RV64I Base Integer Instruction Set
110+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] m: "m";
111+
/// "M" Standard Extension for Integer Multiplication and Division
112+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] a: "a";
113+
/// "A" Standard Extension for Atomic Instructions
114+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zicsr: "zicsr";
115+
/// "Zicsr", Control and Status Register (CSR) Instructions
116+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zicntr: "zicntr";
117+
/// "Zicntr", Standard Extension for Base Counters and Timers
118+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zihpm: "zihpm";
119+
/// "Zihpm", Standard Extension for Hardware Performance Counters
120+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] f: "f";
121+
/// "F" Standard Extension for Single-Precision Floating-Point
122+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] d: "d";
123+
/// "D" Standard Extension for Double-Precision Floating-Point
124+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] q: "q";
125+
/// "Q" Standard Extension for Quad-Precision Floating-Point
126+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] c: "c";
127+
/// "C" Standard Extension for Compressed Instructions
128+
129+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zfinx: "zfinx";
130+
/// "Zfinx" Standard Extension for Single-Precision Floating-Point in Integer Registers
131+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zdinx: "zdinx";
132+
/// "Zdinx" Standard Extension for Double-Precision Floating-Point in Integer Registers
133+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zhinx: "zhinx";
134+
/// "Zhinx" Standard Extension for Half-Precision Floating-Point in Integer Registers
135+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zhinxmin: "zhinxmin";
136+
/// "Zhinxmin" Standard Extension for Minimal Half-Precision Floating-Point in Integer Registers
137+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] ztso: "ztso";
138+
/// "Ztso" Standard Extension for Total Store Ordering
139+
140+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] rv32e: "rv32e";
141+
/// RV32E Base Integer Instruction Set
142+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] rv128i: "rv128i";
143+
/// RV128I Base Integer Instruction Set
144+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zfh: "zfh";
145+
/// "Zfh" Standard Extension for 16-Bit Half-Precision Floating-Point
146+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zfhmin: "zfhmin";
147+
/// "Zfhmin" Standard Extension for Minimal Half-Precision Floating-Point Support
148+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] b: "b";
149+
/// "B" Standard Extension for Bit Manipulation
150+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] j: "j";
151+
/// "J" Standard Extension for Dynamically Translated Languages
152+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] p: "p";
153+
/// "P" Standard Extension for Packed-SIMD Instructions
154+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] v: "v";
155+
/// "V" Standard Extension for Vector Operations
156+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zam: "zam";
157+
/// "Zam" Standard Extension for Misaligned Atomics
158+
159+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] s: "s";
160+
/// Supervisor-Level ISA
161+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] svnapot: "svnapot";
162+
/// "Svnapot" Standard Extension for NAPOT Translation Contiguity
163+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] svpbmt: "svpbmt";
164+
/// "Svpbmt" Standard Extension for Page-Based Memory Types
165+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] svinval: "svinval";
166+
/// "Svinval" Standard Extension for Fine-Grained Address-Translation Cache Invalidation
167+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] h: "h";
168+
/// Hypervisor Extension
169+
170+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zba: "zba";
171+
/// "Zba" Standard Extension for Address Generation Instructions
172+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zbb: "zbb";
173+
/// "Zbb" Standard Extension for Basic Bit-Manipulation
174+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zbc: "zbc";
175+
/// "Zbc" Standard Extension for Carry-less Multiplication
176+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zbs: "zbs";
177+
/// "Zbs" Standard Extension for Single-Bit instructions
178+
179+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zbkb: "zbkb";
180+
/// "Zbkb" Standard Extension for Bitmanip instructions for Cryptography
181+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zbkc: "zbkc";
182+
/// "Zbkc" Standard Extension for Carry-less multiply instructions
183+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zbkx: "zbkx";
184+
/// "Zbkx" Standard Extension for Crossbar permutation instructions
185+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zknd: "zknd";
186+
/// "Zknd" Standard Extension for NIST Suite: AES Decryption
187+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zkne: "zkne";
188+
/// "Zkne" Standard Extension for NIST Suite: AES Encryption
189+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zknh: "zknh";
190+
/// "Zknh" Standard Extension for NIST Suite: Hash Function Instructions
191+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zksed: "zksed";
192+
/// "Zksed" Standard Extension for ShangMi Suite: SM4 Block Cipher Instructions
193+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zksh: "zksh";
194+
/// "Zksh" Standard Extension for ShangMi Suite: SM3 Hash Function Instructions
195+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zkr: "zkr";
196+
/// "Zkr" Standard Extension for Entropy Source Extension
197+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zkn: "zkn";
198+
/// "Zkn" Standard Extension for NIST Algorithm Suite
199+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zks: "zks";
200+
/// "Zks" Standard Extension for ShangMi Algorithm Suite
201+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zk: "zk";
202+
/// "Zk" Standard Extension for Standard scalar cryptography extension
203+
@FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] zkt: "zkt";
204+
/// "Zkt" Standard Extension for Data Independent Execution Latency
205+
}

crates/std_detect/src/detect/error_macros.rs

+21
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,27 @@ macro_rules! is_aarch64_feature_detected {
6565
};
6666
}
6767

68+
/// Prevents compilation if `is_riscv_feature_detected` is used somewhere else
69+
/// than `riscv32` or `riscv64` targets.
70+
#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
71+
#[macro_export]
72+
#[unstable(feature = "stdsimd", issue = "27731")]
73+
macro_rules! is_riscv_feature_detected {
74+
($t: tt) => {
75+
compile_error!(
76+
r#"
77+
is_riscv_feature_detected can only be used on RISC-V targets.
78+
You can prevent it from being used in other architectures by
79+
guarding it behind a cfg(target_arch) as follows:
80+
81+
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
82+
if is_riscv_feature_detected(...) { ... }
83+
}
84+
"#
85+
)
86+
};
87+
}
88+
6889
/// Prevents compilation if `is_powerpc_feature_detected` is used somewhere else
6990
/// than `PowerPC` targets.
7091
#[cfg(not(target_arch = "powerpc"))]

crates/std_detect/src/detect/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ cfg_if! {
3838
#[path = "arch/aarch64.rs"]
3939
#[macro_use]
4040
mod arch;
41+
} else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
42+
#[path = "arch/riscv.rs"]
43+
#[macro_use]
44+
mod arch;
4145
} else if #[cfg(target_arch = "powerpc")] {
4246
#[path = "arch/powerpc.rs"]
4347
#[macro_use]
@@ -134,12 +138,15 @@ pub fn features() -> impl Iterator<Item = (&'static str, bool)> {
134138
target_arch = "x86_64",
135139
target_arch = "arm",
136140
target_arch = "aarch64",
141+
target_arch = "riscv32",
142+
target_arch = "riscv64",
137143
target_arch = "powerpc",
138144
target_arch = "powerpc64",
139145
target_arch = "mips",
140146
target_arch = "mips64",
141147
))] {
142148
(0_u8..Feature::_last as u8).map(|discriminant: u8| {
149+
#[allow(bindings_with_variant_name)] // RISC-V has Feature::f
143150
let f: Feature = unsafe { core::mem::transmute(discriminant) };
144151
let name: &'static str = f.to_str();
145152
let enabled: bool = check_for(f);

crates/std_detect/src/detect/os/linux/auxvec.rs

+21-3
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,13 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {
6363
// Try to call a dynamically-linked getauxval function.
6464
if let Ok(hwcap) = getauxval(AT_HWCAP) {
6565
// Targets with only AT_HWCAP:
66-
#[cfg(any(target_arch = "aarch64", target_arch = "mips", target_arch = "mips64"))]
66+
#[cfg(any(
67+
target_arch = "aarch64",
68+
target_arch = "riscv32",
69+
target_arch = "riscv64",
70+
target_arch = "mips",
71+
target_arch = "mips64"
72+
))]
6773
{
6874
if hwcap != 0 {
6975
return Ok(AuxVec { hwcap });
@@ -90,7 +96,13 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {
9096
#[cfg(not(feature = "std_detect_dlsym_getauxval"))]
9197
{
9298
// Targets with only AT_HWCAP:
93-
#[cfg(any(target_arch = "aarch64", target_arch = "mips", target_arch = "mips64"))]
99+
#[cfg(any(
100+
target_arch = "aarch64",
101+
target_arch = "riscv32",
102+
target_arch = "riscv64",
103+
target_arch = "mips",
104+
target_arch = "mips64"
105+
))]
94106
{
95107
let hwcap = unsafe { libc::getauxval(AT_HWCAP as libc::c_ulong) as usize };
96108
if hwcap != 0 {
@@ -168,7 +180,13 @@ fn auxv_from_file(file: &str) -> Result<AuxVec, ()> {
168180
#[cfg(feature = "std_detect_file_io")]
169181
fn auxv_from_buf(buf: &[usize; 64]) -> Result<AuxVec, ()> {
170182
// Targets with only AT_HWCAP:
171-
#[cfg(any(target_arch = "aarch64", target_arch = "mips", target_arch = "mips64"))]
183+
#[cfg(any(
184+
target_arch = "aarch64",
185+
target_arch = "riscv32",
186+
target_arch = "riscv64",
187+
target_arch = "mips",
188+
target_arch = "mips64",
189+
))]
172190
{
173191
for el in buf.chunks(2) {
174192
match el[0] {

crates/std_detect/src/detect/os/linux/cpuinfo.rs

+32
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,38 @@ CPU revision : 1";
212212
assert!(cpuinfo.field("Features").has("asimd"));
213213
}
214214

215+
const RISCV_RV64GC: &str = r"processor : 0
216+
hart : 3
217+
isa : rv64imafdc
218+
mmu : sv39
219+
uarch : sifive,u74-mc
220+
221+
processor : 1
222+
hart : 1
223+
isa : rv64imafdc
224+
mmu : sv39
225+
uarch : sifive,u74-mc
226+
227+
processor : 2
228+
hart : 2
229+
isa : rv64imafdc
230+
mmu : sv39
231+
uarch : sifive,u74-mc
232+
233+
processor : 3
234+
hart : 4
235+
isa : rv64imafdc
236+
mmu : sv39
237+
uarch : sifive,u74-mc";
238+
239+
#[test]
240+
fn riscv_rv64gc() {
241+
let cpuinfo = CpuInfo::from_str(RISCV_RV64GC).unwrap();
242+
assert_eq!(cpuinfo.field("isa"), "rv64imafdc");
243+
assert_eq!(cpuinfo.field("mmu"), "sv39");
244+
assert_eq!(cpuinfo.field("uarch"), "sifive,u74-mc");
245+
}
246+
215247
const POWER8E_POWERKVM: &str = r"processor : 0
216248
cpu : POWER8E (raw), altivec supported
217249
clock : 3425.000000MHz

crates/std_detect/src/detect/os/linux/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ cfg_if::cfg_if! {
4545
} else if #[cfg(target_arch = "arm")] {
4646
mod arm;
4747
pub(crate) use self::arm::detect_features;
48-
} else if #[cfg(any(target_arch = "mips", target_arch = "mips64"))] {
48+
} else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
49+
mod riscv;
50+
pub(crate) use self::riscv::detect_features;
51+
} else if #[cfg(any(target_arch = "mips", target_arch = "mips64"))] {
4952
mod mips;
5053
pub(crate) use self::mips::detect_features;
5154
} else if #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] {

0 commit comments

Comments
 (0)