use core::ffi::c_void;
pub type Ints = [u64; 8];
pub type Floats = [f64; 4];
pub fn ints(values: &[u64]) -> Ints {
assert!(values.len() <= 8, "{} integer arguments, but only eight registers", values.len());
let mut a = [0u64; 8];
a[..values.len()].copy_from_slice(values);
a
}
pub unsafe fn call_out(
func: *const c_void,
args: Ints,
floats: Floats,
self_reg: u64,
out: *mut u8,
) {
unsafe {
core::arch::asm!("blr {f}", f = in(reg) func,
in("x0") args[0], in("x1") args[1], in("x2") args[2], in("x3") args[3],
in("x4") args[4], in("x5") args[5], in("x6") args[6], in("x7") args[7],
in("d0") floats[0], in("d1") floats[1], in("d2") floats[2], in("d3") floats[3],
in("x8") out, in("x20") self_reg,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
}
}
pub unsafe fn call_spilled(
func: *const c_void,
ints: &[u64],
floats: Floats,
self_reg: u64,
out: *mut u8,
) {
assert!(ints.len() <= 16, "call with {} integer arguments", ints.len());
let mut a = [0u64; 16];
a[..ints.len()].copy_from_slice(ints);
let spill = &a[8..];
unsafe {
core::arch::asm!(
"sub sp, sp, #64",
"stp {s0}, {s1}, [sp]",
"stp {s2}, {s3}, [sp, #16]",
"stp {s4}, {s5}, [sp, #32]",
"stp {s6}, {s7}, [sp, #48]",
"blr {f}",
"add sp, sp, #64",
f = in(reg) func,
s0 = in(reg) spill[0], s1 = in(reg) spill[1],
s2 = in(reg) spill[2], s3 = in(reg) spill[3],
s4 = in(reg) spill[4], s5 = in(reg) spill[5],
s6 = in(reg) spill[6], s7 = in(reg) spill[7],
in("x0") a[0], in("x1") a[1], in("x2") a[2], in("x3") a[3],
in("x4") a[4], in("x5") a[5], in("x6") a[6], in("x7") a[7],
in("d0") floats[0], in("d1") floats[1], in("d2") floats[2], in("d3") floats[3],
in("x8") out, in("x20") self_reg,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
}
}
pub unsafe fn call_regs(
func: *const c_void,
args: Ints,
floats: Floats,
self_reg: u64,
) -> [u64; 3] {
let (r0, r1, r2): (u64, u64, u64);
unsafe {
core::arch::asm!("blr {f}", f = in(reg) func,
inout("x0") args[0] => r0, inout("x1") args[1] => r1,
inout("x2") args[2] => r2, in("x3") args[3],
in("x4") args[4], in("x5") args[5], in("x6") args[6], in("x7") args[7],
in("d0") floats[0], in("d1") floats[1], in("d2") floats[2], in("d3") floats[3],
in("x20") self_reg,
lateout("x8") _, lateout("x9") _, lateout("x10") _, lateout("x11") _,
lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
lateout("x16") _, lateout("x17") _, lateout("lr") _, lateout("x21") _,
clobber_abi("C"),
);
}
[r0, r1, r2]
}
pub unsafe fn call_f64(func: *const c_void, args: Ints, floats: Floats, self_reg: u64) -> f64 {
let out: f64;
unsafe {
core::arch::asm!("blr {f}", f = in(reg) func,
in("x0") args[0], in("x1") args[1], in("x2") args[2], in("x3") args[3],
in("x4") args[4], in("x5") args[5], in("x6") args[6], in("x7") args[7],
inout("d0") floats[0] => out,
in("d1") floats[1], in("d2") floats[2], in("d3") floats[3],
in("x20") self_reg,
lateout("x8") _, lateout("x9") _, lateout("x10") _, lateout("x11") _,
lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
lateout("x16") _, lateout("x17") _, lateout("lr") _, lateout("x21") _,
clobber_abi("C"),
);
}
out
}
pub unsafe fn static_out(getter: *const c_void, meta: *const c_void, stride: usize) -> Vec<u8> {
let mut out = vec![0u8; stride.max(1)];
unsafe { call_out(getter, [0; 8], [0.0; 4], meta as u64, out.as_mut_ptr()) };
out
}
pub unsafe fn static_regs(getter: *const c_void, meta: *const c_void) -> [u64; 3] {
unsafe { call_regs(getter, [0; 8], [0.0; 4], meta as u64) }
}