use rucc_base::Interner;
use rucc_ir::{Block, Builder, Func, Signature, Type};
pub(crate) fn graph(edges: &[&[usize]]) -> Func {
let mut names = Interner::new();
let mut func = Func::new(names.intern("f"), Signature::new());
let blocks: Vec<Block> = edges.iter().map(|_| func.create_block()).collect();
for (index, targets) in edges.iter().enumerate() {
assert!(targets.iter().all(|&t| t < blocks.len()), "block {index} branches to nowhere");
let mut build = Builder::new(&mut func, blocks[index]);
match targets {
[] => {
build.ret(&[]);
}
[only] => {
build.jump(blocks[*only], &[]);
}
[taken, not_taken] => {
let cond = build.iconst(Type::int(1), 1);
build.br_if(cond, blocks[*taken], &[], blocks[*not_taken], &[]);
}
[default, cases @ ..] => {
let value = build.iconst(Type::int(32), 0);
let cases: Vec<(i128, Block)> = cases
.iter()
.enumerate()
.map(|(case, &target)| (case as i128, blocks[target]))
.collect();
build.switch(value, blocks[*default], &cases);
}
}
}
func
}
pub(crate) fn computed_goto() -> Func {
let mut names = Interner::new();
let mut func = Func::new(names.intern("f"), Signature::new());
let entry = func.create_block();
let middle = func.create_block();
let target = func.create_block();
let mut build = Builder::new(&mut func, entry);
let addr = build.block_addr(target);
build.jump(middle, &[]);
let mut build = Builder::new(&mut func, middle);
build.indirect_br(addr, &[target]);
let mut build = Builder::new(&mut func, target);
build.ret(&[]);
func
}