diff --git a/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/dfs_ordering.rs b/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/dfs_ordering.rs deleted file mode 100644 index da6e548b..00000000 --- a/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/dfs_ordering.rs +++ /dev/null @@ -1,78 +0,0 @@ -use crate::ir::function::*; -use std::collections::HashMap; -/// This module implement depth frist search ordering algorithm -/// this algorithm can construct the order of CFG even if there -/// are cycle in CFG, the order can be use to iterative data flow -/// algorithm to reduce the time of iteration -use std::mem::take; -pub struct DFSOrdering { - index: usize, - marks: Vec, - orders: Vec, -} - -impl DFSOrdering { - /// Create a DFS ordering struct to get the order of blocks in a cfg. - pub fn new() -> Self { - Self { - index: 0, - marks: Vec::new(), - orders: Vec::new(), - } - } - /// Get order of CFG blocks, return a vec. frist element of vec - /// is the frist block of cfg - pub fn get_order(&mut self, entry_id: BasicBlock, blocks: &BasicBlockMap) -> Vec { - // init data - self.index = blocks.len(); - self.marks = vec![false; blocks.len()]; - // dfs ordering - self.dfs_visit(entry_id, blocks); - // take ownership of orders. - let mut orders = take(&mut self.orders); - orders.reverse(); - orders - } - fn dfs_visit(&mut self, block: BasicBlock, blocks: &BasicBlockMap) { - if self.marks[block.0 - 1] == true { - return; - } - self.marks[block.0 - 1] = true; - for sucessor in &blocks.get(&block).unwrap().successor { - self.dfs_visit(sucessor.clone(), blocks); - } - self.orders.push(block); - } - pub fn get_order_with_map( - &mut self, - entry_id: BasicBlock, - blocks: &BasicBlockMap, - ) -> (Vec, HashMap) { - let mut map = HashMap::new(); - // init data - self.index = blocks.len(); - self.marks = vec![false; blocks.len()]; - // dfs ordering - self.dfs_visit_with_map(entry_id, blocks, &mut map); - // take ownership of orders. - let mut orders = take(&mut self.orders); - orders.reverse(); - (orders, map) - } - fn dfs_visit_with_map( - &mut self, - block: BasicBlock, - blocks: &BasicBlockMap, - map: &mut HashMap, - ) { - if self.marks[block.0 - 1] == true { - return; - } - self.marks[block.0 - 1] = true; - for sucessor in &blocks.get(&block).unwrap().successor { - self.dfs_visit_with_map(sucessor.clone(), blocks, map); - } - map.insert(block, self.index); - self.orders.push(block); - } -} diff --git a/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/dfs_ordering/debugger.rs b/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/dfs_ordering/debugger.rs new file mode 100644 index 00000000..333565ca --- /dev/null +++ b/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/dfs_ordering/debugger.rs @@ -0,0 +1,25 @@ +use super::DFSOrdering; +use crate::ir::function::BasicBlock; +use crate::ir::function::Function; +use crate::ir_optimizer::anaylsis::DebuggerAnaylsis; +use crate::ir_optimizer::print_table_helper::{get_max_block_id_len, print_divider, print_header}; + +impl DebuggerAnaylsis> for DFSOrdering { + fn debugger(&mut self, function: &Function, table: &Vec) -> String { + let mut output_string = String::new(); + let max_block_id_len = get_max_block_id_len(function); + let row_len = if "DFS Ordering".len() > max_block_id_len { + "DFS Ordering".len() + 2 + } else { + max_block_id_len + 2 + }; + output_string.push_str(print_divider(row_len).as_str()); + output_string.push_str(print_header("DFS Ordering", row_len).as_str()); + output_string.push_str(print_divider(row_len).as_str()); + for block in table { + output_string.push_str(&print_header(format!("BB {}", block.0).as_str(), row_len)); + } + output_string.push_str(print_divider(row_len).as_str()); + output_string + } +} diff --git a/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/dfs_ordering/mod.rs b/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/dfs_ordering/mod.rs new file mode 100644 index 00000000..953b437b --- /dev/null +++ b/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/dfs_ordering/mod.rs @@ -0,0 +1,83 @@ +mod debugger; + +use crate::ir::function::*; +use crate::ir_optimizer::anaylsis::OptimizerAnaylsis; +/// This module implement depth frist search ordering algorithm +/// this algorithm can construct the order of CFG even if there +/// are cycle in CFG, the order can be use to iterative data flow +/// algorithm to reduce the time of iteration +use std::mem::take; +pub struct DFSOrdering { + index: usize, + marks: Vec, + orders: Vec, +} + +impl OptimizerAnaylsis> for DFSOrdering { + fn anaylsis(&mut self, function: &Function) -> Vec { + let entry_id = function.entry_block[0]; + let blocks = &function.blocks; + // init data + self.index = blocks.len(); + self.marks = vec![false; blocks.len()]; + // dfs ordering + self.dfs_visit(entry_id, blocks); + // take ownership of orders. + let mut orders = take(&mut self.orders); + orders.reverse(); + orders + } +} + +impl DFSOrdering { + /// Create a DFS ordering struct to get the order of blocks in a cfg. + pub fn new() -> Self { + Self { + index: 0, + marks: Vec::new(), + orders: Vec::new(), + } + } + fn dfs_visit(&mut self, block: BasicBlock, blocks: &BasicBlockMap) { + if self.marks[block.0 - 1] == true { + return; + } + self.marks[block.0 - 1] = true; + for sucessor in &blocks.get(&block).unwrap().successor { + self.dfs_visit(sucessor.clone(), blocks); + } + self.orders.push(block); + } + // pub fn get_order_with_map( + // &mut self, + // entry_id: BasicBlock, + // blocks: &BasicBlockMap, + // ) -> (Vec, HashMap) { + // let mut map = HashMap::new(); + // // init data + // self.index = blocks.len(); + // self.marks = vec![false; blocks.len()]; + // // dfs ordering + // self.dfs_visit_with_map(entry_id, blocks, &mut map); + // // take ownership of orders. + // let mut orders = take(&mut self.orders); + // orders.reverse(); + // (orders, map) + // } + // fn dfs_visit_with_map( + // &mut self, + // block: BasicBlock, + // blocks: &BasicBlockMap, + // map: &mut HashMap, + // ) { + // if self.marks[block.0 - 1] == true { + // return; + // } + // self.marks[block.0 - 1] = true; + // for sucessor in &blocks.get(&block).unwrap().successor { + // self.dfs_visit_with_map(sucessor.clone(), blocks, map); + // } + // map.insert(block, self.index); + // self.orders.push(block); + // } +} diff --git a/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/domtree/mod.rs b/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/domtree/mod.rs index 43de4d79..8730879a 100644 --- a/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/domtree/mod.rs +++ b/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/domtree/mod.rs @@ -68,7 +68,7 @@ impl DomAnaylsier { // iterative algorithm for dom data flow analysis let mut is_change = true; let mut dfs_ordering_anaylsiser = DFSOrdering::new(); - let ordering = dfs_ordering_anaylsiser.get_order(function.entry_block[0], &function.blocks); + let ordering = dfs_ordering_anaylsiser.anaylsis(function); while is_change { is_change = false; for block_id in &ordering { diff --git a/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/use_def_chain.rs b/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/use_def_chain.rs deleted file mode 100644 index 25c0f1ae..00000000 --- a/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/use_def_chain.rs +++ /dev/null @@ -1,482 +0,0 @@ -use crate::ir::function::*; -use crate::ir::instructions::*; -use crate::ir::value::*; -use std::collections::{HashMap, HashSet}; -use std::mem::replace; - -pub type ValueTuple = (BasicBlock, Instruction, Value); -/// Def table, mapping a Value in right hand side of three-address code -/// to a definition (a instruction assign a value). -pub type DefTable = HashMap; -/// Use table, mapping the Value in left hand side of three-address code -/// to a series of use (instruction use value in right hand side). -pub type UseTable = HashMap>; -/// Use -#[derive(Debug, Clone, PartialEq)] -pub enum DefKind { - InternalDef(Instruction), - ParamDef(Value), - ExternalDef, -} -/// A struct for a basic block, contain information that every value in -/// this basic block's use and def relationship. -#[derive(Debug, Clone, PartialEq)] -pub struct UseDefEntry { - pub use_table: UseTable, - pub def_table: DefTable, -} -/// Mapping basic block to use-def-table. -pub type UseDefTable = HashMap; - -/// Struct for building use def table for a functioon. -pub struct UseDefAnaylsier { - /// a value is def in - def_cache: HashMap, - /// a value is used in set of blocks - use_cache: HashMap>, - use_def_table: UseDefTable, -} - -impl UseDefAnaylsier { - /// Create a new use-def anayliser. - pub fn new() -> Self { - Self { - def_cache: HashMap::new(), - use_cache: HashMap::new(), - use_def_table: HashMap::new(), - } - } - /// Anaylsis use-def relation for a function (CFG). - pub fn anaylsis(&mut self, function: &Function) -> UseDefTable { - // this anaylsis use two iter to add all use-def relation. - // - frist iterate find all def and use as a tuple mapping - // - second iterate fill all relation aoccroding to cache. - self.find_all_use_def_tuple(function); - self.fill_table_with_cache(function); - self.def_cache.clear(); - self.use_cache.clear(); - replace(&mut self.use_def_table, HashMap::new()) - } - fn find_all_use_def_tuple(&mut self, function: &Function) { - for (block_id, bb) in &function.blocks { - self.use_def_table.insert( - block_id.clone(), - UseDefEntry { - use_table: HashMap::new(), - def_table: HashMap::new(), - }, - ); - for inst_id in &bb.instructions { - let inst = function.instructions.get(inst_id).unwrap(); - match inst { - InstructionData::Add { - opcode: _, - src1, - src2, - dst, - } - | InstructionData::Sub { - opcode: _, - src1, - src2, - dst, - } - | InstructionData::Mul { - opcode: _, - src1, - src2, - dst, - } - | InstructionData::Divide { - opcode: _, - src1, - src2, - dst, - } - | InstructionData::Reminder { - opcode: _, - src1, - src2, - dst, - } - | InstructionData::FAdd { - opcode: _, - src1, - src2, - dst, - } - | InstructionData::FSub { - opcode: _, - src1, - src2, - dst, - } - | InstructionData::FMul { - opcode: _, - src1, - src2, - dst, - } - | InstructionData::FDivide { - opcode: _, - src1, - src2, - dst, - } - | InstructionData::FReminder { - opcode: _, - src1, - src2, - dst, - } - | InstructionData::BitwiseAnd { - opcode: _, - src1, - src2, - dst, - } - | InstructionData::BitwiseOR { - opcode: _, - src1, - src2, - dst, - } - | InstructionData::LogicalAnd { - opcode: _, - src1, - src2, - dst, - } - | InstructionData::LogicalOR { - opcode: _, - src1, - src2, - dst, - } - | InstructionData::ShiftLeft { - opcode: _, - src1, - src2, - dst, - } - | InstructionData::ShiftRight { - opcode: _, - src1, - src2, - dst, - } => { - if self.is_value_register(dst, function) { - self.add_to_def_cache(dst.clone(), block_id.clone(), inst_id.clone()) - } - if self.is_value_register(src1, function) { - self.add_to_use_cache(src1.clone(), block_id.clone(), inst_id.clone()) - } - if self.is_value_register(src2, function) { - self.add_to_use_cache(src2.clone(), block_id.clone(), inst_id.clone()) - } - } - InstructionData::Neg { - opcode: _, - src, - dst, - } - | InstructionData::BitwiseNot { - opcode: _, - src, - dst, - } - | InstructionData::LogicalNot { - opcode: _, - src, - dst, - } - | InstructionData::ToU8 { - opcode: _, - src, - dst, - } - | InstructionData::ToU16 { - opcode: _, - src, - dst, - } - | InstructionData::ToU32 { - opcode: _, - src, - dst, - } - | InstructionData::ToU64 { - opcode: _, - src, - dst, - } - | InstructionData::ToI16 { - opcode: _, - src, - dst, - } - | InstructionData::ToI32 { - opcode: _, - src, - dst, - } - | InstructionData::ToI64 { - opcode: _, - src, - dst, - } - | InstructionData::ToF32 { - opcode: _, - src, - dst, - } - | InstructionData::ToF64 { - opcode: _, - src, - dst, - } - | InstructionData::ToAddress { - opcode: _, - src, - dst, - } => { - if self.is_value_register(dst, function) { - self.add_to_def_cache(dst.clone(), block_id.clone(), inst_id.clone()) - } - if self.is_value_register(src, function) { - self.add_to_use_cache(src.clone(), block_id.clone(), inst_id.clone()) - } - } - InstructionData::Icmp { - opcode: _, - flag: _1, - src1, - src2, - dst, - } - | InstructionData::Fcmp { - opcode: _, - flag: _1, - src1, - src2, - dst, - } => { - if self.is_value_register(dst, function) { - self.add_to_def_cache(dst.clone(), block_id.clone(), inst_id.clone()) - } - if self.is_value_register(src1, function) { - self.add_to_use_cache(src1.clone(), block_id.clone(), inst_id.clone()) - } - if self.is_value_register(src2, function) { - self.add_to_use_cache(src2.clone(), block_id.clone(), inst_id.clone()) - } - } - InstructionData::StoreRegister { - opcode: _, - base, - offset, - src, - data_type: _1, - } => { - if self.is_value_register(base, function) { - self.add_to_use_cache(base.clone(), block_id.clone(), inst_id.clone()) - } - if self.is_value_register(offset, function) { - self.add_to_use_cache(offset.clone(), block_id.clone(), inst_id.clone()) - } - if self.is_value_register(src, function) { - self.add_to_use_cache(src.clone(), block_id.clone(), inst_id.clone()) - } - } - InstructionData::LoadRegister { - opcode: _, - base, - offset, - dst, - data_type: _1, - } => { - if self.is_value_register(dst, function) { - self.add_to_def_cache(dst.clone(), block_id.clone(), inst_id.clone()) - } - if self.is_value_register(base, function) { - self.add_to_use_cache(base.clone(), block_id.clone(), inst_id.clone()) - } - if self.is_value_register(offset, function) { - self.add_to_use_cache(offset.clone(), block_id.clone(), inst_id.clone()) - } - } - InstructionData::Jump { opcode: _, dst: _1 } => {} - InstructionData::BrIf { - opcode: _, - test, - conseq: _1, - alter: _2, - } => { - if self.is_value_register(test, function) { - self.add_to_use_cache(test.clone(), block_id.clone(), inst_id.clone()) - } - } - InstructionData::StackAlloc { - opcode: _, - size: _1, - align: _2, - dst, - ir_type: _4, - } => { - if self.is_value_register(dst, function) { - self.add_to_def_cache(dst.clone(), block_id.clone(), inst_id.clone()) - } - } - InstructionData::Move { - opcode: _, - src, - dst, - } => { - if self.is_value_register(dst, function) { - self.add_to_def_cache(dst.clone(), block_id.clone(), inst_id.clone()) - } - if self.is_value_register(src, function) { - self.add_to_use_cache(src.clone(), block_id.clone(), inst_id.clone()) - } - } - InstructionData::Call { - opcode: _, - name: _1, - params, - dst, - } => { - for value in params { - if self.is_value_register(value, function) { - self.add_to_use_cache( - value.clone(), - block_id.clone(), - inst_id.clone(), - ) - } - } - match dst { - Some(value) => { - self.add_to_def_cache( - value.clone(), - block_id.clone(), - inst_id.clone(), - ); - } - None => {} - }; - } - InstructionData::Ret { opcode: _, value } => { - if let Some(val) = value { - if self.is_value_register(val, function) { - self.add_to_use_cache( - val.clone(), - block_id.clone(), - inst_id.clone(), - ); - } - } - } - InstructionData::Phi { - opcode: _, - dst, - from, - } => { - if self.is_value_register(dst, function) { - self.add_to_def_cache(dst.clone(), block_id.clone(), inst_id.clone()) - } - for (_block, value) in from { - if self.is_value_register(value, function) { - self.add_to_use_cache( - value.clone(), - block_id.clone(), - inst_id.clone(), - ); - } - } - } - InstructionData::Comment(_) => {} - } - } - } - } - fn fill_table_with_cache(&mut self, function: &Function) { - for (use_value, use_blocks_and_insts) in &self.use_cache { - match self.def_cache.get(use_value) { - Some(def) => { - let (def_block_id, def_inst_id) = def; - for (use_block_id, use_inst_id) in use_blocks_and_insts { - // add use to def - let used_entry = self.use_def_table.get_mut(use_block_id).unwrap(); - let def_table = &mut used_entry.def_table; - def_table - .insert(use_value.clone(), DefKind::InternalDef(def_inst_id.clone())); - // get table of def block id, and insert use value to that table. - let def_entry = self.use_def_table.get_mut(def_block_id).unwrap(); - let use_table = &mut def_entry.use_table; - if use_table.contains_key(use_value) { - use_table - .get_mut(use_value) - .unwrap() - .insert(use_inst_id.clone()); - } else { - use_table - .insert(use_value.clone(), HashSet::from([use_inst_id.clone()])); - } - } - } - None => { - if function.params_value.contains(use_value) { - let entry_id = function.entry_block[0].clone(); - for (use_block_id, use_inst_id) in use_blocks_and_insts { - // add def-relation to use - let used_entry = self.use_def_table.get_mut(use_block_id).unwrap(); - let def_table = &mut used_entry.def_table; - def_table - .insert(use_value.clone(), DefKind::ParamDef(use_value.clone())); - // get use-relation to def - let def_entry = self.use_def_table.get_mut(&entry_id).unwrap(); - let use_table = &mut def_entry.use_table; - if use_table.contains_key(use_value) { - use_table - .get_mut(use_value) - .unwrap() - .insert(use_inst_id.clone()); - } else { - use_table.insert( - use_value.clone(), - HashSet::from([use_inst_id.clone()]), - ); - } - } - } else { - // reference to global value - todo!() - } - } - } - } - } - /// add value and related info to def cache - fn add_to_def_cache(&mut self, value: Value, block: BasicBlock, inst: Instruction) { - self.def_cache.insert(value, (block, inst)); - } - /// add a value and related info to use cache. - fn add_to_use_cache(&mut self, value: Value, block: BasicBlock, inst: Instruction) { - if self.use_cache.contains_key(&value) { - let vec = self.use_cache.get_mut(&value).unwrap(); - vec.push((block, inst)); - } else { - self.use_cache.insert(value, vec![(block, inst)]); - } - } - /// test a value is virtual register or not. - fn is_value_register(&self, value: &Value, function: &Function) -> bool { - match function.values.get(value) { - Some(data) => match data { - ValueData::Immi(_) => false, - _ => true, - }, - None => panic!(), - } - } -} diff --git a/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/use_def_chain/debugger.rs b/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/use_def_chain/debugger.rs new file mode 100644 index 00000000..0fb64dab --- /dev/null +++ b/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/use_def_chain/debugger.rs @@ -0,0 +1,129 @@ +use std::collections::HashMap; + +use super::{DefKind, UseDefAnaylsier, UseDefTable, ValueData}; +use crate::ir::instructions::Instruction; +use crate::ir::value::Value; +use crate::ir_optimizer::anaylsis::DebuggerAnaylsis; +use crate::ir_optimizer::print_table_helper::{ + print_divider, print_header, print_table_row, sort_inst_ids, sort_value_ids, +}; + +impl DebuggerAnaylsis for UseDefAnaylsier { + fn debugger(&mut self, function: &super::Function, table: &UseDefTable) -> String { + let mut output_string = String::new(); + + // get all inst string and max inst string len + let mut inst_map_string: HashMap = HashMap::new(); + let mut max_len_of_insts = 0 as usize; + for (inst, inst_data) in &function.instructions { + let mut string = String::new(); + function.print_inst(&mut string, inst_data); + string = string.trim().to_string(); + if max_len_of_insts < string.len() { + max_len_of_insts = string.len(); + } + inst_map_string.insert(inst.clone(), string); + } + max_len_of_insts += 2; + // get all value string and max value len + let mut value_map_string: HashMap = HashMap::new(); + let mut max_len_of_value = 0 as usize; + for (value, value_data) in &function.values { + if let ValueData::VirRegister(reg) = value_data { + value_map_string.insert(value.clone(), reg.clone()); + if reg.len() > max_len_of_value { + max_len_of_value = reg.len(); + } + } + } + max_len_of_value += 2; + // get len of row + let max_len = max_len_of_insts + max_len_of_value + 1; + // print def table + output_string.push_str(print_divider(max_len).as_str()); + output_string.push_str(print_header("Def Table", max_len).as_str()); + output_string.push_str(print_divider(max_len).as_str()); + let values = table + .1 + .keys() + .into_iter() + .map(|k| k.clone()) + .collect::>(); + let sorted_values = sort_value_ids(values); + for value in sorted_values { + let def_kind = table.1.get(&value).unwrap(); + match def_kind { + DefKind::InternalDef(def_inst) => { + if let Some(reg_str) = value_map_string.get(&value) { + let inst_string = inst_map_string.get(def_inst).unwrap(); + output_string.push_str(&print_table_row( + reg_str, + inst_string, + max_len_of_value, + max_len_of_insts, + )); + } + } + DefKind::ParamDef(value) => { + if let Some(reg_str) = value_map_string.get(&value) { + let value_data = { + if let Some(val) = function.values.get(value) { + if let ValueData::VirRegister(reg) = val { + reg.clone() + } else { + panic!("[unreach]") + } + } else { + panic!("[unreach]") + } + }; + let right_string = format!("{}(param)", value_data); + output_string.push_str(&print_table_row( + reg_str, + &right_string, + max_len_of_value, + max_len_of_insts, + )); + } + } + _ => {} + } + } + output_string.push_str(print_divider(max_len).as_str()); + // print use table + output_string.push_str(print_divider(max_len).as_str()); + output_string.push_str(print_header("Use Table", max_len).as_str()); + output_string.push_str(print_divider(max_len).as_str()); + let values = table + .0 + .keys() + .into_iter() + .map(|k| k.clone()) + .collect::>(); + let sorted_values = sort_value_ids(values); + for value in sorted_values { + let insts = table.0.get(&value).unwrap(); + let mut index = 0 as usize; + let insts_len = insts.len(); + let sorted_insts = sort_inst_ids(insts.into_iter().map(|k| k.clone()).collect()); + for inst in &sorted_insts { + let left = if index != insts_len / 2 { + format!(" ") + } else { + value_map_string.get(&value).unwrap().clone() + }; + let inst_string = inst_map_string.get(inst).unwrap(); + //println!("{}", inst_string); + output_string.push_str(&print_table_row( + &left, + inst_string, + max_len_of_value, + max_len_of_insts, + )); + index += 1; + } + output_string.push_str(print_divider(max_len).as_str()); + } + output_string + } +} diff --git a/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/use_def_chain/mod.rs b/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/use_def_chain/mod.rs new file mode 100644 index 00000000..cabab88b --- /dev/null +++ b/compilers/rustyc/optimizer/src/ir_optimizer/anaylsis/use_def_chain/mod.rs @@ -0,0 +1,286 @@ +mod debugger; + +use crate::ir::function::*; +use crate::ir::instructions::*; +use crate::ir::value::*; +use crate::ir_optimizer::anaylsis::OptimizerAnaylsis; +use std::collections::{HashMap, HashSet}; +use std::mem::replace; + +#[derive(Debug, Clone, PartialEq)] +pub enum DefKind { + InternalDef(Instruction), + ParamDef(Value), + ExternalDef, +} + +pub type UseTable = HashMap>; +pub type DefTable = HashMap; +pub type UseDefTable = (UseTable, DefTable); + +/// Struct for building use def table for a functioon. +pub struct UseDefAnaylsier { + use_table: UseTable, + def_table: DefTable, +} + +impl OptimizerAnaylsis for UseDefAnaylsier { + /// Anaylsis use-def relation for a function (CFG). + fn anaylsis(&mut self, function: &Function) -> UseDefTable { + self.traversal_all_instruction_to_fill_use_def_table(function); + let use_table = replace(&mut self.use_table, HashMap::new()); + let def_table = replace(&mut self.def_table, HashMap::new()); + (use_table, def_table) + } +} + +impl UseDefAnaylsier { + /// Create a new use-def anayliser. + pub fn new() -> Self { + Self { + use_table: HashMap::new(), + def_table: HashMap::new(), + } + } + /// add value and related info to def cache + fn add_to_def_table(&mut self, value: Value, def_kind: DefKind, function: &Function) { + if !self.is_value_register(&value, function) { + return; + } + self.def_table.insert(value, def_kind); + } + /// add a value and related info to use cache. + fn add_to_use_table(&mut self, value: Value, inst: Instruction, function: &Function) { + if !self.is_value_register(&value, function) { + return; + } + if let Some(set) = self.use_table.get_mut(&value) { + set.insert(inst); + } else { + let mut set = HashSet::new(); + set.insert(inst); + self.use_table.insert(value, set); + } + } + /// test a value is virtual register or not. + fn is_value_register(&self, value: &Value, function: &Function) -> bool { + match function.values.get(value) { + Some(data) => match data { + ValueData::Immi(_) => false, + _ => true, + }, + None => panic!(), + } + } + fn traversal_all_instruction_to_fill_use_def_table(&mut self, function: &Function) { + for param in &function.params_value { + self.add_to_def_table(param.clone(), DefKind::ParamDef(param.clone()), function); + } + for (_, bb) in &function.blocks { + for inst_id in &bb.instructions { + let inst = function.instructions.get(inst_id).unwrap(); + match inst { + InstructionData::Add { + src1, src2, dst, .. + } + | InstructionData::Sub { + src1, src2, dst, .. + } + | InstructionData::Mul { + src1, src2, dst, .. + } + | InstructionData::Divide { + src1, src2, dst, .. + } + | InstructionData::Reminder { + src1, src2, dst, .. + } + | InstructionData::FAdd { + src1, src2, dst, .. + } + | InstructionData::FSub { + src1, src2, dst, .. + } + | InstructionData::FMul { + src1, src2, dst, .. + } + | InstructionData::FDivide { + src1, src2, dst, .. + } + | InstructionData::FReminder { + src1, src2, dst, .. + } + | InstructionData::BitwiseAnd { + src1, src2, dst, .. + } + | InstructionData::BitwiseOR { + src1, src2, dst, .. + } + | InstructionData::LogicalAnd { + src1, src2, dst, .. + } + | InstructionData::LogicalOR { + src1, src2, dst, .. + } + | InstructionData::ShiftLeft { + src1, src2, dst, .. + } + | InstructionData::ShiftRight { + src1, src2, dst, .. + } + | InstructionData::Icmp { + src1, src2, dst, .. + } + | InstructionData::Fcmp { + src1, src2, dst, .. + } => { + self.add_to_def_table( + dst.clone(), + DefKind::InternalDef(inst_id.clone()), + function, + ); + self.add_to_use_table(src1.clone(), inst_id.clone(), function); + self.add_to_use_table(src2.clone(), inst_id.clone(), function); + } + InstructionData::StoreRegister { + base, offset, src, .. + } => { + self.add_to_use_table(base.clone(), inst_id.clone(), function); + self.add_to_use_table(offset.clone(), inst_id.clone(), function); + self.add_to_use_table(src.clone(), inst_id.clone(), function); + } + InstructionData::LoadRegister { + base, offset, dst, .. + } => { + self.add_to_def_table( + dst.clone(), + DefKind::InternalDef(inst_id.clone()), + function, + ); + self.add_to_use_table(base.clone(), inst_id.clone(), function); + self.add_to_use_table(offset.clone(), inst_id.clone(), function); + } + InstructionData::Neg { + opcode: _, + src, + dst, + } + | InstructionData::BitwiseNot { + opcode: _, + src, + dst, + } + | InstructionData::LogicalNot { + opcode: _, + src, + dst, + } + | InstructionData::ToU8 { + opcode: _, + src, + dst, + } + | InstructionData::ToU16 { + opcode: _, + src, + dst, + } + | InstructionData::ToU32 { + opcode: _, + src, + dst, + } + | InstructionData::ToU64 { + opcode: _, + src, + dst, + } + | InstructionData::ToI16 { + opcode: _, + src, + dst, + } + | InstructionData::ToI32 { + opcode: _, + src, + dst, + } + | InstructionData::ToI64 { + opcode: _, + src, + dst, + } + | InstructionData::ToF32 { + opcode: _, + src, + dst, + } + | InstructionData::ToF64 { + opcode: _, + src, + dst, + } + | InstructionData::ToAddress { + opcode: _, + src, + dst, + } => { + self.add_to_def_table( + dst.clone(), + DefKind::InternalDef(inst_id.clone()), + function, + ); + self.add_to_use_table(src.clone(), inst_id.clone(), function); + } + InstructionData::BrIf { test, .. } => { + self.add_to_use_table(test.clone(), inst_id.clone(), function); + } + InstructionData::StackAlloc { dst, .. } => self.add_to_def_table( + dst.clone(), + DefKind::InternalDef(inst_id.clone()), + function, + ), + InstructionData::Move { src, dst, .. } => { + self.add_to_def_table( + dst.clone(), + DefKind::InternalDef(inst_id.clone()), + function, + ); + self.add_to_use_table(src.clone(), inst_id.clone(), function); + } + InstructionData::Call { params, dst, .. } => { + for value in params { + self.add_to_use_table(value.clone(), inst_id.clone(), function) + } + if let Some(value) = dst { + self.add_to_def_table( + value.clone(), + DefKind::InternalDef(inst_id.clone()), + function, + ); + }; + } + InstructionData::Ret { value, .. } => { + if let Some(val) = value { + self.add_to_use_table(val.clone(), inst_id.clone(), function); + } + } + InstructionData::Phi { dst, from, .. } => { + if self.is_value_register(dst, function) { + self.add_to_def_table( + dst.clone(), + DefKind::InternalDef(inst_id.clone()), + function, + ) + } + for (_block, value) in from { + self.add_to_use_table(value.clone(), inst_id.clone(), function); + } + } + InstructionData::Jump { opcode: _, dst: _1 } => {} + InstructionData::Comment(_) => {} + } + } + } + } +} diff --git a/compilers/rustyc/optimizer/src/ir_optimizer/pass/gvn/scope_table.rs b/compilers/rustyc/optimizer/src/ir_optimizer/pass/gvn/scope_table.rs index 4024b432..df4d599f 100644 --- a/compilers/rustyc/optimizer/src/ir_optimizer/pass/gvn/scope_table.rs +++ b/compilers/rustyc/optimizer/src/ir_optimizer/pass/gvn/scope_table.rs @@ -3,6 +3,7 @@ use crate::ir::function::{BasicBlock, Function}; use crate::ir::value::Value; use crate::ir_optimizer::anaylsis::dfs_ordering::DFSOrdering; use crate::ir_optimizer::anaylsis::domtree::DomTable; +use crate::ir_optimizer::anaylsis::OptimizerAnaylsis; use std::collections::HashMap; /// ## Scope Inst Cache Table @@ -93,8 +94,7 @@ pub fn sorted_dom_children_in_dfs_ordering<'a>( let mut dfs_order_anaylsis = DFSOrdering::new(); let mut id_map_order = HashMap::new(); let mut index = 0 as usize; - for block_id in dfs_order_anaylsis.get_order(function.entry_block[0].clone(), &function.blocks) - { + for block_id in dfs_order_anaylsis.anaylsis(&function) { id_map_order.insert(block_id, index); index += 1; } diff --git a/compilers/rustyc/optimizer/src/ir_optimizer/pass/lazy_code_motion.rs b/compilers/rustyc/optimizer/src/ir_optimizer/pass/lazy_code_motion.rs deleted file mode 100644 index 621792f5..00000000 --- a/compilers/rustyc/optimizer/src/ir_optimizer/pass/lazy_code_motion.rs +++ /dev/null @@ -1,895 +0,0 @@ -use crate::ir::function::{BasicBlock, Function}; -use crate::ir::instructions::{CmpFlag, Instruction, InstructionData, OpCode}; -use crate::ir::module::get_text_format_of_value; -use crate::ir::value::Value; -use crate::ir_optimizer::anaylsis::dfs_ordering::DFSOrdering; -use std::collections::{HashMap, HashSet}; - -use crate::ir_optimizer::anaylsis::domtree::DomTable; - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum RightHandSideInst { - Binary((Value, Value, OpCode)), - Unary((Value, OpCode)), - Cmp((Value, Value, CmpFlag)), -} - -impl RightHandSideInst { - pub fn get_value_ref(&self) -> Vec<&Value> { - match self { - RightHandSideInst::Binary((src1, src2, _)) - | RightHandSideInst::Cmp((src1, src2, _)) => { - vec![src1, src2] - } - RightHandSideInst::Unary((src, _)) => { - vec![src] - } - } - } -} -/// ## Right-Hand-Side-Expression Inst -/// Right hand side expression instruction set is used to storage -/// hash of right hand side expression. -pub type RightHandSideInstructionSet = HashSet; -/// ## Struct of Lazy code motion -pub struct LazyCodeMotionPass { - // use and kill expression set - pub expression_use: HashMap, - pub expression_kill: HashMap>, - // data flow result set - pub anticipate_in: HashMap, - pub anticipate_out: HashMap, - pub available_in: HashMap, - pub available_out: HashMap, - pub earliest: HashMap, - pub postponable_in: HashMap, - pub postponable_out: HashMap, - pub lastest: HashMap, - pub live_expr_in: HashMap, - pub live_expr_out: HashMap, - // ordering - pub dfs_order: Vec, - pub reverse_dfs_order: Vec, -} - -impl Default for LazyCodeMotionPass { - fn default() -> Self { - LazyCodeMotionPass::new() - } -} - -impl LazyCodeMotionPass { - pub fn new() -> Self { - Self { - expression_use: HashMap::new(), - expression_kill: HashMap::new(), - - anticipate_in: HashMap::new(), - anticipate_out: HashMap::new(), - available_in: HashMap::new(), - available_out: HashMap::new(), - postponable_in: HashMap::new(), - postponable_out: HashMap::new(), - live_expr_in: HashMap::new(), - live_expr_out: HashMap::new(), - earliest: HashMap::new(), - lastest: HashMap::new(), - - dfs_order: Vec::new(), - reverse_dfs_order: Vec::new(), - } - } - pub fn process(&mut self, function: &mut Function, dom_table: &DomTable) { - let mut dfs_pass = DFSOrdering::new(); - let mut ordering = dfs_pass.get_order(function.entry_block[0].clone(), &function.blocks); - self.dfs_order = ordering.clone(); - ordering.reverse(); - self.reverse_dfs_order = ordering; - - self.pass_get_kill_use_set(function); - self.pass_anticipate_expression(function); - self.pass_available_expression(function); - self.pass_earliest(); - self.pass_postponable(function); - self.pass_lastest(function); - self.pass_live_expr(function); - - self.pass_ssa_rewrite(function, dom_table) - } - fn get_right_hand_side_inst_key( - &self, - instruction: &InstructionData, - ) -> (Option, Option) { - match instruction { - InstructionData::Add { - opcode, - src1, - src2, - dst, - } - | InstructionData::Sub { - opcode, - src1, - src2, - dst, - } - | InstructionData::Mul { - opcode, - src1, - src2, - dst, - } - | InstructionData::Divide { - opcode, - src1, - src2, - dst, - } - | InstructionData::Reminder { - opcode, - src1, - src2, - dst, - } - | InstructionData::FAdd { - opcode, - src1, - src2, - dst, - } - | InstructionData::FSub { - opcode, - src1, - src2, - dst, - } - | InstructionData::FMul { - opcode, - src1, - src2, - dst, - } - | InstructionData::FDivide { - opcode, - src1, - src2, - dst, - } - | InstructionData::FReminder { - opcode, - src1, - src2, - dst, - } - | InstructionData::BitwiseAnd { - opcode, - src1, - src2, - dst, - } - | InstructionData::BitwiseOR { - opcode, - src1, - src2, - dst, - } - | InstructionData::LogicalAnd { - opcode, - src1, - src2, - dst, - } - | InstructionData::LogicalOR { - opcode, - src1, - src2, - dst, - } - | InstructionData::ShiftLeft { - opcode, - src1, - src2, - dst, - } - | InstructionData::ShiftRight { - opcode, - src1, - src2, - dst, - } => ( - Some(RightHandSideInst::Binary(( - src1.clone(), - src2.clone(), - opcode.clone(), - ))), - Some(dst.clone()), - ), - InstructionData::Neg { opcode, src, dst } - | InstructionData::BitwiseNot { opcode, src, dst } - | InstructionData::LogicalNot { opcode, src, dst } - | InstructionData::ToU8 { opcode, src, dst } - | InstructionData::ToU16 { opcode, src, dst } - | InstructionData::ToU32 { opcode, src, dst } - | InstructionData::ToU64 { opcode, src, dst } - | InstructionData::ToI16 { opcode, src, dst } - | InstructionData::ToI32 { opcode, src, dst } - | InstructionData::ToI64 { opcode, src, dst } - | InstructionData::ToF32 { opcode, src, dst } - | InstructionData::ToF64 { opcode, src, dst } - | InstructionData::ToAddress { opcode, src, dst } => ( - Some(RightHandSideInst::Unary((src.clone(), opcode.clone()))), - Some(dst.clone()), - ), - InstructionData::Icmp { - opcode: _, - flag, - src1, - src2, - dst, - } - | InstructionData::Fcmp { - opcode: _, - flag, - src1, - src2, - dst, - } => ( - Some(RightHandSideInst::Cmp(( - src1.clone(), - src2.clone(), - flag.clone(), - ))), - Some(dst.clone()), - ), - InstructionData::Move { dst, .. } - | InstructionData::Phi { dst, .. } - | InstructionData::LoadRegister { dst, .. } => (None, Some(dst.clone())), - _ => (None, None), - } - } - fn get_all_right_hand_expr_set(&self, function: &Function) -> RightHandSideInstructionSet { - let mut set = HashSet::new(); - for (_, data) in &function.instructions { - let tuple = self.get_right_hand_side_inst_key(data); - if let Some(key) = tuple.0 { - set.insert(key); - }; - } - set - } - /// ## Compute use and kill expression - /// Use expression is a expression is right hand - fn pass_get_kill_use_set(&mut self, function: &Function) { - for (block_id, block_data) in &function.blocks { - let mut expr_use_set = HashSet::new(); - let mut expr_kill_set = HashSet::new(); - - for inst in &block_data.instructions { - let inst_data = function.instructions.get(inst).unwrap(); - match self.get_right_hand_side_inst_key(inst_data) { - (Some(key), Some(value)) => { - expr_use_set.insert(key); - expr_kill_set.insert(value); - } - (Some(key), None) => { - expr_use_set.insert(key); - } - (None, Some(value)) => { - expr_kill_set.insert(value); - } - (None, None) => {} - } - } - self.expression_use.insert(block_id.clone(), expr_use_set); - self.expression_kill.insert(block_id.clone(), expr_kill_set); - } - } - /// ## Compute anticipate expression of each basic block. - /// A expression e is anticipate at the program point p if and only if there is a path from p to some - /// point a that use expression e before any re-define argument of expression e. - fn pass_anticipate_expression(&mut self, function: &Function) { - // init set - for (block_id, _) in &function.blocks { - let init_set = self.get_all_right_hand_expr_set(function); - self.anticipate_in.insert(block_id.clone(), init_set); - } - for block_id in &function.exit_block { - self.anticipate_in.insert(block_id.clone(), HashSet::new()); - } - // backward data flow iter algorithm - let mut change = true; - while change { - change = false; - // for every block, get out-set from predecessor's in-set. - // then get in-set from self-compute - for block_id in &self.reverse_dfs_order { - let block_data = function.blocks.get(block_id).unwrap(); - // Get out set from intersection of suceesor's in-set - let next_anticipate_out = { - let mut index = 0; - let mut next_set = HashSet::new(); - for sucessor_id in &block_data.successor { - if index == 0 { - next_set = self.anticipate_in.get(sucessor_id).unwrap().clone(); - } else { - next_set.retain(|key| { - self.anticipate_in.get(sucessor_id).unwrap().contains(key) - }) - } - index += 1; - } - next_set - }; - // Get in-set from transfer function - // remove expr which value in kill set, - // then union the use set. - self.anticipate_out - .insert(block_id.clone(), next_anticipate_out); - let next_anticipate_in = { - let mut next_set = self.anticipate_out.get(block_id).unwrap().clone(); - let kill_set = self.expression_kill.get(block_id).unwrap(); - next_set.retain(|key| { - let values = key.get_value_ref(); - for val in values { - if kill_set.contains(val) { - return false; - } - } - return true; - }); - let use_set = self.expression_use.get(block_id).unwrap().clone(); - next_set.extend(use_set.into_iter()); - next_set - }; - let existed_anticipate_in = self.anticipate_in.get(block_id).unwrap(); - if *existed_anticipate_in != next_anticipate_in { - change = true; - self.anticipate_in - .insert(block_id.clone(), next_anticipate_in); - } - } - } - } - /// ## Compute available expression - /// A expression e is available is - fn pass_available_expression(&mut self, function: &Function) { - // init as forward data flow anaylsis - for (block_id, _) in &function.blocks { - let init_set = self.get_all_right_hand_expr_set(function); - self.available_out.insert(block_id.clone(), init_set); - } - for block_id in &function.entry_block { - self.available_out.insert(block_id.clone(), HashSet::new()); - } - // forward data flow iter algorithm - let mut change = true; - while change { - change = false; - // for every block - for block_id in &self.dfs_order { - let block_data = function.blocks.get(block_id).unwrap(); - let next_available_in = { - let mut index = 0; - let mut next_set = HashSet::new(); - for predecessor_id in &block_data.predecessor { - let predecessor_out_set = self.available_out.get(predecessor_id).unwrap(); - if index == 0 { - next_set = predecessor_out_set.clone(); - } else { - next_set.retain(|key| predecessor_out_set.contains(key)) - } - index += 1; - } - next_set - }; - self.available_in - .insert(block_id.clone(), next_available_in); - let next_available_out = { - let mut out_set = self.available_in.get(block_id).unwrap().clone(); - let kill_set = self.expression_kill.get(block_id).unwrap(); - let anticipate_in = self.anticipate_in.get(block_id).unwrap(); - out_set.retain(|key| { - let values = key.get_value_ref(); - for val in values { - if kill_set.contains(val) { - return false; - }; - } - return true; - }); - 'out: for inst in anticipate_in { - let values = inst.get_value_ref(); - for val in values { - if kill_set.contains(val) { - continue 'out; - }; - } - out_set.insert(inst.clone()); - } - out_set - }; - let exised_avaiable_out = self.available_out.get(block_id).unwrap(); - if next_available_out != *exised_avaiable_out { - change = true; - self.available_out - .insert(block_id.clone(), next_available_out); - } - } - } - } - fn pass_earliest(&mut self) { - for (block_id, mut anticipate_set) in self.anticipate_in.clone() { - let aviailable = self.available_in.get(&block_id).unwrap(); - anticipate_set.retain(|inst| aviailable.contains(inst)); - self.earliest.insert(block_id, anticipate_set); - } - } - fn pass_postponable(&mut self, function: &Function) { - // init as forward data flow anaylsis - for (block_id, _) in &function.blocks { - let init_set = self.get_all_right_hand_expr_set(function); - self.postponable_out.insert(block_id.clone(), init_set); - } - for block_id in &function.entry_block { - self.postponable_out - .insert(block_id.clone(), HashSet::new()); - } - // forward data flow iter algorithm - let mut change = true; - while change { - change = false; - // for every block - for block_id in &self.dfs_order { - let block_data = function.blocks.get(block_id).unwrap(); - let next_postponable_in = { - let mut index = 0; - let mut next_set = HashSet::new(); - for predecessor_id in &block_data.predecessor { - let predecessor_out_set = self.postponable_out.get(predecessor_id).unwrap(); - if index == 0 { - next_set = predecessor_out_set.clone(); - } else { - next_set.retain(|key| predecessor_out_set.contains(key)) - } - index += 1; - } - next_set - }; - self.postponable_in - .insert(block_id.clone(), next_postponable_in); - let next_postponable_out = { - let mut out_set = self.postponable_in.get(block_id).unwrap().clone(); - out_set.extend(self.earliest.get(block_id).unwrap().clone().into_iter()); - let use_set = self.expression_use.get(block_id).unwrap(); - out_set.retain(|key| !use_set.contains(key)); - out_set - }; - let exised_postponable_out = self.postponable_out.get(block_id).unwrap(); - if next_postponable_out != *exised_postponable_out { - change = true; - self.postponable_out - .insert(block_id.clone(), next_postponable_out); - } - } - } - } - fn pass_lastest(&mut self, function: &Function) { - for (block_id, block_data) in &function.blocks { - // base case, earlest or postponable - let mut base = HashSet::new(); - base.extend(self.earliest.get(block_id).unwrap().clone().into_iter()); - base.extend( - self.postponable_in - .get(block_id) - .unwrap() - .clone() - .into_iter(), - ); - let mut other_base = base.clone(); - // use expression - let use_expr = self.expression_use.get(block_id).unwrap(); - base.retain(|inst| use_expr.contains(inst)); - // sucessor candi - let mut sucessor_candi = HashSet::new(); - for sucessor_id in &block_data.successor { - sucessor_candi.extend(self.earliest.get(sucessor_id).unwrap().clone().into_iter()); - sucessor_candi.extend( - self.postponable_in - .get(sucessor_id) - .unwrap() - .clone() - .into_iter(), - ); - } - other_base.retain(|key| !sucessor_candi.contains(key)); - base.extend(other_base.into_iter()); - self.lastest.insert(block_id.clone(), base); - } - } - fn pass_live_expr(&mut self, function: &Function) { - // init in-set - for (block_id, _) in &function.blocks { - self.live_expr_in - .insert(block_id.clone(), Default::default()); - } - let mut change = true; - while change { - change = false; - for block_id in &self.reverse_dfs_order { - let block_data = function.blocks.get(block_id).unwrap(); - let next_live_expr_out = { - let mut next_set = HashSet::new(); - let mut index = 0; - for sucessor_id in &block_data.successor { - let sucessor_live_expr_in = self.live_expr_in.get(sucessor_id).unwrap(); - if index == 0 { - next_set = sucessor_live_expr_in.clone(); - } else { - next_set.extend(sucessor_live_expr_in.clone().into_iter()); - } - index += 1; - } - next_set - }; - self.live_expr_out - .insert(block_id.clone(), next_live_expr_out); - let next_live_expr_in = { - let mut next_set = self.live_expr_out.get(block_id).unwrap().clone(); - let use_set = self.expression_use.get(block_id).unwrap().clone(); - next_set.extend(use_set.into_iter()); - let lastest = self.lastest.get(block_id).unwrap(); - next_set.retain(|key| !lastest.contains(key)); - next_set - }; - let existed_live_expr_in = self.live_expr_in.get(block_id).unwrap(); - if next_live_expr_in != *existed_live_expr_in { - change = true; - self.live_expr_in - .insert(block_id.clone(), next_live_expr_in); - } - } - } - } - fn pass_ssa_rewrite(&self, function: &mut Function, dom_table: &DomTable) { - let replace_key = self.pass_ssa_rewrite_find_all_replaceable_key(function); - let mut visited_key = HashSet::new(); - for (inst, inst_data, key, dst) in replace_key { - if visited_key.contains(&key) { - continue; - } - let (record_phis, record_new_insts) = self - .pass_ssa_rewrite_motion_inst_and_insert_phi_of_key( - function, dom_table, &key, &dst, &inst, &inst_data, - ); - self.pass_ssa_rewrite_rename_other_inst_of_key( - function.entry_block[0].clone(), - function, - &key, - &record_new_insts, - &record_phis, - &mut Vec::new(), - &mut HashSet::new(), - ); - visited_key.insert(key); - } - } - fn pass_ssa_rewrite_find_all_replaceable_key( - &self, - function: &Function, - ) -> Vec<(Instruction, InstructionData, RightHandSideInst, Value)> { - let mut replaceable_key = Vec::new(); - for (inst, inst_data) in &function.instructions { - match self.get_right_hand_side_inst_key(&inst_data) { - (Some(key), Some(dst)) => { - replaceable_key.push((inst.clone(), inst_data.clone(), key, dst)); - } - _ => {} - } - } - replaceable_key - } - fn pass_ssa_rewrite_motion_inst_and_insert_phi_of_key( - &self, - function: &mut Function, - dom_table: &DomTable, - key: &RightHandSideInst, - dst: &Value, - inst: &Instruction, - inst_data: &InstructionData, - ) -> (HashSet, HashSet) { - let mut record_phi = HashSet::new(); - let mut record_new_inst = HashSet::new(); - let mut motion_vec = Vec::new(); - let mut rewrite_to_copy_vec = Vec::new(); - let mut to_be_insert_phis = HashMap::new(); - for (block_id, _) in &function.blocks { - // If block is a lasest and live out contain a expression e - let lastest = self.lastest.get(block_id).unwrap(); - let live_expr_out = self.live_expr_out.get(block_id).unwrap(); - if lastest.contains(&key) && live_expr_out.contains(&key) { - // change inst to copy and motion inst to front of block - let data_type = function - .value_types - .get(&helper_get_dst_of_inst(inst_data)) - .unwrap() - .clone(); - motion_vec.push((block_id.clone(), inst_data.clone(), data_type)); - rewrite_to_copy_vec.push(inst.clone()); - // insert phi into domfrotier and record it - for df_block in &dom_table.get(block_id).unwrap().dom_frontier { - let data_type = function.value_types.get(dst).unwrap(); - to_be_insert_phis.insert(df_block.clone(), data_type.clone()); - } - } - } - let mut map_dst_value: Vec = Vec::new(); - for (block_id, mut motion_inst_data, data_type) in motion_vec { - let new_dst = function.add_register(data_type); - helper_rewrite_inst_dst(&mut motion_inst_data, new_dst); - let new_inst = function.insert_inst_to_block_front(&block_id, motion_inst_data); - let new_inst_data = function.instructions.get(&new_inst).unwrap(); - record_new_inst.insert(new_inst); - map_dst_value.push(helper_get_dst_of_inst(new_inst_data)); - } - let mut index = 0; - for inst_id in rewrite_to_copy_vec { - let data = function.instructions.get_mut(&inst_id).unwrap(); - let dst = helper_get_dst_of_inst(data); - *data = InstructionData::Move { - opcode: OpCode::Mov, - src: map_dst_value[index], - dst, - }; - index += 1; - } - for (block_id, data_type) in to_be_insert_phis { - let new_dst = function.add_register(data_type); - let phi_data = InstructionData::Phi { - opcode: OpCode::Phi, - dst: new_dst, - from: Vec::new(), - }; - let phi_inst = function.insert_inst_to_block_front(&block_id, phi_data); - record_phi.insert(phi_inst); - } - (record_phi, record_new_inst) - } - fn pass_ssa_rewrite_rename_other_inst_of_key( - &self, - block_id: BasicBlock, - function: &mut Function, - target_key: &RightHandSideInst, - record_new_insts: &HashSet, - record_phis: &HashSet, - stack: &mut Vec<(BasicBlock, Value)>, - mark: &mut HashSet, - ) { - for inst in &function.blocks.get(&block_id).unwrap().instructions { - let data = function.instructions.get_mut(inst).unwrap(); - if let InstructionData::Phi { from, .. } = data { - from.push(stack.last().unwrap().clone()); - } - } - if mark.contains(&block_id) { - return; - } - mark.insert(block_id.clone()); - let mut count = 0; - for inst in &function.blocks.get(&block_id).unwrap().instructions { - let data = function.instructions.get_mut(inst).unwrap(); - match data { - InstructionData::Phi { dst, .. } => { - if record_phis.contains(inst) { - stack.push((block_id.clone(), dst.clone())); - count += 1; - }; - } - _ => match self.get_right_hand_side_inst_key(data) { - (Some(inst_key), _) => { - if inst_key == *target_key { - if record_new_insts.contains(inst) { - stack.push((block_id.clone(), helper_get_dst_of_inst(data))); - count += 1; - } else { - let origin_dst = helper_get_dst_of_inst(&data); - let new_src = stack.last().unwrap().1; - *data = InstructionData::Move { - opcode: OpCode::Mov, - src: new_src, - dst: origin_dst, - } - } - } - } - _ => {} - }, - } - } - for sucessor_id in function.blocks.get(&block_id).unwrap().successor.clone() { - self.pass_ssa_rewrite_rename_other_inst_of_key( - sucessor_id, - function, - target_key, - record_new_insts, - record_phis, - stack, - mark, - ); - } - for _i in 0..count { - stack.pop(); - } - } -} -fn helper_get_dst_of_inst(inst_data: &InstructionData) -> Value { - match inst_data { - InstructionData::Add { dst, .. } - | InstructionData::Sub { dst, .. } - | InstructionData::Mul { dst, .. } - | InstructionData::Divide { dst, .. } - | InstructionData::Reminder { dst, .. } - | InstructionData::FAdd { dst, .. } - | InstructionData::FSub { dst, .. } - | InstructionData::FMul { dst, .. } - | InstructionData::FDivide { dst, .. } - | InstructionData::FReminder { dst, .. } - | InstructionData::BitwiseAnd { dst, .. } - | InstructionData::BitwiseOR { dst, .. } - | InstructionData::LogicalAnd { dst, .. } - | InstructionData::LogicalOR { dst, .. } - | InstructionData::ShiftLeft { dst, .. } - | InstructionData::ShiftRight { dst, .. } - | InstructionData::Neg { dst, .. } - | InstructionData::BitwiseNot { dst, .. } - | InstructionData::LogicalNot { dst, .. } - | InstructionData::ToU8 { dst, .. } - | InstructionData::ToU16 { dst, .. } - | InstructionData::ToU32 { dst, .. } - | InstructionData::ToU64 { dst, .. } - | InstructionData::ToI16 { dst, .. } - | InstructionData::ToI32 { dst, .. } - | InstructionData::ToI64 { dst, .. } - | InstructionData::ToF32 { dst, .. } - | InstructionData::ToF64 { dst, .. } - | InstructionData::ToAddress { dst, .. } - | InstructionData::Icmp { dst, .. } - | InstructionData::Fcmp { dst, .. } - | InstructionData::Move { dst, .. } - | InstructionData::Phi { dst, .. } - | InstructionData::LoadRegister { dst, .. } => dst.clone(), - _ => panic!(), - } -} -fn helper_rewrite_inst_dst(inst_data: &mut InstructionData, new_dst: Value) { - match inst_data { - InstructionData::Add { dst, .. } - | InstructionData::Sub { dst, .. } - | InstructionData::Mul { dst, .. } - | InstructionData::Divide { dst, .. } - | InstructionData::Reminder { dst, .. } - | InstructionData::FAdd { dst, .. } - | InstructionData::FSub { dst, .. } - | InstructionData::FMul { dst, .. } - | InstructionData::FDivide { dst, .. } - | InstructionData::FReminder { dst, .. } - | InstructionData::BitwiseAnd { dst, .. } - | InstructionData::BitwiseOR { dst, .. } - | InstructionData::LogicalAnd { dst, .. } - | InstructionData::LogicalOR { dst, .. } - | InstructionData::ShiftLeft { dst, .. } - | InstructionData::ShiftRight { dst, .. } - | InstructionData::Neg { dst, .. } - | InstructionData::BitwiseNot { dst, .. } - | InstructionData::LogicalNot { dst, .. } - | InstructionData::ToU8 { dst, .. } - | InstructionData::ToU16 { dst, .. } - | InstructionData::ToU32 { dst, .. } - | InstructionData::ToU64 { dst, .. } - | InstructionData::ToI16 { dst, .. } - | InstructionData::ToI32 { dst, .. } - | InstructionData::ToI64 { dst, .. } - | InstructionData::ToF32 { dst, .. } - | InstructionData::ToF64 { dst, .. } - | InstructionData::ToAddress { dst, .. } - | InstructionData::Icmp { dst, .. } - | InstructionData::Fcmp { dst, .. } - | InstructionData::Move { dst, .. } - | InstructionData::Phi { dst, .. } - | InstructionData::LoadRegister { dst, .. } => *dst = new_dst, - _ => panic!(), - } -} -/// Print all set table of lazy code motion, need function as argument to get the -/// instruction data. -pub fn print_lazy_code_motion_table(pass: &LazyCodeMotionPass, function: &Function) { - fn get_length_of_find_longest_set(sets: Vec<&RightHandSideInstructionSet>) -> usize { - let mut max_size = 0; - for set in sets { - if set.len() > max_size { - max_size = set.len(); - } - } - max_size - } - fn get_text_format_of_operator(opcode: &OpCode) -> &'static str { - match opcode { - OpCode::Add | OpCode::FAdd => "+", - OpCode::Divide | OpCode::FDivide => "/", - OpCode::Sub | OpCode::FSub | OpCode::Neg => "-", - OpCode::Mul | OpCode::FMul => "*", - OpCode::Reminder | OpCode::FReminder => "%", - OpCode::BitwiseAnd => "&", - OpCode::BitwiseNot => "~", - OpCode::BitwiseOR => "|", - OpCode::LogicalAnd => "&&", - OpCode::LogicalNot => "!", - OpCode::LogicalOR => "||", - _ => panic!(), - } - } - fn get_inst_string(instruction_key: &RightHandSideInst, function: &Function) -> String { - match instruction_key { - RightHandSideInst::Binary((src1, src2, opcode)) => { - let src1_string = get_text_format_of_value(function.values.get(src1).unwrap()); - let src2_string = get_text_format_of_value(function.values.get(src2).unwrap()); - let op_string = get_text_format_of_operator(opcode); - format!("{} {} {}", src1_string, op_string, src2_string) - } - RightHandSideInst::Unary((src, opcode)) => { - let src_string = get_text_format_of_value(function.values.get(src).unwrap()); - let op_string = get_text_format_of_operator(opcode); - format!(" {} {} ", op_string, src_string) - } - RightHandSideInst::Cmp((src1, src2, _cmp_flag)) => { - let src1_string = get_text_format_of_value(function.values.get(src1).unwrap()); - let src2_string = get_text_format_of_value(function.values.get(src2).unwrap()); - format!("{} {}", src1_string, src2_string) - } - } - } - fn print_right_hand_side_exprs_table( - table: &HashMap, - function: &Function, - ) { - let max_len = get_length_of_find_longest_set(table.values().collect()); - let mut inst_vec = vec![vec![String::from(" "); table.len()]; max_len]; - for (block_id, exprs) in table { - let col_index = block_id.0 - 1; - let mut row_index = 0; - for right_hand_expr in exprs { - inst_vec[row_index][col_index] = get_inst_string(right_hand_expr, function); - row_index += 1; - } - } - let mut block_id_string = String::new(); - for id in 0..function.blocks.len() { - block_id_string.push_str(format!("| {} ", id).as_str()) - } - block_id_string.push_str("|"); - let mut start_string = vec!["--------"; table.len()].join(""); - start_string.push_str("-"); - println!("{}", start_string); - println!("{}", block_id_string); - println!("{}", start_string); - for vec_string in inst_vec { - print!("|"); - for string in vec_string { - print!("{}", string); - print!("|"); - } - println!(""); - } - println!("{}", start_string); - } - print_right_hand_side_exprs_table(&pass.expression_use, function); - print_right_hand_side_exprs_table(&pass.anticipate_in, function); - print_right_hand_side_exprs_table(&pass.anticipate_out, function); - print_right_hand_side_exprs_table(&pass.available_in, function); - print_right_hand_side_exprs_table(&pass.available_out, function); - print_right_hand_side_exprs_table(&pass.earliest, function); - print_right_hand_side_exprs_table(&pass.postponable_in, function); - print_right_hand_side_exprs_table(&pass.postponable_out, function); - print_right_hand_side_exprs_table(&pass.lastest, function); - print_right_hand_side_exprs_table(&pass.live_expr_in, function); - print_right_hand_side_exprs_table(&pass.live_expr_out, function); -} diff --git a/compilers/rustyc/optimizer/src/ir_optimizer/pass/lcm/pre_proc.rs b/compilers/rustyc/optimizer/src/ir_optimizer/pass/lcm/pre_proc.rs index 08259f61..ef5f2ec7 100644 --- a/compilers/rustyc/optimizer/src/ir_optimizer/pass/lcm/pre_proc.rs +++ b/compilers/rustyc/optimizer/src/ir_optimizer/pass/lcm/pre_proc.rs @@ -2,6 +2,7 @@ use super::expr_key::get_dst_value; use super::LCMPass; use crate::ir::function::Function; use crate::ir_optimizer::anaylsis::dfs_ordering::DFSOrdering; +use crate::ir_optimizer::anaylsis::OptimizerAnaylsis; use std::collections::HashSet; impl LCMPass { @@ -41,7 +42,7 @@ impl LCMPass { } fn build_dfs_ordering(&mut self, function: &Function) { let mut dfs = DFSOrdering::new(); - self.dfs_order = dfs.get_order(function.entry_block[0].clone(), &function.blocks); + self.dfs_order = dfs.anaylsis(function); let mut reverse_dfs_order = self.dfs_order.clone(); reverse_dfs_order.reverse(); self.reverse_dfs_order = reverse_dfs_order; diff --git a/compilers/rustyc/optimizer/src/ir_optimizer/pass/mem2reg/mod.rs b/compilers/rustyc/optimizer/src/ir_optimizer/pass/mem2reg/mod.rs index 50567a91..2473c789 100644 --- a/compilers/rustyc/optimizer/src/ir_optimizer/pass/mem2reg/mod.rs +++ b/compilers/rustyc/optimizer/src/ir_optimizer/pass/mem2reg/mod.rs @@ -19,8 +19,7 @@ impl<'a> OptimizerPass for Mem2RegPass<'a> { let alloc_pointers_and_bb_ids = self.find_all_alloc_inst_from_entry_block(function); // insert phi is df of store inst of alloc use. for (alloc_pointer, inst_id, bb_id) in &alloc_pointers_and_bb_ids { - let use_def_entry = self.use_def_table.get(bb_id).unwrap(); - let use_table = &use_def_entry.use_table; + let use_table = &self.use_def_table.0; let use_set = use_table.get(alloc_pointer).unwrap(); // if have pointer access, skip let mut is_pointer_access = false; diff --git a/compilers/rustyc/optimizer/src/ir_optimizer/pass/mod.rs b/compilers/rustyc/optimizer/src/ir_optimizer/pass/mod.rs index 93c8f5e3..4e22fda9 100644 --- a/compilers/rustyc/optimizer/src/ir_optimizer/pass/mod.rs +++ b/compilers/rustyc/optimizer/src/ir_optimizer/pass/mod.rs @@ -1,6 +1,5 @@ pub mod copy_propagation; pub mod gvn; -pub mod lazy_code_motion; pub mod lcm; pub mod mem2reg; pub mod value_numbering; diff --git a/compilers/rustyc/optimizer/src/ir_optimizer/print_table_helper/mod.rs b/compilers/rustyc/optimizer/src/ir_optimizer/print_table_helper/mod.rs index d12c3ce3..6a2b131c 100644 --- a/compilers/rustyc/optimizer/src/ir_optimizer/print_table_helper/mod.rs +++ b/compilers/rustyc/optimizer/src/ir_optimizer/print_table_helper/mod.rs @@ -1,14 +1,37 @@ use crate::ir::function::BasicBlock; use crate::ir::function::Function; +use crate::ir::instructions::Instruction; +use crate::ir::value::Value; static DIVIDE_CHAR: &'static str = "-"; - +/// ## Print Table Header +/// print header like below format: +/// ```markdown +/// | {Header Name} | +/// ``` +/// - `total_len` is total space of header without `|` char. +/// - `name`: header name. pub fn print_header(name: &str, total_len: usize) -> String { format!("|{name:^total_len$}|\n") } +/// ## Print Divider of Table +/// print divider like below format: +/// ```markdown +/// |---------------| +/// ``` +/// - `total_len`: is total number `-` char without `|`. pub fn print_divider(total_len: usize) -> String { format!("|{DIVIDE_CHAR:->total_len$}|\n") } +/// ## Print table row +/// print row as below format: +/// ```markdown +/// | {left} | {right} | +/// ``` +/// - `left`: the content of left side of row. +/// - `left_len`: the total len size of left. +/// - `right`: the content of right side of row. +/// - `right_len`: the total len size of right. pub fn print_table_row(left: &str, right: &str, left_len: usize, right_len: usize) -> String { format!("|{left:^left_len$}|{right:^right_len$}|\n") } @@ -22,6 +45,8 @@ pub fn get_max_block_id_len(function: &Function) -> usize { } max_block_id_len } +/// ## Sorted blocks +/// sorted block ids by values usize by bubble sort. pub fn sort_block_ids(mut block_ids: Vec) -> Vec { if block_ids.len() == 0 { return block_ids; @@ -37,3 +62,37 @@ pub fn sort_block_ids(mut block_ids: Vec) -> Vec { } block_ids } +/// ## Sorted Values +/// sorted value ids by value's usize by bubble sort. +pub fn sort_value_ids(mut value_ids: Vec) -> Vec { + if value_ids.len() == 0 { + return value_ids; + } + for i in 0..value_ids.len() - 1 { + for j in 0..(value_ids.len() - 1 - i) { + if value_ids[j].0 > value_ids[j + 1].0 { + let temp = value_ids[j]; + value_ids[j] = value_ids[j + 1]; + value_ids[j + 1] = temp; + } + } + } + value_ids +} +/// ## Sorted Instructions +/// sorted Instructions ids by instruction's usize by bubble sort. +pub fn sort_inst_ids(mut inst_ids: Vec) -> Vec { + if inst_ids.len() == 0 { + return inst_ids; + } + for i in 0..inst_ids.len() - 1 { + for j in 0..(inst_ids.len() - 1 - i) { + if inst_ids[j].0 > inst_ids[j + 1].0 { + let temp = inst_ids[j]; + inst_ids[j] = inst_ids[j + 1]; + inst_ids[j + 1] = temp; + } + } + } + inst_ids +} diff --git a/compilers/rustyc/optimizer/src/main.rs b/compilers/rustyc/optimizer/src/main.rs index 7599f652..83b47f62 100644 --- a/compilers/rustyc/optimizer/src/main.rs +++ b/compilers/rustyc/optimizer/src/main.rs @@ -5,6 +5,7 @@ pub mod ir_optimizer; use crate::ir::function::Function; use crate::ir_converter::Converter; use ir::value::IrValueType; +use ir_optimizer::anaylsis::dfs_ordering::DFSOrdering; use ir_optimizer::anaylsis::{DebuggerAnaylsis, OptimizerAnaylsis}; use ir_optimizer::pass::{DebuggerPass, OptimizerPass}; use rustyc_frontend::parser::Parser; @@ -15,9 +16,6 @@ use crate::ir_optimizer::anaylsis::domtree::DomAnaylsier; use crate::ir_optimizer::anaylsis::use_def_chain::*; use crate::ir_optimizer::pass::copy_propagation::CopyPropagationPass; use crate::ir_optimizer::pass::gvn::GVNPass; -use crate::ir_optimizer::pass::lazy_code_motion::{ - print_lazy_code_motion_table, LazyCodeMotionPass, -}; use crate::ir_optimizer::pass::lcm::LCMPass; use crate::ir_optimizer::pass::mem2reg::Mem2RegPass; use crate::ir_optimizer::pass::value_numbering::ValueNumberingPass; @@ -44,16 +42,16 @@ fn main() { // println!("{:#?}", program); // let mut converter = Converter::new(); // let module = converter.convert(&program); - let mut func = create_gvn_graph_from_conrnell(); - let mut dom_anaylsis = DomAnaylsier::new(); - let table = dom_anaylsis.anaylsis(&func); - let out = dom_anaylsis.debugger(&func, &table); + let func = create_gvn_graph_from_conrnell(); + let mut use_def_anaylsier = DFSOrdering::new(); + let table = use_def_anaylsier.anaylsis(&func); + let out = use_def_anaylsier.debugger(&func, &table); // let mut lcm_pass = LCMPass::new(); // lcm_pass.process(&mut func); // let mut file = File::create("./test1.txt").unwrap(); // write!(file,"{}", func.print_to_string()).unwrap(); // let out = lcm_pass.debugger(&func); - let mut file1 = File::create("./debug.txt").unwrap(); + let mut file1 = File::create("./test.txt").unwrap(); write!(file1, "{}", out).unwrap(); // lcm_pass.process(&mut func); @@ -113,7 +111,7 @@ pub fn create_reducnt_expr_graph() -> Function { } /// Create simple graph to test use-def information: -/// ``` +/// ```markdown /// t0 = 10; /// t1 = 1000; /// -------- @@ -140,38 +138,15 @@ pub fn create_use_def_graph() -> Function { let b2 = func.create_block(); func.switch_to_block(b2); let _t4 = func.build_add_inst(t1, t3); + // mark entry exit + func.mark_as_exit(b2); + func.mark_as_entry(b0); + // connect + func.connect_block(b0, b1); + func.connect_block(b1, b2); func } -/// Create simple graph for test dom data flow anaylsis. -/// struct of graph please reference to -pub fn create_dom_graph() -> Function { - let mut function = Function::new(String::from("test_fun")); - let b0 = function.create_block(); - let b1 = function.create_block(); - let b2 = function.create_block(); - let b3 = function.create_block(); - let b4 = function.create_block(); - let b5 = function.create_block(); - let b6 = function.create_block(); - let b7 = function.create_block(); - let b8 = function.create_block(); - - function.connect_block(b0, b1); - function.connect_block(b1, b2); - function.connect_block(b2, b3); - function.connect_block(b3, b4); - function.connect_block(b3, b1); - - function.connect_block(b1, b5); - function.connect_block(b5, b6); - function.connect_block(b5, b8); - function.connect_block(b6, b7); - function.connect_block(b8, b7); - function.connect_block(b7, b3); - function -} - fn create_gvn_graph_from_conrnell() -> Function { let mut function = Function::new(String::from("test_fun")); let b1 = function.create_block(); @@ -233,11 +208,11 @@ fn create_gvn_graph_from_conrnell() -> Function { function } -fn create_lcm_test_graph() -> Function { - let mut function = Function::new(String::from("test_lcm_from_cmu")); - // create blocks - let entry = function.create_block(); - function.mark_as_entry(entry); +/// ## Generate Test function for DOM +/// This function is reference from the book `Engineering a Compiler 2/e` p499 +pub fn create_dom_graph_example() -> Function { + let mut function = Function::new(String::from("test_fun")); + let b0 = function.create_block(); let b1 = function.create_block(); let b2 = function.create_block(); let b3 = function.create_block(); @@ -246,39 +221,22 @@ fn create_lcm_test_graph() -> Function { let b6 = function.create_block(); let b7 = function.create_block(); let b8 = function.create_block(); - let b9 = function.create_block(); - let b10 = function.create_block(); - let exit = function.create_block(); - function.mark_as_exit(exit); - // connect - function.connect_block(entry, b1); + function.connect_block(b0, b1); function.connect_block(b1, b2); - function.connect_block(b2, b3); function.connect_block(b3, b4); - function.connect_block(b4, b3); - function.connect_block(b4, b5); - function.connect_block(b5, b6); - function.connect_block(b6, b10); - - function.connect_block(b2, b7); - function.connect_block(b7, b8); - function.connect_block(b8, b9); - function.connect_block(b9, b10); + function.connect_block(b3, b1); - function.connect_block(b10, exit); + function.connect_block(b1, b5); + function.connect_block(b5, b6); + function.connect_block(b5, b8); + function.connect_block(b6, b7); + function.connect_block(b8, b7); + function.connect_block(b7, b3); - // inst - function.switch_to_block(b1); - let u8_const = function.create_u8_const(1); - let b = function.build_mov_inst(u8_const); - let u8_const_1 = function.create_u8_const(1); - let c = function.build_mov_inst(u8_const_1); - function.switch_to_block(b7); - function.build_add_inst(b, c); - function.switch_to_block(b10); - function.build_add_inst(b, c); + function.mark_as_entry(b0); + function.mark_as_exit(b4); function } diff --git a/compilers/rustyc/optimizer/tests/build_ir_graph.rs b/compilers/rustyc/optimizer/tests/build_ir_graph.rs index bf5adbea..5a58e1c6 100644 --- a/compilers/rustyc/optimizer/tests/build_ir_graph.rs +++ b/compilers/rustyc/optimizer/tests/build_ir_graph.rs @@ -20,7 +20,6 @@ pub fn create_lcm_test_graph() -> Function { let b10 = function.create_block(); let exit = function.create_block(); function.mark_as_exit(exit); - // connect function.connect_block(entry, b1); function.connect_block(b1, b2); @@ -52,9 +51,6 @@ pub fn create_lcm_test_graph() -> Function { function } -/// ## Generate Test Function For LCM 2 -/// This function is reference from dragon book lazy code motion section. -pub fn create_lcm_test_graph_2() {} /// ## Generate Test Function For GVN /// This function is reference from conrnell course example @@ -89,7 +85,7 @@ pub fn create_gvn_graph_from_conrnell() -> Function { function.switch_to_block(b1); let u0 = function.build_add_inst(a0, b0); let v0 = function.build_add_inst(c0, d0); - let w0: ir::value::Value = function.build_add_inst(e0, f0); + let _w0: ir::value::Value = function.build_add_inst(e0, f0); let cond = function.build_icmp_inst(u0, v0, ir::instructions::CmpFlag::Eq); function.build_brif_inst(cond, b2, b3); @@ -106,7 +102,7 @@ pub fn create_gvn_graph_from_conrnell() -> Function { function.switch_to_block(b4); let u2 = function.build_phi_inst(vec![(b2, u0), (b3, u1)]); - let x2 = function.build_phi_inst(vec![(b2, x0), (b3, x1)]); + let _x2 = function.build_phi_inst(vec![(b2, x0), (b3, x1)]); let y2 = function.build_phi_inst(vec![(b2, y0), (b3, y1)]); function.build_add_inst(u2, y2); function.build_add_inst(a0, b0); @@ -114,3 +110,73 @@ pub fn create_gvn_graph_from_conrnell() -> Function { function } + +/// ## Generate Test function for DOM +/// This function is reference from the book `Engineering a Compiler 2/e` p499 +pub fn create_dom_graph_example() -> Function { + let mut function = Function::new(String::from("test_fun")); + let b0 = function.create_block(); + let b1 = function.create_block(); + let b2 = function.create_block(); + let b3 = function.create_block(); + let b4 = function.create_block(); + let b5 = function.create_block(); + let b6 = function.create_block(); + let b7 = function.create_block(); + let b8 = function.create_block(); + + function.connect_block(b0, b1); + function.connect_block(b1, b2); + function.connect_block(b2, b3); + function.connect_block(b3, b4); + function.connect_block(b3, b1); + + function.connect_block(b1, b5); + function.connect_block(b5, b6); + function.connect_block(b5, b8); + function.connect_block(b6, b7); + function.connect_block(b8, b7); + function.connect_block(b7, b3); + + function.mark_as_entry(b0); + function.mark_as_exit(b4); + + function +} + +/// ## Create simple graph to test use-def information: +/// ```markdown +/// t0 = 10; +/// t1 = 1000; +/// -------- +/// t2 = t1 + t0; +/// t3 = t1 + t2; +/// ---------- +/// t4 = t1 + t3; +/// ``` +pub fn create_use_def_graph() -> Function { + let mut func = Function::new(String::from("test_fun")); + // block 0 + let b0 = func.create_block(); + func.switch_to_block(b0); + let const10 = func.create_u32_const(10); + let t0 = func.build_mov_inst(const10); + let const1000 = func.create_u32_const(10000); + let t1 = func.build_mov_inst(const1000); + // block1 + let b1 = func.create_block(); + func.switch_to_block(b1); + let t2 = func.build_add_inst(t0, t1); + let t3 = func.build_add_inst(t1, t2); + // block 2 + let b2 = func.create_block(); + func.switch_to_block(b2); + let _t4 = func.build_add_inst(t1, t3); + // mark entry exit + func.mark_as_exit(b2); + func.mark_as_entry(b0); + // connect + func.connect_block(b0, b1); + func.connect_block(b1, b2); + func +} diff --git a/compilers/rustyc/optimizer/tests/fixtures/ir_optimizer/dfs_ordering/conrnell_example/output.txt b/compilers/rustyc/optimizer/tests/fixtures/ir_optimizer/dfs_ordering/conrnell_example/output.txt new file mode 100644 index 00000000..95023b7e --- /dev/null +++ b/compilers/rustyc/optimizer/tests/fixtures/ir_optimizer/dfs_ordering/conrnell_example/output.txt @@ -0,0 +1,8 @@ +|--------------| +| DFS Ordering | +|--------------| +| BB 1 | +| BB 2 | +| BB 3 | +| BB 4 | +|--------------| diff --git a/compilers/rustyc/optimizer/tests/fixtures/ir_optimizer/dfs_ordering/dom_example/output.txt b/compilers/rustyc/optimizer/tests/fixtures/ir_optimizer/dfs_ordering/dom_example/output.txt new file mode 100644 index 00000000..732669d4 --- /dev/null +++ b/compilers/rustyc/optimizer/tests/fixtures/ir_optimizer/dfs_ordering/dom_example/output.txt @@ -0,0 +1,13 @@ +|--------------| +| DFS Ordering | +|--------------| +| BB 1 | +| BB 2 | +| BB 6 | +| BB 9 | +| BB 7 | +| BB 8 | +| BB 3 | +| BB 4 | +| BB 5 | +|--------------| diff --git a/compilers/rustyc/optimizer/tests/fixtures/ir_optimizer/dfs_ordering/simple_example/output.txt b/compilers/rustyc/optimizer/tests/fixtures/ir_optimizer/dfs_ordering/simple_example/output.txt new file mode 100644 index 00000000..172843b7 --- /dev/null +++ b/compilers/rustyc/optimizer/tests/fixtures/ir_optimizer/dfs_ordering/simple_example/output.txt @@ -0,0 +1,7 @@ +|--------------| +| DFS Ordering | +|--------------| +| BB 1 | +| BB 2 | +| BB 3 | +|--------------| diff --git a/compilers/rustyc/optimizer/tests/fixtures/ir_optimizer/dom/dom_example/output.txt b/compilers/rustyc/optimizer/tests/fixtures/ir_optimizer/dom/dom_example/output.txt new file mode 100644 index 00000000..4ac0df36 --- /dev/null +++ b/compilers/rustyc/optimizer/tests/fixtures/ir_optimizer/dom/dom_example/output.txt @@ -0,0 +1,93 @@ +|-----------------------| +| IDom | +|-----------------------| +| Block id: 1 | BB0 | +|-----------------------| +| Block id: 2 | BB1 | +|-----------------------| +| Block id: 3 | BB2 | +|-----------------------| +| Block id: 4 | BB2 | +|-----------------------| +| Block id: 5 | BB4 | +|-----------------------| +| Block id: 6 | BB2 | +|-----------------------| +| Block id: 7 | BB6 | +|-----------------------| +| Block id: 8 | BB6 | +|-----------------------| +| Block id: 9 | BB6 | +|-----------------------| +|-----------------------| +| Dom | +|-----------------------| +| Block id: 1 | BB1 | +|-----------------------| +| | BB1 | +| Block id: 2 | BB2 | +|-----------------------| +| | BB1 | +| Block id: 3 | BB2 | +| | BB3 | +|-----------------------| +| | BB1 | +| Block id: 4 | BB2 | +| | BB4 | +|-----------------------| +| | BB1 | +| | BB2 | +| Block id: 5 | BB4 | +| | BB5 | +|-----------------------| +| | BB1 | +| Block id: 6 | BB2 | +| | BB6 | +|-----------------------| +| | BB1 | +| | BB2 | +| Block id: 7 | BB6 | +| | BB7 | +|-----------------------| +| | BB1 | +| | BB2 | +| Block id: 8 | BB6 | +| | BB8 | +|-----------------------| +| | BB1 | +| | BB2 | +| Block id: 9 | BB6 | +| | BB9 | +|-----------------------| +|-----------------------| +| DF | +|-----------------------| +| Block id: 2 | BB2 | +|-----------------------| +| Block id: 3 | BB4 | +|-----------------------| +| Block id: 4 | BB2 | +|-----------------------| +| Block id: 6 | BB4 | +|-----------------------| +| Block id: 7 | BB8 | +|-----------------------| +| Block id: 8 | BB4 | +|-----------------------| +| Block id: 9 | BB8 | +|-----------------------| +|-----------------------| +| Dom-Children | +|-----------------------| +| Block id: 1 | BB2 | +|-----------------------| +| | BB3 | +| Block id: 2 | BB4 | +| | BB6 | +|-----------------------| +| Block id: 4 | BB5 | +|-----------------------| +| | BB7 | +| Block id: 6 | BB8 | +| | BB9 | +|-----------------------| diff --git a/compilers/rustyc/optimizer/tests/fixtures/ir_optimizer/use_def/conrnell_example/output.txt b/compilers/rustyc/optimizer/tests/fixtures/ir_optimizer/use_def/conrnell_example/output.txt new file mode 100644 index 00000000..9bc37441 --- /dev/null +++ b/compilers/rustyc/optimizer/tests/fixtures/ir_optimizer/use_def/conrnell_example/output.txt @@ -0,0 +1,72 @@ +|---------------------------------------| +| Def Table | +|---------------------------------------| +| t1 | t1(param) | +| t2 | t2(param) | +| t3 | t3(param) | +| t4 | t4(param) | +| t5 | t5(param) | +| t6 | t6(param) | +| t7 | t7 = add t1 t2 | +| t8 | t8 = add t3 t4 | +| t9 | t9 = add t5 t6 | +| t10 | t10 = icmp t7 t8 Eq | +| t11 | t11 = add t3 t4 | +| t12 | t12 = add t3 t4 | +| t13 | t13 = add t1 t2 | +| t14 | t14 = add t5 t6 | +| t15 | t15 = add t5 t6 | +| t16 | phi t16, block2 t7, block3 t13 | +| t17 | phi t17, block2 t11, block3 t14 | +| t18 | phi t18, block2 t12, block3 t15 | +| t19 | t19 = add t16 t18 | +| t20 | t20 = add t1 t2 | +|---------------------------------------| +|---------------------------------------| +| Use Table | +|---------------------------------------| +| | t7 = add t1 t2 | +| t1 | t13 = add t1 t2 | +| | t20 = add t1 t2 | +|---------------------------------------| +| | t7 = add t1 t2 | +| t2 | t13 = add t1 t2 | +| | t20 = add t1 t2 | +|---------------------------------------| +| | t8 = add t3 t4 | +| t3 | t11 = add t3 t4 | +| | t12 = add t3 t4 | +|---------------------------------------| +| | t8 = add t3 t4 | +| t4 | t11 = add t3 t4 | +| | t12 = add t3 t4 | +|---------------------------------------| +| | t9 = add t5 t6 | +| t5 | t14 = add t5 t6 | +| | t15 = add t5 t6 | +|---------------------------------------| +| | t9 = add t5 t6 | +| t6 | t14 = add t5 t6 | +| | t15 = add t5 t6 | +|---------------------------------------| +| | t10 = icmp t7 t8 Eq | +| t7 | phi t16, block2 t7, block3 t13 | +|---------------------------------------| +| t8 | t10 = icmp t7 t8 Eq | +|---------------------------------------| +| t10 | brif t10, block2, block3 | +|---------------------------------------| +| t11 | phi t17, block2 t11, block3 t14 | +|---------------------------------------| +| t12 | phi t18, block2 t12, block3 t15 | +|---------------------------------------| +| t13 | phi t16, block2 t7, block3 t13 | +|---------------------------------------| +| t14 | phi t17, block2 t11, block3 t14 | +|---------------------------------------| +| t15 | phi t18, block2 t12, block3 t15 | +|---------------------------------------| +| t16 | t19 = add t16 t18 | +|---------------------------------------| +| t18 | t19 = add t16 t18 | +|---------------------------------------| diff --git a/compilers/rustyc/optimizer/tests/fixtures/ir_optimizer/use_def/simple_example/output.txt b/compilers/rustyc/optimizer/tests/fixtures/ir_optimizer/use_def/simple_example/output.txt new file mode 100644 index 00000000..597f8568 --- /dev/null +++ b/compilers/rustyc/optimizer/tests/fixtures/ir_optimizer/use_def/simple_example/output.txt @@ -0,0 +1,22 @@ +|---------------------| +| Def Table | +|---------------------| +| t1 | t1 = 10 | +| t2 | t2 = 10000 | +| t3 | t3 = add t1 t2 | +| t4 | t4 = add t2 t3 | +| t5 | t5 = add t2 t4 | +|---------------------| +|---------------------| +| Use Table | +|---------------------| +| t1 | t3 = add t1 t2 | +|---------------------| +| | t3 = add t1 t2 | +| t2 | t4 = add t2 t3 | +| | t5 = add t2 t4 | +|---------------------| +| t3 | t4 = add t2 t3 | +|---------------------| +| t4 | t5 = add t2 t4 | +|---------------------| diff --git a/compilers/rustyc/optimizer/tests/ir_optimizer_test_runner.rs b/compilers/rustyc/optimizer/tests/ir_optimizer_test_runner.rs index 549a6e20..67f0d33c 100644 --- a/compilers/rustyc/optimizer/tests/ir_optimizer_test_runner.rs +++ b/compilers/rustyc/optimizer/tests/ir_optimizer_test_runner.rs @@ -2,7 +2,9 @@ mod build_ir_graph; use build_ir_graph::*; use rustyc_optimizer::ir::function::Function; +use rustyc_optimizer::ir_optimizer::anaylsis::dfs_ordering::DFSOrdering; use rustyc_optimizer::ir_optimizer::anaylsis::domtree::DomAnaylsier; +use rustyc_optimizer::ir_optimizer::anaylsis::use_def_chain::UseDefAnaylsier; use rustyc_optimizer::ir_optimizer::anaylsis::{DebuggerAnaylsis, OptimizerAnaylsis}; use rustyc_optimizer::ir_optimizer::pass::lcm::LCMPass; use rustyc_optimizer::ir_optimizer::pass::{DebuggerPass, OptimizerPass}; @@ -76,8 +78,43 @@ generate_pass_cases!(( )); generate_anaylsis_cases!(( - test_conrnell, + test_dom_pass_conrnell_example, "./dom/gvn_conrnell", create_gvn_graph_from_conrnell(), DomAnaylsier::new() )); + +generate_anaylsis_cases!(( + test_dom_pass_dom_example, + "./dom/dom_example", + create_dom_graph_example(), + DomAnaylsier::new() +)); + +generate_anaylsis_cases!(( + test_use_def_anaylsis_simple_example, + "./use_def/simple_example", + create_use_def_graph(), + UseDefAnaylsier::new() +)); + +generate_anaylsis_cases!(( + test_dfs_ordering_conrnell_example, + "./dfs_ordering/conrnell_example", + create_gvn_graph_from_conrnell(), + DFSOrdering::new() +)); + +generate_anaylsis_cases!(( + test_dfs_ordering_dom_example, + "./dfs_ordering/dom_example", + create_dom_graph_example(), + DFSOrdering::new() +)); + +generate_anaylsis_cases!(( + test_dfs_ordering_simple_example, + "./dfs_ordering/simple_example", + create_use_def_graph(), + DFSOrdering::new() +));