use crate::codegen::cfg::{BasicBlock, ControlFlowGraph, Instr, InstrOrigin};
use crate::codegen::reaching_definitions::block_edges;
use crate::codegen::subexpression_elimination::available_variable::AvailableVariable;
use crate::codegen::subexpression_elimination::common_subexpression_tracker::CommonSubExpressionTracker;
use crate::codegen::subexpression_elimination::operator::Operator;
use crate::sema::ast::Namespace;
use num_bigint::BigInt;
use std::cell::RefCell;
use std::collections::{HashMap, HashSet, VecDeque};
use std::rc::Rc;
mod available_expression;
mod available_expression_set;
mod available_variable;
pub mod common_subexpression_tracker;
mod expression;
mod instruction;
mod operator;
mod tests;
pub type NodeId = usize;
#[derive(Default)]
pub struct AvailableExpression {
global_id_counter: NodeId,
cur_block: usize,
}
#[derive(Clone)]
pub struct BasicExpression {
expr_type: ExpressionType,
expression_id: NodeId,
children: HashMap<NodeId, Rc<RefCell<BasicExpression>>>,
pub available_variable: AvailableVariable,
pub block: usize,
pub parent_block: usize,
pub on_parent_block: bool,
}
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
pub enum ConstantType {
Bool(bool),
Bytes(Vec<u8>),
Number(BigInt),
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum ExpressionType {
BinaryOperation(NodeId, NodeId, Operator),
UnaryOperation(NodeId, Operator),
Variable(usize),
FunctionArg(usize),
Literal(ConstantType),
}
#[derive(Default)]
pub struct AvailableExpressionSet {
expression_memory: HashMap<NodeId, Rc<RefCell<BasicExpression>>>,
expr_map: HashMap<ExpressionType, NodeId>,
parent_block_no: usize,
}
pub fn common_sub_expression_elimination(cfg: &mut ControlFlowGraph, ns: &mut Namespace) {
let mut ave = AvailableExpression::default();
let mut cst = CommonSubExpressionTracker::default();
let mut sets: HashMap<usize, AvailableExpressionSet> = HashMap::new();
let (visiting_order, dag) = find_visiting_order(cfg);
cst.set_dag(dag);
sets.insert(0, AvailableExpressionSet::default());
for (block_no, cycle) in &visiting_order {
let cur_block = &cfg.blocks[*block_no];
ave.set_cur_block(*block_no);
cst.set_cur_block(*block_no);
let mut cur_set = sets.remove(block_no).unwrap();
kill_loop_variables(cur_block, &mut cur_set, *cycle);
for (_, instr) in cur_block.instr.iter() {
cur_set.process_instruction(instr, &mut ave, &mut cst);
}
add_neighbor_blocks(cur_block, &cur_set, block_no, &mut sets, &cst);
}
cst.create_variables(ns, cfg);
sets.clear();
let mut ave = AvailableExpression::default();
sets.insert(0, AvailableExpressionSet::default());
for (block_no, cycle) in &visiting_order {
let mut cur_set = sets.remove(block_no).unwrap();
let mut cur_block = &mut cfg.blocks[*block_no];
ave.set_cur_block(*block_no);
cst.set_cur_block(*block_no);
let mut new_instructions: Vec<(InstrOrigin, Instr)> = Vec::new();
kill_loop_variables(cur_block, &mut cur_set, *cycle);
for (origin, instr) in cur_block.instr.iter() {
let instr = cur_set.regenerate_instruction(instr, &mut ave, &mut cst);
cst.add_new_instructions(&mut new_instructions);
new_instructions.push((origin.clone(), instr));
}
cur_block.instr = new_instructions;
add_neighbor_blocks(cur_block, &cur_set, block_no, &mut sets, &cst);
}
cst.add_parent_block_instructions(cfg);
}
fn add_neighbor_blocks(
cur_block: &BasicBlock,
cur_set: &AvailableExpressionSet,
block_no: &usize,
sets: &mut HashMap<usize, AvailableExpressionSet>,
cst: &CommonSubExpressionTracker,
) {
for edge in block_edges(cur_block) {
if let Some(set) = sets.get_mut(&edge) {
set.intersect_sets(cur_set, cst);
} else {
sets.insert(edge, cur_set.clone_for_parent_block(*block_no));
}
}
}
fn kill_loop_variables(block: &BasicBlock, cur_set: &mut AvailableExpressionSet, has_cycle: bool) {
if !has_cycle {
return;
}
for var_no in &block.loop_reaching_variables {
cur_set.kill(*var_no);
}
}
fn find_visiting_order(cfg: &ControlFlowGraph) -> (Vec<(usize, bool)>, Vec<Vec<usize>>) {
let mut order: Vec<(usize, bool)> = Vec::with_capacity(cfg.blocks.len());
let mut visited: HashSet<usize> = HashSet::new();
let mut stack: HashSet<usize> = HashSet::new();
let mut has_cycle: Vec<bool> = vec![false; cfg.blocks.len()];
let mut degrees: Vec<i32> = vec![0; cfg.blocks.len()];
let mut dag: Vec<Vec<usize>> = Vec::new();
dag.resize(cfg.blocks.len(), vec![]);
cfg_dfs(
0,
cfg,
&mut visited,
&mut stack,
&mut degrees,
&mut has_cycle,
&mut dag,
);
let mut queue: VecDeque<usize> = VecDeque::new();
queue.push_back(0);
while let Some(block_no) = queue.pop_front() {
order.push((block_no, has_cycle[block_no]));
for edge in block_edges(&cfg.blocks[block_no]) {
degrees[edge] -= 1;
if degrees[edge] == 0 {
queue.push_back(edge);
}
}
}
(order, dag)
}
fn cfg_dfs(
block_no: usize,
cfg: &ControlFlowGraph,
visited: &mut HashSet<usize>,
stack: &mut HashSet<usize>,
degrees: &mut Vec<i32>,
has_cycle: &mut Vec<bool>,
dag: &mut Vec<Vec<usize>>,
) -> bool {
if visited.contains(&block_no) {
return true;
}
if stack.contains(&block_no) {
degrees[block_no] -= 1;
has_cycle[block_no] = true;
return false;
}
stack.insert(block_no);
for edge in block_edges(&cfg.blocks[block_no]) {
degrees[edge] += 1;
if cfg_dfs(edge, cfg, visited, stack, degrees, has_cycle, dag) {
dag[block_no].push(edge);
}
}
stack.remove(&block_no);
visited.insert(block_no);
true
}