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

45 lines
1.9 KiB
Rust

//! Common-subexpression elimination merges two instructions only when their results have the
//! same class: `VExtract` of one lane into an I vreg (sign-extended i32) and into an F32 vreg have
//! the same key but are two values. A Splash x4 kernel stored the integer register as an f32 when
//! the F32 extract was replaced by a copy of the I one.
use relax_backend::passes;
use relax_backend::rir::*;
#[test]
fn extracts_of_one_lane_as_int_and_float_stay_apart() {
let mut f = Func::new("cse_result_class".into(), 0);
let (src, dst) = (f.vreg(Cls::I), f.vreg(Cls::I));
f.params = vec![src, dst];
f.block();
let (v, xi, xf) = (f.vreg(Cls::V128), f.vreg(Cls::I), f.vreg(Cls::F32));
let insts = vec![
Inst::VLoad(v, src, 0),
Inst::VExtract(xi, v, 2),
Inst::VExtract(xf, v, 2),
Inst::Store(Mem::Int(4, false), dst, 0, xi),
Inst::Store(Mem::F32, dst, 4, xf),
];
f.blocks[0].pos = vec![0; insts.len()];
f.blocks[0].insts = insts;
f.blocks[0].term = Term::Ret(vec![]);
f.verify().unwrap();
passes::simplify(&relax_session::Options::default(), &mut f, None, true, true);
passes::local_cse(&relax_session::Options::default(), &mut f);
f.verify().unwrap();
// every store still stores a value of its own memory class
for b in &f.blocks {
for i in &b.insts {
if let Inst::Store(m, _, _, val) = i {
let cls = f.vregs[val.0 as usize];
match m {
Mem::F32 => assert_eq!(cls, Cls::F32, "the f32 store reads a {cls:?} vreg"),
Mem::Int(..) => assert_eq!(cls, Cls::I, "the i32 store reads a {cls:?} vreg"),
_ => {}
}
}
if let Inst::Mov(d, s) = i {
assert_eq!(f.vregs[d.0 as usize], f.vregs[s.0 as usize], "a copy across classes");
}
}
}
}