mod backpatch;
mod control_flow_translator;
mod func;
mod interference_graph;
mod ssa_elimination;
mod translator;
#[cfg(test)]
mod tests;
use backpatch::BackpatchContext;
use control_flow_translator::{handle_block_fall_through, handle_control_flow_instruction};
pub use func::{Func, Local};
use interference_graph::{find_copy_edges, InterferenceGraph};
use translator::translate_tac;
use crate::ir::Func as IRFunc;
pub fn generate_func(ir_func: IRFunc) -> Func {
let mut graph = InterferenceGraph::build(&ir_func);
let (max_clique, seo) = graph.find_max_clique();
if max_clique > 256 {
panic!("function requires too many registers");
}
graph.color(&ir_func, seo, max_clique);
let copies = find_copy_edges(&ir_func);
graph.best_effort_coalescence(&ir_func, copies, max_clique as u8);
generate_bytecode(&ir_func, &graph, u8::try_from(max_clique).unwrap())
}
fn generate_bytecode(ir_func: &IRFunc, graph: &InterferenceGraph, max_clique: u8) -> Func {
let mut func = Func::new(
ir_func.get_id(),
ir_func.auto_binds(),
u8::try_from(ir_func.get_args().len()).unwrap(),
max_clique,
);
let mut backpatch_ctx = BackpatchContext::new();
for block in ir_func.get_blocks() {
let spans = block.get_spans();
for (idx, instr) in block.get_instrs().iter().enumerate() {
let span = spans.get(idx);
if let Some(bytecode) = translate_tac(instr, graph, &mut func) {
func.push_instr_spanned(bytecode, span.copied());
continue;
}
if handle_control_flow_instruction(
instr,
block,
ir_func,
graph,
&mut func,
&mut backpatch_ctx,
) {
continue;
}
panic!("Unhandled TAC instruction: {:?}", instr);
}
handle_block_fall_through(block, ir_func, graph, &mut func);
}
backpatch_ctx.apply_patches(&mut func);
func
}