diff --git a/src/asmgen/mod.rs b/src/asmgen/mod.rs index c2a1ffe..edf0652 100644 --- a/src/asmgen/mod.rs +++ b/src/asmgen/mod.rs @@ -5,7 +5,7 @@ use std::ops::Deref; use lang_c::ast; use crate::ir::HasDtype; -use crate::opt::opt_utils; +use crate::opt::opt_utils::*; use crate::{Translate, asm, ir}; #[derive(Debug, Default)] @@ -35,6 +35,167 @@ impl Translate for Asmgen { } } +struct InferenceGraph { + edges: HashSet<(ir::RegisterId, ir::RegisterId)>, +} + +impl InferenceGraph { + fn new(code: &ir::FunctionDefinition) -> Self { + let cfg = make_cfg(code); + let reverse_cfg = reverse_cfg(&cfg); + let domtree = Domtree::new(code.bid_init, &cfg, &reverse_cfg); + + let mut lives = HashMap::new(); + + loop { + let mut changed = false; + + for bid in domtree.rpo() { + let block = &code.blocks[bid]; + let len = block.instructions.len(); + let mut uses = HashSet::new(); + + for (i, inst) in block.instructions.iter().enumerate() { + match inst.deref() { + ir::Instruction::BinOp { lhs, rhs, .. } => { + mark_as_used(lhs, &mut uses); + mark_as_used(rhs, &mut uses); + } + ir::Instruction::UnaryOp { operand, .. } => { + mark_as_used(operand, &mut uses); + } + ir::Instruction::Store { ptr, value } => { + mark_as_used(ptr, &mut uses); + mark_as_used(value, &mut uses); + } + ir::Instruction::Load { ptr } => { + mark_as_used(ptr, &mut uses); + } + ir::Instruction::Call { callee, args, .. } => { + mark_as_used(callee, &mut uses); + for arg in args { + mark_as_used(arg, &mut uses); + } + } + ir::Instruction::TypeCast { value, .. } => { + mark_as_used(value, &mut uses); + } + ir::Instruction::GetElementPtr { ptr, offset, .. } => { + mark_as_used(ptr, &mut uses); + mark_as_used(offset, &mut uses); + } + _ => (), + } + + let mut next_lives = lives + .entry(ir::RegisterId::temp(*bid, i + 1)) + .or_insert_with(HashSet::new) + .clone(); + let _ = next_lives.remove(&ir::RegisterId::temp(*bid, i)); + uses.extend(next_lives); + changed = extend_set( + lives + .entry(ir::RegisterId::temp(*bid, i)) + .or_insert_with(HashSet::new), + std::mem::take(&mut uses), + ) || changed; + } + + let mut uses = HashSet::new(); + match &block.exit { + ir::BlockExit::Jump { arg } => { + for arg in &arg.args { + mark_as_used(arg, &mut uses); + } + } + ir::BlockExit::ConditionalJump { + condition, + arg_then, + arg_else, + } => { + mark_as_used(condition, &mut uses); + for arg in &arg_then.args { + mark_as_used(arg, &mut uses); + } + for arg in &arg_else.args { + mark_as_used(arg, &mut uses); + } + } + ir::BlockExit::Switch { + value, + default, + cases, + } => { + mark_as_used(value, &mut uses); + for arg in &default.args { + mark_as_used(arg, &mut uses); + } + for (_, arg) in cases { + for arg in &arg.args { + mark_as_used(arg, &mut uses); + } + } + } + ir::BlockExit::Return { value } => { + mark_as_used(value, &mut uses); + } + _ => (), + } + + let successors = cfg[bid].iter().map(|arg| arg.bid).collect::>(); + let mut successor_lives = HashSet::::new(); + for succ in &successors { + if let Some(succ_lives) = lives.get(&ir::RegisterId::temp(*succ, 0)) { + successor_lives.extend(succ_lives); + } + } + + uses.extend(successor_lives); + changed = extend_set( + lives + .entry(ir::RegisterId::temp(*bid, len)) + .or_insert_with(HashSet::new), + uses, + ) || changed; + } + + if !changed { + break; + } + } + + let mut edges = HashSet::new(); + + for (_, lives) in &lives { + for rid1 in lives { + for rid2 in lives { + if rid1 != rid2 { + let _ = edges.insert((*rid1, *rid2)); + } + } + } + } + + println!("Inference graph: {:?}", edges); + + InferenceGraph { edges } + } +} + +fn mark_as_used(operand: &ir::Operand, uses: &mut HashSet) { + if let ir::Operand::Register { rid, .. } = operand { + if !matches!(rid, ir::RegisterId::Local { .. }) { + let _ = uses.insert(*rid); + } + } +} + +fn extend_set(set: &mut HashSet, other: HashSet) -> bool { + let len = set.len(); + set.extend(other); + set.len() != len +} + struct Context { insts: Vec, stack_offsets: HashMap, @@ -95,6 +256,9 @@ impl Asmgen { definition, } => { if let Some(definition) = definition { + // TEMP + let graph = InferenceGraph::new(definition); + let mut context = self.translate_prologue(signature, definition, structs); self.translate_block( name, diff --git a/src/opt/opt_utils.rs b/src/opt/opt_utils.rs index ff69108..dcf2fe2 100644 --- a/src/opt/opt_utils.rs +++ b/src/opt/opt_utils.rs @@ -122,7 +122,7 @@ impl Domtree { }; for (bid_pred, _) in preds { let mut runner = *bid_pred; - while !Self::dominates(&idoms, runner, *bid) { + while idoms.contains_key(&runner) && !Self::dominates(&idoms, runner, *bid) { frontiers.entry(runner).or_insert_with(Vec::new).push(*bid); runner = idoms[&runner]; }