use super::super::block::{Block, BlockId};
use super::super::func::Func;
use alloc::collections::BTreeMap;
pub trait DFA: Sized {
type Data;
const BACKWARDS: bool = false;
fn exec(&mut self, func: &Func) {
let mut executor = DFAExecutor::<Self>::new(func);
executor.init(self, func);
executor.exec(self, func);
self.complete(executor.inputs, executor.outputs);
}
fn init_block(&mut self, block: &Block, func: &Func) -> (Self::Data, Self::Data);
fn complete(
&mut self,
_inputs: BTreeMap<BlockId, Self::Data>,
_outputs: BTreeMap<BlockId, Self::Data>,
);
fn merge(&mut self, updating: &mut Self::Data, merge: &Self::Data, count: usize);
fn transfer(&mut self, block: &Block, start: &Self::Data, end: &mut Self::Data) -> bool;
}
struct DFAExecutor<T>
where
T: DFA,
{
inputs: BTreeMap<BlockId, <T as DFA>::Data>,
outputs: BTreeMap<BlockId, <T as DFA>::Data>,
work_list: Vec<BlockId>,
}
impl<T: DFA> DFAExecutor<T> {
fn new(func: &Func) -> Self {
Self {
inputs: BTreeMap::new(),
outputs: BTreeMap::new(),
work_list: func.get_block_ids(),
}
}
fn init(&mut self, dfa: &mut T, func: &Func) {
for block in func.get_blocks().iter() {
let (init_input, init_output) = dfa.init_block(block, func);
self.inputs.insert(block.get_id(), init_input);
self.outputs.insert(block.get_id(), init_output);
}
}
fn exec(&mut self, dfa: &mut T, func: &Func) {
while let Some(block_id) = self.work_list.pop() {
let block = func.get_block(block_id);
if T::BACKWARDS {
self.propagate_backward(dfa, block)
} else {
panic!("there aren't any forward propagations supported yet")
}
}
}
fn propagate_backward(&mut self, dfa: &mut T, block: &Block) {
let id = block.get_id();
let output = self.outputs.get_mut(&id).unwrap();
for (i, succ_id) in block.get_successors().iter().enumerate() {
let succ_input = self.inputs.get(succ_id).unwrap();
dfa.merge(output, succ_input, i);
}
let input = self.inputs.get_mut(&id).unwrap();
let output = self.outputs.get(&id).unwrap();
let update_flag = dfa.transfer(block, output, input);
if update_flag {
for pred_id in block.get_predecessors().iter() {
self.work_list.push(*pred_id);
}
}
}
}