mod.rs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. use crate::codegen::cfg::{BasicBlock, ControlFlowGraph, Instr};
  2. use crate::codegen::reaching_definitions::block_edges;
  3. use crate::codegen::subexpression_elimination::available_variable::AvailableVariable;
  4. use crate::codegen::subexpression_elimination::common_subexpression_tracker::CommonSubExpressionTracker;
  5. use crate::codegen::subexpression_elimination::operator::Operator;
  6. use crate::sema::ast::Namespace;
  7. use num_bigint::BigInt;
  8. use std::cell::RefCell;
  9. use std::collections::{HashMap, HashSet, VecDeque};
  10. use std::rc::Rc;
  11. mod available_expression;
  12. mod available_expression_set;
  13. mod available_variable;
  14. pub mod common_subexpression_tracker;
  15. mod expression;
  16. mod instruction;
  17. mod operator;
  18. mod tests;
  19. /*
  20. The available expression analysis implemented here builds a graph to track expressions. Each
  21. operand and each operation represents a vertex. Edges are directed from operands to an operation.
  22. Let's say we have a+b. 'a', 'b' and 'e1=a+b' are vertexes. Edges are directed from 'a' to 'e1=a+b'
  23. and from 'b' to 'a+b'. If we add now 'a+b-c', we will have two new nodes: 'c' and 'e2=e1-c'.
  24. Edges will connect 'c' to 'e2=e1-c' and 'e1=a+b' to 'e2=e1-c'. Whenever a variable becomes
  25. unavailable (i.e. we kill its definition), we recursively remove the operand node and all its
  26. children operations from the graph.
  27. For the common subexpression elimination, whenever we are trying to add an expression to the graph
  28. that is already available, we track it with the CommonSubexpressionTracker. During another pass on
  29. the CFG, we check if we are adding an expression that is tracked. If so, we can regenerate the
  30. ast::Expression using the new temporary variable.
  31. */
  32. /// NodeId is the identifier of each vertex of the graph
  33. pub type NodeId = usize;
  34. /// This struct serves only to maintain a global id, in such a way that new nodes will always have
  35. /// a different ID
  36. #[derive(Default)]
  37. pub struct AvailableExpression {
  38. global_id_counter: NodeId,
  39. cur_block: usize,
  40. }
  41. /// Each BasicExpression is a graph node
  42. #[derive(Clone)]
  43. pub struct BasicExpression {
  44. expr_type: ExpressionType,
  45. expression_id: NodeId,
  46. children: HashMap<NodeId, Rc<RefCell<BasicExpression>>>,
  47. pub available_variable: AvailableVariable,
  48. pub block: usize,
  49. pub parent_block: usize,
  50. pub on_parent_block: bool,
  51. }
  52. /// Type of constant to streamline the use of a hashmap
  53. #[derive(Eq, PartialEq, Hash, Clone, Debug)]
  54. pub enum ConstantType {
  55. Bool(bool),
  56. Bytes(Vec<u8>),
  57. Number(BigInt),
  58. }
  59. /// The type of expression that a node represents
  60. #[derive(Clone, PartialEq, Hash, Eq, Debug)]
  61. pub enum ExpressionType {
  62. BinaryOperation(NodeId, NodeId, Operator),
  63. UnaryOperation(NodeId, Operator),
  64. Variable(usize),
  65. FunctionArg(usize),
  66. Literal(ConstantType),
  67. }
  68. /// Sets contain the available expression at a certain portion of the CFG
  69. #[derive(Default)]
  70. pub struct AvailableExpressionSet {
  71. // node_no => BasicExpression
  72. expression_memory: HashMap<NodeId, Rc<RefCell<BasicExpression>>>,
  73. // Expression => node_id
  74. expr_map: HashMap<ExpressionType, NodeId>,
  75. parent_block_no: usize,
  76. }
  77. /// Performs common subexpression elimination
  78. pub fn common_sub_expression_elimination(cfg: &mut ControlFlowGraph, ns: &mut Namespace) {
  79. let mut ave = AvailableExpression::default();
  80. let mut cst = CommonSubExpressionTracker::default();
  81. let mut sets: HashMap<usize, AvailableExpressionSet> = HashMap::new();
  82. let (visiting_order, dag) = find_visiting_order(cfg);
  83. cst.set_dag(dag);
  84. sets.insert(0, AvailableExpressionSet::default());
  85. // First pass: identify common subexpressions using available expressiona analysis
  86. for (block_no, cycle) in &visiting_order {
  87. let cur_block = &cfg.blocks[*block_no];
  88. ave.set_cur_block(*block_no);
  89. cst.set_cur_block(*block_no);
  90. let mut cur_set = sets.remove(block_no).unwrap();
  91. kill_loop_variables(cur_block, &mut cur_set, *cycle);
  92. for instr in cur_block.instr.iter() {
  93. cur_set.process_instruction(instr, &mut ave, &mut cst);
  94. }
  95. add_neighbor_blocks(cur_block, &cur_set, block_no, &mut sets, &cst);
  96. }
  97. cst.create_variables(ns, cfg);
  98. sets.clear();
  99. let mut ave = AvailableExpression::default();
  100. sets.insert(0, AvailableExpressionSet::default());
  101. // Second pass: eliminate common subexpressions
  102. for (block_no, cycle) in &visiting_order {
  103. let mut cur_set = sets.remove(block_no).unwrap();
  104. let mut cur_block = &mut cfg.blocks[*block_no];
  105. ave.set_cur_block(*block_no);
  106. cst.set_cur_block(*block_no);
  107. let mut new_instructions: Vec<Instr> = Vec::new();
  108. kill_loop_variables(cur_block, &mut cur_set, *cycle);
  109. for instr in cur_block.instr.iter() {
  110. let instr = cur_set.regenerate_instruction(instr, &mut ave, &mut cst);
  111. cst.add_new_instructions(&mut new_instructions);
  112. new_instructions.push(instr);
  113. }
  114. cur_block.instr = new_instructions;
  115. add_neighbor_blocks(cur_block, &cur_set, block_no, &mut sets, &cst);
  116. }
  117. cst.add_parent_block_instructions(cfg);
  118. }
  119. /// Add neighbor block to the hashset of Available expressions to be processed
  120. fn add_neighbor_blocks(
  121. cur_block: &BasicBlock,
  122. cur_set: &AvailableExpressionSet,
  123. block_no: &usize,
  124. sets: &mut HashMap<usize, AvailableExpressionSet>,
  125. cst: &CommonSubExpressionTracker,
  126. ) {
  127. for edge in block_edges(cur_block) {
  128. if let Some(set) = sets.get_mut(&edge) {
  129. set.intersect_sets(cur_set, cst);
  130. } else {
  131. sets.insert(edge, cur_set.clone_for_parent_block(*block_no));
  132. }
  133. }
  134. }
  135. /// When there is a cycle in the CFG, definitions from a loop can reach the current block. In this
  136. /// case, we must kill previous definitions of the given variable.
  137. fn kill_loop_variables(block: &BasicBlock, cur_set: &mut AvailableExpressionSet, has_cycle: bool) {
  138. if !has_cycle {
  139. return;
  140. }
  141. for var_no in &block.loop_reaching_variables {
  142. cur_set.kill(*var_no);
  143. }
  144. }
  145. /// Find the correct visiting order for the CFG traversal, using topological sorting. The visiting
  146. /// order should be the same as the execution order. This function also returns a DAG for the
  147. /// execution graph. This helps us find the lowest common ancestor later.
  148. fn find_visiting_order(cfg: &ControlFlowGraph) -> (Vec<(usize, bool)>, Vec<Vec<usize>>) {
  149. let mut order: Vec<(usize, bool)> = Vec::with_capacity(cfg.blocks.len());
  150. let mut visited: HashSet<usize> = HashSet::new();
  151. let mut stack: HashSet<usize> = HashSet::new();
  152. let mut has_cycle: Vec<bool> = vec![false; cfg.blocks.len()];
  153. let mut degrees: Vec<i32> = vec![0; cfg.blocks.len()];
  154. let mut dag: Vec<Vec<usize>> = Vec::new();
  155. dag.resize(cfg.blocks.len(), vec![]);
  156. cfg_dfs(
  157. 0,
  158. cfg,
  159. &mut visited,
  160. &mut stack,
  161. &mut degrees,
  162. &mut has_cycle,
  163. &mut dag,
  164. );
  165. let mut queue: VecDeque<usize> = VecDeque::new();
  166. queue.push_back(0);
  167. while let Some(block_no) = queue.pop_front() {
  168. order.push((block_no, has_cycle[block_no]));
  169. for edge in block_edges(&cfg.blocks[block_no]) {
  170. degrees[edge] -= 1;
  171. if degrees[edge] == 0 {
  172. queue.push_back(edge);
  173. }
  174. }
  175. }
  176. (order, dag)
  177. }
  178. /// Run DFS (depth first search) in the CFG to find cycles.
  179. fn cfg_dfs(
  180. block_no: usize,
  181. cfg: &ControlFlowGraph,
  182. visited: &mut HashSet<usize>,
  183. stack: &mut HashSet<usize>,
  184. degrees: &mut Vec<i32>,
  185. has_cycle: &mut Vec<bool>,
  186. dag: &mut Vec<Vec<usize>>,
  187. ) -> bool {
  188. if visited.contains(&block_no) {
  189. return true;
  190. }
  191. if stack.contains(&block_no) {
  192. degrees[block_no] -= 1;
  193. has_cycle[block_no] = true;
  194. return false;
  195. }
  196. stack.insert(block_no);
  197. for edge in block_edges(&cfg.blocks[block_no]) {
  198. degrees[edge] += 1;
  199. if cfg_dfs(edge, cfg, visited, stack, degrees, has_cycle, dag) {
  200. dag[block_no].push(edge);
  201. }
  202. }
  203. stack.remove(&block_no);
  204. visited.insert(block_no);
  205. true
  206. }