@@ -6351,20 +6351,6 @@ impl Function {
63516351 /// This produces a minimal SSA representation amenable to further optimizations.
63526352 /// The implementation is inspired from algorithm 2 in <https://c9x.me/compile/bib/braun13cc.pdf>.
63536353 fn remove_trivial_block_params(&mut self) {
6354-
6355- #[derive(Copy, Clone)]
6356- enum Edge {
6357- True,
6358- False,
6359- Unconditional
6360- }
6361-
6362- #[derive(Copy, Clone)]
6363- struct EdgeKey {
6364- block_id: BlockId,
6365- edge: Edge
6366- }
6367-
63686354 // Each block param is lifted to an abstract domain of ParamValues.
63696355 // The lattice is simple. None is Bottom, Multiple is Top, and One is between both.
63706356 // During analysis, all block params start with None.
@@ -6439,20 +6425,11 @@ impl Function {
64396425 rpo_order[block_id] = idx;
64406426 }
64416427
6442-
64436428 // Populate each block with a vec of instructions that call the block
6444- let mut predecessors: Vec<Vec<EdgeKey >> = vec![vec![]; self.num_blocks()];
6429+ let mut predecessors: Vec<Vec<BlockId >> = vec![vec![]; self.num_blocks()];
64456430 for block_id in rpo.iter().cloned() {
6446- let insn_id = self.blocks[block_id].insns().last().unwrap();
6447- match self.resolve(*insn_id).insn(self) {
6448- Insn::CondBranch { if_true, if_false, .. } => {
6449- predecessors[if_true.target].push(EdgeKey { block_id, edge: Edge::True });
6450- predecessors[if_false.target].push(EdgeKey { block_id, edge: Edge::False });
6451- }
6452- Insn::Jump(edge) => {
6453- predecessors[edge.target].push(EdgeKey { block_id, edge: Edge::Unconditional });
6454- }
6455- _ => ()
6431+ for edge in outgoing_edges(self, block_id) {
6432+ predecessors[edge.target].push(block_id);
64566433 }
64576434 }
64586435
@@ -6465,22 +6442,18 @@ impl Function {
64656442 for target in rpo.iter().copied() {
64666443 let mut abstract_domain = vec![AbstractValue::None; self.blocks[target].params.len()];
64676444
6468- for pred in &predecessors[target] {
6469- // Collect the params for abstract interpretation. The params are args of the BranchEdges extracted from block terminators.
6470- let insn_idx = self.blocks[pred.block_id].insns.len() - 1;
6471- let insn = self.resolve(self.blocks[pred.block_id].insns[insn_idx]).insn(self);
6472- let params = match (insn, pred.edge) {
6473- (Insn::Jump(edge), Edge::Unconditional) => &edge.args,
6474- (Insn::CondBranch { if_true, .. }, Edge::True) => &if_true.args,
6475- (Insn::CondBranch { if_false, .. }, Edge::False) => &if_false.args,
6476- (_, _) => unreachable!("Predecessors should only be Jump or CondBranch with a corresponding EdgeKey bool.")
6477- };
6478-
6479- // Perform abstract interpretation to determine trivial params
6480- for i in 0..params.len() {
6481- let param = self.find_id(params[i]);
6482- let self_loop_param = self.find_id(self.blocks[target].params[i]);
6483- abstract_domain[i].update(param, self_loop_param);
6445+ for &block_id in &predecessors[target] {
6446+ // In almost all cases, there is only one edge that returns from this filter. However, there's one thorny edge case.
6447+ // Technically, a CondBranch could pass two sets of different parameters to the same target. Both of these are predecessors and both must be checked.
6448+ for edge in outgoing_edges(self, block_id).filter(|edge| edge.target == target) {
6449+ // Collect the params for abstract interpretation. The params are args of the BranchEdges extracted from block terminators.
6450+ let predecessor_params = &edge.args;
6451+ // Perform abstract interpretation to determine trivial params
6452+ for i in 0..predecessor_params.len() {
6453+ let param = self.find_id(predecessor_params[i]);
6454+ let self_loop_param = self.find_id(self.blocks[target].params[i]);
6455+ abstract_domain[i].update(param, self_loop_param);
6456+ }
64846457 }
64856458 }
64866459
@@ -6507,15 +6480,12 @@ impl Function {
65076480 }
65086481
65096482 // Remove trivial params from the incoming edges
6510- for pred in &predecessors[target] {
6511- let insn_idx = self.blocks[pred.block_id].insns.len() - 1;
6512- let insn = self.resolve(self.blocks[pred.block_id].insns[insn_idx]).insn_mut(self);
6513- match (insn, pred.edge) {
6514- (Insn::Jump(edge), Edge::Unconditional) => prune_vec_by_indices(&mut edge.args, &trivial_indices),
6515- (Insn::CondBranch { if_true, .. }, Edge::True) => prune_vec_by_indices(&mut if_true.args, &trivial_indices),
6516- (Insn::CondBranch { if_false, .. }, Edge::False) => prune_vec_by_indices(&mut if_false.args, &trivial_indices),
6517- (_, _) => unreachable!("Predecessors should only be Jump or CondBranch with a corresponding EdgeKey bool.")
6518- };
6483+ for &block_id in &predecessors[target] {
6484+ for edge in outgoing_edges_mut(self, block_id) {
6485+ if edge.target == target {
6486+ prune_vec_by_indices(&mut edge.args, &trivial_indices);
6487+ }
6488+ }
65196489 }
65206490
65216491 // Remove trivial params from the block definition
0 commit comments