diff --git a/src/ir/func.rs b/src/ir/func.rs index 29ddbe1..826173a 100644 --- a/src/ir/func.rs +++ b/src/ir/func.rs @@ -135,6 +135,7 @@ impl FunctionBody { let cfg = crate::cfg::CFGInfo::new(self); crate::passes::basic_opt::gvn(self, &cfg); crate::passes::resolve_aliases::run(self); + crate::passes::ssa::run(self, &cfg); } pub fn convert_to_max_ssa(&mut self) { diff --git a/src/passes.rs b/src/passes.rs index 93de4ad..e0b36b0 100644 --- a/src/passes.rs +++ b/src/passes.rs @@ -6,3 +6,4 @@ pub mod empty_blocks; pub mod maxssa; pub mod resolve_aliases; pub mod trace; +pub mod ssa; diff --git a/src/passes/ssa.rs b/src/passes/ssa.rs new file mode 100644 index 0000000..283c0b9 --- /dev/null +++ b/src/passes/ssa.rs @@ -0,0 +1,56 @@ +//! SSA validation. + +use crate::cfg::CFGInfo; +use crate::entity::*; +use crate::ir::*; + +struct DefBlocks { + def_block: PerEntity, +} +impl DefBlocks { + fn compute(body: &FunctionBody) -> Self { + let mut def_block = PerEntity::default(); + for (block, data) in body.blocks.entries() { + for &(_, param) in &data.params { + def_block[param] = block; + } + for &inst in &data.insts { + def_block[inst] = block; + } + } + DefBlocks { def_block } + } +} + +pub fn run(body: &FunctionBody, cfg: &CFGInfo) { + let def_blocks = DefBlocks::compute(body); + + for (block, data) in body.blocks.entries() { + let validate = |value| { + let value = body.resolve_alias(value); + let def_block = def_blocks.def_block[value]; + assert!(cfg.dominates(def_block, block)); + }; + + for &inst in &data.insts { + match &body.values[inst] { + &ValueDef::Operator(_, ref args, _) => { + for &arg in args { + validate(arg); + } + } + &ValueDef::PickOutput(val, _, _) => { + validate(val); + } + &ValueDef::Trace(_, ref args) => { + for &arg in args { + validate(arg); + } + } + &ValueDef::Alias(..) => {} + &ValueDef::None | &ValueDef::Placeholder(_) | &ValueDef::BlockParam(..) => {} + } + } + data.terminator.visit_uses(|u| validate(u)); + } +}