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

60 lines
2.3 KiB
Rust

//! simplify: `(x + k) - x` is k and `x - (x + k)` is -k (64-bit wrapping arithmetic): the length of
//! `data[i..i + 8]`, so `try_into::<[u8; 8]>` folds to Ok.
use relax_backend::passes;
use relax_backend::rir::*;
const U64: IntTy = IntTy { bits: 64, signed: false };
const U32: IntTy = IntTy { bits: 32, signed: false };
fn push(f: &mut Func, i: Inst) {
f.blocks[0].insts.push(i);
f.blocks[0].pos.push(0);
}
/// fn(x) { y = x + k (or x - k); ret <sub> } with `sub` built from (x, y)
fn build(add: IOp, k: i64, it: IntTy, sub: impl Fn(VReg, VReg) -> (VReg, VReg)) -> Func {
let mut f = Func::new("subk".into(), 0);
let x = f.vreg(Cls::I);
f.params.push(x);
f.rets.push(Cls::I);
f.block();
let (y, z) = (f.vreg(Cls::I), f.vreg(Cls::I));
push(&mut f, Inst::IBinI(add, U64, y, x, k));
let (a, b) = sub(x, y);
push(&mut f, Inst::IBin(IOp::Sub, it, z, a, b));
f.blocks[0].term = Term::Ret(vec![z]);
f
}
fn ret_const(f: &Func) -> Option<i64> {
let Term::Ret(ref v) = f.blocks[0].term else { return None };
f.blocks[0].insts.iter().find_map(|i| match *i {
Inst::Iconst(d, k) if d == v[0] => Some(k),
_ => None,
})
}
#[test]
fn a_sub_of_an_offset_of_the_same_value_is_the_offset() {
let o = relax_session::Options::default();
let cases: [(IOp, i64, bool, i64); 4] = [(IOp::Add, 8, false, 8), (IOp::Add, 8, true, -8), (IOp::Sub, 3, false, -3), (IOp::Sub, 3, true, 3)];
for (op, k, swapped, want) in cases {
let mut f = build(op, k, U64, |x, y| if swapped { (x, y) } else { (y, x) });
passes::simplify(&o, &mut f, None, true, true);
f.verify().unwrap();
assert_eq!(ret_const(&f), Some(want), "{op:?} {k} swapped {swapped}: {}", f.dump());
}
}
#[test]
fn a_narrow_sub_or_another_value_is_left() {
let o = relax_session::Options::default();
// 32-bit subtraction of 64-bit values: not folded here
let mut f = build(IOp::Add, 8, U32, |x, y| (y, x));
passes::simplify(&o, &mut f, None, true, true);
assert_eq!(ret_const(&f), None, "{}", f.dump());
// (x + 8) - (x + 8): not this rule (and x - x is another one)
let mut f = build(IOp::Add, 8, U64, |_, y| (y, y));
passes::simplify(&o, &mut f, None, true, true);
assert_ne!(ret_const(&f), Some(8));
}