diff --git a/lib/frontend/src/ssa.rs b/lib/frontend/src/ssa.rs index c9f763cf7f..016d8f0ce7 100644 --- a/lib/frontend/src/ssa.rs +++ b/lib/frontend/src/ssa.rs @@ -169,7 +169,7 @@ enum ZeroOneOrMore { enum UseVarCases { Unsealed(Value), SealedOnePredecessor(Block), - SealedMultiplePredecessors(Vec<(Block, Inst)>, Value, Ebb), + SealedMultiplePredecessors(Value, Ebb), } /// The following methods are the API of the SSA builder. Here is how it should be used when @@ -238,8 +238,7 @@ where UseVarCases::SealedOnePredecessor(data.predecessors[0].0) } else { let val = dfg.append_ebb_arg(data.ebb, ty); - let preds = data.predecessors.clone(); - UseVarCases::SealedMultiplePredecessors(preds, val, data.ebb) + UseVarCases::SealedMultiplePredecessors(val, data.ebb) } } else { let val = dfg.append_ebb_arg(data.ebb, ty); @@ -264,11 +263,11 @@ where self.def_var(var, val, block); (val, SideEffects::new()) } - UseVarCases::SealedMultiplePredecessors(preds, val, ebb) => { + UseVarCases::SealedMultiplePredecessors(val, ebb) => { // If multiple predecessor we look up a use_var in each of them: // if they all yield the same value no need for an Ebb argument self.def_var(var, val, block); - self.predecessors_lookup(dfg, layout, jts, val, var, ebb, &preds) + self.predecessors_lookup(dfg, layout, jts, val, var, ebb) } } } @@ -346,10 +345,7 @@ where ) -> SideEffects { let block = self.header_block(ebb); - // TODO: find a way to not allocate vectors - let (predecessors, undef_vars, ebb): (Vec<(Block, Inst)>, - Vec<(Variable, Value)>, - Ebb) = match self.blocks[block] { + let (undef_vars, ebb): (Vec<(Variable, Value)>, Ebb) = match self.blocks[block] { BlockData::EbbBody { .. } => panic!("this should not happen"), BlockData::EbbHeader(ref mut data) => { assert!(!data.sealed); @@ -357,7 +353,7 @@ where // can iterate over it without borrowing the whole builder. let mut undef_variables = Vec::new(); mem::swap(&mut data.undef_variables, &mut undef_variables); - (data.predecessors.clone(), undef_variables, data.ebb) + (undef_variables, data.ebb) } }; @@ -366,7 +362,7 @@ where // only if necessary. for (var, val) in undef_vars { let (_, mut local_side_effects) = - self.predecessors_lookup(dfg, layout, jts, val, var, ebb, &predecessors); + self.predecessors_lookup(dfg, layout, jts, val, var, ebb); side_effects.split_ebbs_created.append( &mut local_side_effects .split_ebbs_created, @@ -399,13 +395,18 @@ where temp_arg_val: Value, temp_arg_var: Variable, dest_ebb: Ebb, - preds: &[(Block, Inst)], ) -> (Value, SideEffects) { let mut pred_values: ZeroOneOrMore = ZeroOneOrMore::Zero(); // TODO: find a way to not allocate a vector let mut jump_args_to_append: Vec<(Block, Inst, Value)> = Vec::new(); let ty = dfg.value_type(temp_arg_val); let mut side_effects = SideEffects::new(); + + // Iterate over the predecessors. To avoid borrowing `self` for the whole loop, + // temporarily detach the predecessors list and replace it with an empty list. + // `use_var`'s traversal won't revisit these predecesors. + let mut preds = Vec::new(); + mem::swap(&mut preds, &mut self.predecessors_mut(dest_ebb)); for &(pred, last_inst) in preds.iter() { // For undef value and each predecessor we query what is the local SSA value // corresponding to var and we put it as an argument of the branch instruction. @@ -437,6 +438,10 @@ where &mut local_side_effects.instructions_added_to_ebbs, ); } + // Now that we're done iterating, move the predecessors list back. + debug_assert!(self.predecessors(dest_ebb).is_empty()); + *self.predecessors_mut(dest_ebb) = preds; + match pred_values { ZeroOneOrMore::Zero() => { // The variable is used but never defined before. This is an irregularity in the @@ -560,6 +565,15 @@ where } } + /// Same as predecessors, but for &mut. + pub fn predecessors_mut(&mut self, ebb: Ebb) -> &mut Vec<(Block, Inst)> { + let block = self.header_block(ebb); + match self.blocks[block] { + BlockData::EbbBody { .. } => panic!("should not happen"), + BlockData::EbbHeader(ref mut data) => &mut data.predecessors, + } + } + /// Returns `true` if and only if `seal_ebb_header_block` has been called on the argument. pub fn is_sealed(&self, ebb: Ebb) -> bool { match self.blocks[self.header_block(ebb)] {