makepad/libs/relax/backend/tests/vec_index_addr.rs

63 lines
2.9 KiB
Rust

//! Indexed vector accesses (`Inst::VLoadX` / `VStoreX`, made by `passes::addr_modes`) at every
//! shift the encoders take and with and without a displacement: arm64's register-offset form
//! (`ldr q, [x, x, lsl #4]`), its shifted-add fallback, and x86-64's SIB forms, run on the host.
#![cfg(any(all(target_arch = "x86_64", unix), all(target_arch = "aarch64", unix)))]
use relax_backend::{exec::Code, rir::*};
#[cfg(target_arch = "x86_64")]
type Entry = extern "sysv64" fn(*const u8, *mut u8, u64);
#[cfg(target_arch = "aarch64")]
type Entry = extern "C" fn(*const u8, *mut u8, u64);
#[cfg(target_arch = "x86_64")]
fn compile(f: &Func) -> Code {
let options = &relax_session::Options::default();
let env = relax_backend::x64::Env { slots: SlotsPtr::NONE, tls_key: 0, tls_slow: 0, resume: 0, opt_regs: true, syms: 0, sym_class: 0, near: false };
let c = relax_backend::x64::compile(options, f, &env).unwrap();
assert!(c.relocs.is_empty());
Code::new(&c.code).unwrap()
}
#[cfg(target_arch = "aarch64")]
fn compile(f: &Func) -> Code {
let options = &relax_session::Options::default();
let env = relax_backend::arm64::Env { slots: SlotsPtr::NONE, tls_key: 0, tls_slow: 0, resume: 0, opt_regs: true, syms: 0, sym_class: 0, near: false };
let c = relax_backend::arm64::compile(options, f, &env).unwrap();
assert!(c.relocs.is_empty());
Code::new(&c.code).unwrap()
}
/// fn(src, dst, i) { dst[(i << sh) + off ..][..16] = src[(i << sh) + off ..][..16] } through the
/// indexed forms (VLoadX into VStoreX)
fn func(sh: u8, off: i32) -> Func {
let mut f = Func::new("vec_index".into(), 0);
let (ps, pd, pi) = (f.vreg(Cls::I), f.vreg(Cls::I), f.vreg(Cls::I));
f.params = vec![ps, pd, pi];
f.rets = vec![];
f.block();
let v = f.vreg(Cls::V128);
f.blocks[0].insts = vec![Inst::VLoadX(v, ps, pi, sh, off), Inst::VStoreX(pd, pi, sh, off, v)];
f.blocks[0].pos = vec![Default::default(); 2];
f.blocks[0].term = Term::Ret(vec![]);
f
}
#[test]
fn indexed_vector_accesses_address_base_plus_scaled_index_plus_offset() {
let src: Vec<u8> = (0..256u32).map(|x| (x * 7 + 3) as u8).collect();
let max_sh = if cfg!(target_arch = "aarch64") { 4 } else { 3 };
for sh in 0..=max_sh {
for off in [0i32, 16, -16, 4] {
let code = compile(&func(sh, off));
let entry: Entry = unsafe { std::mem::transmute(code.ptr()) };
for i in [1u64, 3, 5] {
let at = ((i << sh) as i64 + off as i64 + 32) as usize;
let mut dst = vec![0u8; 256];
// base pointers 32 bytes in, so negative displacements stay inside
entry(src[32..].as_ptr(), dst[32..].as_mut_ptr(), i);
assert_eq!(&dst[at..at + 16], &src[at..at + 16], "sh {sh} off {off} i {i}");
assert!(dst[..at].iter().chain(&dst[at + 16..]).all(|b| *b == 0), "sh {sh} off {off} i {i}: wrote outside");
}
}
}
}