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

36 lines
1.7 KiB
Rust

//! The domain-base reads of a function that names domain statics dominate every use and sit on
//! the paths that use it. A jump table (`Term::Switch`) enters its case blocks straight from the
//! dispatching block: the table's targets are its successors, so each case that names a domain
//! static reads the base itself and no read sits in a block the other cases skip (a warm-cached
//! `match` in Stage's parser once faulted at a small address because a read sat in a skipped link
//! block).
use relax_backend::regalloc;
use relax_backend::rir::*;
use std::sync::Arc;
#[test]
fn switch_edges_count_for_the_domain_base_block() {
let mut f = Func::new("dom_table".to_string(), 0);
let x = f.vreg(Cls::I);
f.params = vec![x];
// b0 -> b1 (the dispatch) -> case blocks 2..8 (case k is b(2 + k)), default b8
let blocks: Vec<u32> = (0..9).map(|_| f.block()).collect();
f.blocks[0].term = Term::Jump(blocks[1]);
let targets: Vec<u32> = (0..6).map(|k| 2 + k).collect();
f.blocks[1].term = Term::Switch(x, Arc::new(SwitchTable::new(0, targets, 8)));
for k in 0..6u32 {
let b = 2 + k;
if k == 3 || k == 5 {
let d = f.vreg(Cls::I);
f.blocks[b as usize].insts.push(Inst::Addr(d, Sym { id: 1, off: 0 }));
f.blocks[b as usize].pos.push(0);
}
f.blocks[b as usize].term = Term::Ret(Vec::new());
}
f.blocks[8].term = Term::Ret(Vec::new());
// sym id 1 is a Domain symbol (class byte 3)
static CLASS: [u8; 2] = [0, 3];
let reach = regalloc::reachable(&f);
assert!(reach[5] && reach[7]);
assert_eq!(regalloc::domain_base_blocks(&f, CLASS.as_ptr() as u64, &reach), vec![5, 7]);
}