diff --git a/src/opt/simplify_cfg.rs b/src/opt/simplify_cfg.rs index 4bcb1ed..6f4be0c 100644 --- a/src/opt/simplify_cfg.rs +++ b/src/opt/simplify_cfg.rs @@ -32,13 +32,12 @@ pub struct SimplifyCfgEmpty {} impl Optimize for SimplifyCfgConstProp { fn optimize(&mut self, code: &mut FunctionDefinition) -> bool { - code.blocks.iter_mut().any(|(_, block)| { - if let Some(exit) = self.simplify_block_exit(&block.exit) { - block.exit = exit; - true - } else { - false + code.blocks.values_mut().fold(false, |mut result, block| { + if let Some(new_exit) = self.simplify_block_exit(&block.exit) { + block.exit = new_exit; + result = true; } + result }) } } @@ -47,9 +46,11 @@ impl Optimize for SimplifyCfgReach { fn optimize(&mut self, code: &mut FunctionDefinition) -> bool { let graph = make_cfg(code); let mut visited = HashSet::new(); + let mut queue = Vec::new(); - let mut queue = vec![code.bid_init]; let _ = visited.insert(code.bid_init); + queue.push(code.bid_init); + while let Some(bid) = queue.pop() { if let Some(args) = graph.get(&bid) { for arg in args { @@ -60,9 +61,9 @@ impl Optimize for SimplifyCfgReach { } } - let size_org = code.blocks.len(); + let blocks_org = code.blocks.len(); code.blocks.retain(|bid, _| visited.contains(bid)); - code.blocks.len() < size_org + code.blocks.len() < blocks_org } } @@ -72,7 +73,7 @@ impl Optimize for SimplifyCfgMerge { let mut indegrees = HashMap::new(); for args in graph.values() { for arg in args { - *indegrees.entry(arg.bid).or_insert(0) += 1usize; + *indegrees.entry(arg.bid).or_default() += 1usize; } } @@ -84,26 +85,26 @@ impl Optimize for SimplifyCfgMerge { if let BlockExit::Jump { arg } = &block_from.exit { let bid_to = arg.bid; if *bid_from != bid_to && indegrees.get(&bid_to) == Some(&1) { - let bid_merge_target = *merged_to.get(bid_from).unwrap_or(bid_from); + let bid_from = *merged_to.get(bid_from).unwrap_or(bid_from); merged_from - .entry(bid_merge_target) + .entry(bid_from) .or_insert(Vec::new()) .push(bid_to); - let _ = merged_to.insert(bid_to, bid_merge_target); + let _ = merged_to.insert(bid_to, bid_from); - if let Some(mut bids_from) = merged_from.remove(&bid_to) { + if let Some(mut bids_merged) = merged_from.remove(&bid_to) { merged_from - .entry(bid_merge_target) - .or_insert(Vec::new()) - .append(&mut bids_from); - merged_to.iter_mut().map(|(_, merged_to)| { + .get_mut(&bid_from) + .unwrap() + .append(&mut bids_merged); + merged_to.values_mut().for_each(|merged_to| { if *merged_to == bid_to { - *merged_to = bid_merge_target; + *merged_to = bid_from; } }); } - let block_to = code.blocks.get(&bid_to).unwrap(); + let block_to = &code.blocks[&bid_to]; for (i, (a, p)) in izip!(&arg.args, block_to.phinodes.iter()).enumerate() { let from = RegisterId::arg(bid_to, i); let _unused = replaces.insert(from, a.clone()); @@ -112,31 +113,29 @@ impl Optimize for SimplifyCfgMerge { } } - for (bid_merge_target, bids_merge_from) in &merged_from { + for (bid_merge_to, bids_merge_from) in &merged_from { let blocks_merge_from = bids_merge_from .iter() .map(|bid| code.blocks.get(bid).unwrap().clone()) .collect::>(); - let block_merge_target = code.blocks.get_mut(bid_merge_target).unwrap(); - let mut i = block_merge_target.instructions.len(); + let block_merge_to = code.blocks.get_mut(bid_merge_to).unwrap(); + let mut i = block_merge_to.instructions.len(); for (bid, block) in bids_merge_from.iter().zip(blocks_merge_from) { for (j, inst) in block.instructions.iter().enumerate() { let dtype = inst.dtype(); - block_merge_target.instructions.push(inst.clone()); + block_merge_to.instructions.push(inst.clone()); let from = RegisterId::temp(*bid, j); - let to = Operand::register(RegisterId::temp(*bid_merge_target, i), dtype); + let to = Operand::register(RegisterId::temp(*bid_merge_to, i), dtype); let _unused = replaces.insert(from, to); i += 1; } - block_merge_target.exit = block.exit; + block_merge_to.exit = block.exit; } } - code.blocks.retain(|bid, _| !merged_to.contains_key(bid)); - for (bid, block) in &mut code.blocks { for inst in block.instructions.iter_mut() { replace_instruction_operands(inst, &replaces); @@ -144,6 +143,7 @@ impl Optimize for SimplifyCfgMerge { replace_exit_operands(&mut block.exit, &replaces); } + code.blocks.retain(|bid, _| !merged_to.contains_key(bid)); !merged_to.is_empty() } } @@ -156,9 +156,9 @@ impl Optimize for SimplifyCfgEmpty { .filter(|(_, block)| block.phinodes.is_empty() && block.instructions.is_empty()) .map(|(bid, block)| (*bid, block.clone())) .collect::>(); - code.blocks - .iter_mut() - .any(|(_, block)| self.simplify_block_exit(&mut block.exit, &empty_blocks)) + code.blocks.values_mut().fold(false, |result, block| { + self.simplify_block_exit(&mut block.exit, &empty_blocks) || result + }) } } @@ -174,18 +174,16 @@ impl SimplifyCfgConstProp { Some(BlockExit::Jump { arg: arg_then.clone(), }) - } else if let Some(condition) = condition.get_constant() { - match condition { - Constant::Int { value: 0, .. } => Some(BlockExit::Jump { - arg: arg_else.clone(), - }), - Constant::Int { value: 1, .. } => Some(BlockExit::Jump { - arg: arg_then.clone(), - }), - _ => None, - } } else { - None + condition.get_constant().and_then(|condition| { + Some(BlockExit::Jump { + arg: match condition { + Constant::Int { value: 0, .. } => arg_else.clone(), + Constant::Int { value: 1, .. } => arg_then.clone(), + _ => return None, + }, + }) + }) } } BlockExit::Switch { @@ -234,13 +232,12 @@ impl SimplifyCfgEmpty { ) -> bool { match exit { BlockExit::Jump { arg } => { - let block = if let Some(empty_block) = empty_blocks.get(&arg.bid) { - empty_block + if let Some(empty_block) = empty_blocks.get(&arg.bid) { + *exit = empty_block.exit.clone(); + true } else { - return false; - }; - *exit = block.exit.clone(); - true + false + } } BlockExit::ConditionalJump { arg_then, arg_else, .. @@ -251,9 +248,9 @@ impl SimplifyCfgEmpty { } BlockExit::Switch { default, cases, .. } => { let changed1 = self.simplify_jump_arg(default, empty_blocks); - let changed2 = cases - .iter_mut() - .any(|c| self.simplify_jump_arg(&mut c.1, empty_blocks)); + let changed2 = cases.iter_mut().fold(false, |result, (_, arg)| { + self.simplify_jump_arg(arg, empty_blocks) || result + }); changed1 || changed2 } BlockExit::Return { .. } | BlockExit::Unreachable => false, @@ -287,19 +284,6 @@ fn make_cfg(fdef: &FunctionDefinition) -> HashMap> { .collect() } -// fn reverse_cfg(cfg: &HashMap>) -> HashMap> { -// let mut result = HashMap::new(); -// for (bid, jumps) in cfg { -// for jump in jumps { -// result -// .entry(jump.bid) -// .or_insert_with(Vec::new) -// .push((*bid, jump.clone())) -// } -// } -// result -// } - fn replace_instruction_operands(inst: &mut Instruction, replaces: &HashMap) { match inst { Instruction::BinOp { lhs, rhs, .. } => { @@ -329,21 +313,15 @@ fn replace_instruction_operands(inst: &mut Instruction, replaces: &HashMap todo!(), + _ => unreachable!(), } } fn replace_exit_operands(exit: &mut BlockExit, replaces: &HashMap) { match exit { - BlockExit::ConditionalJump { condition, .. } => { - replace_operand(condition, replaces); - } - BlockExit::Switch { value, .. } => { - replace_operand(value, replaces); - } - BlockExit::Return { value } => { - replace_operand(value, replaces); - } + BlockExit::ConditionalJump { condition, .. } => replace_operand(condition, replaces), + BlockExit::Switch { value, .. } => replace_operand(value, replaces), + BlockExit::Return { value } => replace_operand(value, replaces), _ => (), } } @@ -351,7 +329,7 @@ fn replace_exit_operands(exit: &mut BlockExit, replaces: &HashMap) { if let Operand::Register { rid, .. } = operand { if let Some(new_operand) = replaces.get(rid) { - std::mem::replace(operand, new_operand.clone()); + *operand = new_operand.clone(); } } }