Skip to content

Commit 04b78c4

Browse files
committed
feat: add support for riscv64
The macos_compat layer should also include a `JMP_BUF_SIZE` const (or a totally different structure, just like with glibc), but it has been omitted because there is no support for RISC V at the moment. The asm based implementation should be fine for riscv32, but I did not check what `JmpBufFields` should be.
1 parent 380518e commit 04b78c4

File tree

6 files changed

+105
-0
lines changed

6 files changed

+105
-0
lines changed

build/get_riscv64_consts.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <setjmp.h>
2+
3+
#if defined __riscv_float_abi_double
4+
CEE_SCAPE_FLOAT_ABI_DOUBLE
5+
#endif
6+
7+
#if defined __riscv_float_abi_soft
8+
CEE_SCAPE_FLOAT_ABI_SOFT
9+
#endif

build/main.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,42 @@ fn main() {
2121
.compile("interop_via_c");
2222
} else {
2323
}
24+
25+
if cfg!(target_arch = "riscv64") {
26+
generate_riscv64_consts();
27+
}
28+
}
29+
30+
fn generate_riscv64_consts() {
31+
println!("cargo:rerun-if-changed=build/get_riscv64_consts.c");
32+
33+
let expanded = cc::Build::new().file("build/get_riscv64_consts.c").expand();
34+
let expanded = String::from_utf8(expanded).unwrap();
35+
36+
let mut float_abi_double = false;
37+
let mut float_abi_soft = false;
38+
for line in expanded.lines() {
39+
match line.trim() {
40+
"CEE_SCAPE_FLOAT_ABI_DOUBLE" => float_abi_double = true,
41+
"CEE_SCAPE_FLOAT_ABI_SOFT" => float_abi_soft = true,
42+
_ => {}
43+
}
44+
}
45+
46+
let out_dir: PathBuf = std::env::var("OUT_DIR")
47+
.expect("OUT_DIR env variable should be available")
48+
.into();
49+
println!("cargo::rustc-env=OUT_DIR={}", out_dir.display());
50+
51+
let mut riscv64_consts_file = File::create(out_dir.join("riscv64_consts.rs"))
52+
.expect("unable to create riscv64_consts.rs");
53+
writeln!(
54+
riscv64_consts_file,
55+
"const FLOAT_ABI_DOUBLE: bool = {float_abi_double};\n\
56+
const FLOAT_ABI_SOFT: bool = {float_abi_soft};"
57+
)
58+
.expect("unable to write to riscv64_consts.rs");
59+
riscv64_consts_file
60+
.flush()
61+
.expect("unable to write to riscv64_consts.rs");
2462
}

src/asm_based.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,34 @@ macro_rules! maybesig_setjmp_asm {
118118
}
119119
}
120120

121+
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
122+
macro_rules! maybesig_setjmp_asm {
123+
($sigsetjmp:ident, $jbuf_ptr:ident, $ifsig_savemask:ident, $closure_env_ptr:ident, $c2r:ident, $ret:ident) => {
124+
core::arch::asm!(
125+
// savemask, if needed, is already in a1
126+
"mv a0, s3", // move saved jbuf_ptr to sigsetjmp param position. (savemask is already in position)
127+
"jalr 0({tmp})", // fills in jbuf; future longjmp calls go here.
128+
"bnez a0, 1f", // if return value non-zero, skip the callback invocation
129+
// (and if return value non-zero, we cannot assume register state has been restored!)
130+
"mv a0, s3", // move saved jmp buf into callback's arg position
131+
"mv a1, s2", // move saved closure env into callback's arg position
132+
"jalr 0(s4)", // invoke the callback
133+
"1:", // at this point, a0 carries the return value (from either outcome)
134+
// we let compiler pick this register since we don't need to preseve
135+
// it across the first call.
136+
tmp = in(reg) $sigsetjmp,
137+
in("a1") $ifsig_savemask, // savemask arg position for sigsetjmp
138+
out("a0") $ret, // the output will be stored here.
139+
// [s2,s3,s4] are all callee-save registers for the normal sigsetjmp return.
140+
// we will have them to reference.
141+
in("s2") $closure_env_ptr,
142+
in("s3") $jbuf_ptr,
143+
in("s4") $c2r,
144+
clobber_abi("C"), // clobber abi reflects call effects, including {x1,x5,x6,x7}...
145+
);
146+
}
147+
}
148+
121149
/// Covers the usual use case for setjmp: it invokes the callback, and the code
122150
/// of the callback can use longjmp to exit early from the call_with_setjmp.
123151
#[inline(never)] // see https://github.com/pnkfelix/cee-scape/issues/14

src/glibc_compat.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,23 @@ pub struct JmpBufFields {
99
_neither_send_nor_sync: PhantomData<*const u8>,
1010
}
1111

12+
/// `JmpBufFields` are the accessible fields when viewed via a JmpBuf pointer.
13+
/// But also: You shouldn't be poking at these!
14+
#[cfg(target_arch = "riscv64")]
15+
#[repr(C)]
16+
pub struct JmpBufFields {
17+
/// Program counter.
18+
__pc: i64,
19+
/// Callee-saved registers.
20+
__regs: [i64; 12],
21+
/// Stack pointer.
22+
__sp: i64,
23+
/// Callee-saved floating point registers.
24+
__fpregs: [f64; crate::riscv64::floating_point_registers()],
25+
26+
_neither_send_nor_sync: PhantomData<*const u8>,
27+
}
28+
1229
/// `SigJmpBufFields` are the accessible fields when viewed via a SigJmpBuf pointer.
1330
/// But also: You shouldn't be poking at these!
1431
#[repr(C)]

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ use libc::c_int;
182182
mod glibc_compat;
183183
#[cfg(target_os = "macos")]
184184
mod macos_compat;
185+
#[cfg(target_arch = "riscv64")]
186+
mod riscv64;
185187
#[cfg(target_os = "linux")]
186188
use glibc_compat as struct_defs;
187189
#[cfg(target_os = "macos")]

src/riscv64.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
include!(concat!(env!("OUT_DIR"), "/riscv64_consts.rs"));
2+
3+
pub const fn floating_point_registers() -> usize {
4+
if FLOAT_ABI_DOUBLE {
5+
12
6+
} else if !FLOAT_ABI_SOFT {
7+
panic!("unsupported number of floating point registers");
8+
} else {
9+
0
10+
}
11+
}

0 commit comments

Comments
 (0)