Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/native/src/riscv.rs
1691 views
1
use cranelift_codegen::settings::Configurable;
2
use std::fs::File;
3
use std::io::{BufRead, BufReader};
4
5
pub fn hwcap_detect(isa_builder: &mut dyn Configurable) -> Result<(), &'static str> {
6
let v = unsafe { libc::getauxval(libc::AT_HWCAP) };
7
8
const HWCAP_RISCV_EXT_A: libc::c_ulong = 1 << (b'a' - b'a');
9
const HWCAP_RISCV_EXT_C: libc::c_ulong = 1 << (b'c' - b'a');
10
const HWCAP_RISCV_EXT_D: libc::c_ulong = 1 << (b'd' - b'a');
11
const HWCAP_RISCV_EXT_F: libc::c_ulong = 1 << (b'f' - b'a');
12
const HWCAP_RISCV_EXT_M: libc::c_ulong = 1 << (b'm' - b'a');
13
const HWCAP_RISCV_EXT_V: libc::c_ulong = 1 << (b'v' - b'a');
14
15
if (v & HWCAP_RISCV_EXT_A) != 0 {
16
isa_builder.enable("has_a").unwrap();
17
}
18
19
if (v & HWCAP_RISCV_EXT_C) != 0 {
20
isa_builder.enable("has_c").unwrap();
21
}
22
23
if (v & HWCAP_RISCV_EXT_D) != 0 {
24
isa_builder.enable("has_d").unwrap();
25
}
26
27
if (v & HWCAP_RISCV_EXT_F) != 0 {
28
isa_builder.enable("has_f").unwrap();
29
30
// TODO: There doesn't seem to be a bit associated with this extension
31
// rust enables it with the `f` extension:
32
// https://github.com/rust-lang/stdarch/blob/790411f93c4b5eada3c23abb4c9a063fb0b24d99/crates/std_detect/src/detect/os/linux/riscv.rs#L43
33
isa_builder.enable("has_zicsr").unwrap();
34
}
35
36
if (v & HWCAP_RISCV_EXT_M) != 0 {
37
isa_builder.enable("has_m").unwrap();
38
}
39
40
if (v & HWCAP_RISCV_EXT_V) != 0 {
41
isa_builder.enable("has_v").unwrap();
42
}
43
44
// In general extensions that are longer than one letter
45
// won't have a bit associated with them. The Linux kernel
46
// is currently working on a new way to query the extensions.
47
Ok(())
48
}
49
50
/// Read the /proc/cpuinfo file and detect the extensions.
51
///
52
/// We are looking for the isa line string, which contains the extensions.
53
/// The format for this string is specified in the linux user space ABI for RISC-V:
54
/// https://github.com/torvalds/linux/blob/09a9639e56c01c7a00d6c0ca63f4c7c41abe075d/Documentation/riscv/uabi.rst
55
///
56
/// The format is fairly similar to the one specified in the RISC-V ISA manual, but
57
/// all lower case.
58
///
59
/// An example ISA string is: rv64imafdcvh_zawrs_zba_zbb_zicbom_zicboz_zicsr_zifencei_zihintpause
60
pub fn cpuinfo_detect(isa_builder: &mut dyn Configurable) -> Result<(), &'static str> {
61
let file = File::open("/proc/cpuinfo").map_err(|_| "failed to open /proc/cpuinfo")?;
62
63
let isa_string = BufReader::new(file)
64
.lines()
65
.filter_map(Result::ok)
66
.find_map(|line| {
67
if let Some((k, v)) = line.split_once(':') {
68
if k.trim_end() == "isa" {
69
return Some(v.trim().to_string());
70
}
71
}
72
None
73
})
74
.ok_or("failed to find isa line in /proc/cpuinfo")?;
75
76
for ext in isa_string_extensions(&isa_string) {
77
// Try enabling all the extensions that are parsed.
78
// Cranelift won't recognize all of them, but that's okay we just ignore them.
79
// Extensions flags in the RISC-V backend have the format of `has_x` for the `x` extension.
80
let _ = isa_builder.enable(&format!("has_{ext}"));
81
}
82
83
Ok(())
84
}
85
86
/// Parses an ISA string and returns an iterator over the extensions.
87
fn isa_string_extensions(isa: &str) -> Vec<&str> {
88
let mut parts = isa.split('_');
89
let mut extensions = Vec::new();
90
// The first entry has the form `rv64imafdcvh`, we need to skip the architecture ("rv64").
91
// Each of the letters after the cpu architecture is an extension, so return them
92
// individually.
93
if let Some(letters) = parts.next().unwrap().strip_prefix("rv64") {
94
extensions.extend(letters.matches(|_| true));
95
extensions.extend(parts);
96
}
97
extensions
98
}
99
100
#[cfg(test)]
101
mod tests {
102
use super::*;
103
104
#[test]
105
fn parse_isa() {
106
let isa_string = "rv64imafdcvh_zawrs_zba_zbb_zicbom_zicboz_zicsr_zifencei_zihintpause";
107
let extensions = vec![
108
"i",
109
"m",
110
"a",
111
"f",
112
"d",
113
"c",
114
"v",
115
"h",
116
"zawrs",
117
"zba",
118
"zbb",
119
"zicbom",
120
"zicboz",
121
"zicsr",
122
"zifencei",
123
"zihintpause",
124
];
125
126
assert_eq!(isa_string_extensions(isa_string), extensions,);
127
}
128
}
129
130