diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index c2bc1e32cd6..4487187de3b 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -116,7 +116,12 @@ impl<'block> BrilligBlock<'block> { dfg: &DataFlowGraph, ) { match terminator_instruction { - TerminatorInstruction::JmpIf { condition, then_destination, else_destination } => { + TerminatorInstruction::JmpIf { + condition, + then_destination, + else_destination, + call_stack: _, + } => { let condition = self.convert_ssa_single_addr_value(*condition, dfg); self.brillig_context.jump_if_instruction( condition.address, diff --git a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs index b24c5632b24..49184bf4c63 100644 --- a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs @@ -371,10 +371,12 @@ impl FunctionBuilder { then_destination: BasicBlockId, else_destination: BasicBlockId, ) { + let call_stack = self.call_stack.clone(); self.terminate_block_with(TerminatorInstruction::JmpIf { condition, then_destination, else_destination, + call_stack, }); } diff --git a/compiler/noirc_evaluator/src/ssa/ir/cfg.rs b/compiler/noirc_evaluator/src/ssa/ir/cfg.rs index 5a3f07cd673..b9166bf1d56 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/cfg.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/cfg.rs @@ -168,11 +168,13 @@ mod tests { condition: cond, then_destination: block2_id, else_destination: block1_id, + call_stack: CallStack::new(), }); func.dfg[block1_id].set_terminator(TerminatorInstruction::JmpIf { condition: cond, then_destination: block1_id, else_destination: block2_id, + call_stack: CallStack::new(), }); func.dfg[block2_id].set_terminator(TerminatorInstruction::Return { return_values: vec![], @@ -235,6 +237,7 @@ mod tests { condition: cond, then_destination: block1_id, else_destination: ret_block_id, + call_stack: CallStack::new(), }); // Recompute new and changed blocks diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index 35b114fd115..7dcb50762f5 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -1,3 +1,4 @@ +use noirc_errors::Location; use serde::{Deserialize, Serialize}; use std::hash::{Hash, Hasher}; @@ -808,7 +809,12 @@ pub(crate) enum TerminatorInstruction { /// /// If the condition is true: jump to the specified `then_destination`. /// Otherwise, jump to the specified `else_destination`. - JmpIf { condition: ValueId, then_destination: BasicBlockId, else_destination: BasicBlockId }, + JmpIf { + condition: ValueId, + then_destination: BasicBlockId, + else_destination: BasicBlockId, + call_stack: CallStack, + }, /// Unconditional Jump /// @@ -835,10 +841,11 @@ impl TerminatorInstruction { ) -> TerminatorInstruction { use TerminatorInstruction::*; match self { - JmpIf { condition, then_destination, else_destination } => JmpIf { + JmpIf { condition, then_destination, else_destination, call_stack } => JmpIf { condition: f(*condition), then_destination: *then_destination, else_destination: *else_destination, + call_stack: call_stack.clone(), }, Jmp { destination, arguments, call_stack } => Jmp { destination: *destination, @@ -906,6 +913,14 @@ impl TerminatorInstruction { Return { .. } => (), } } + + pub(crate) fn call_stack(&self) -> im::Vector { + match self { + TerminatorInstruction::JmpIf { call_stack, .. } + | TerminatorInstruction::Jmp { call_stack, .. } + | TerminatorInstruction::Return { call_stack, .. } => call_stack.clone(), + } + } } /// Contains the result to Instruction::simplify, specifying how the instruction diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs index 08f145f598f..ea2523e873e 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs @@ -126,7 +126,14 @@ pub(super) fn simplify_call( return SimplifyResult::SimplifiedToMultiple(vec![new_slice_length, new_slice]); } - simplify_slice_push_back(slice, element_type, arguments, dfg, block) + simplify_slice_push_back( + slice, + element_type, + arguments, + dfg, + block, + call_stack.clone(), + ) } else { SimplifyResult::None } @@ -149,7 +156,7 @@ pub(super) fn simplify_call( Intrinsic::SlicePopBack => { let slice = dfg.get_array_constant(arguments[1]); if let Some((_, typ)) = slice { - simplify_slice_pop_back(typ, arguments, dfg, block) + simplify_slice_pop_back(typ, arguments, dfg, block, call_stack.clone()) } else { SimplifyResult::None } @@ -348,12 +355,12 @@ fn simplify_slice_push_back( arguments: &[ValueId], dfg: &mut DataFlowGraph, block: BasicBlockId, + call_stack: CallStack, ) -> SimplifyResult { // The capacity must be an integer so that we can compare it against the slice length let capacity = dfg.make_constant((slice.len() as u128).into(), Type::length_type()); let len_equals_capacity_instr = Instruction::Binary(Binary { lhs: arguments[0], operator: BinaryOp::Eq, rhs: capacity }); - let call_stack = dfg.get_value_call_stack(arguments[0]); let len_equals_capacity = dfg .insert_instruction_and_results(len_equals_capacity_instr, block, None, call_stack.clone()) .first(); @@ -384,7 +391,7 @@ fn simplify_slice_push_back( }; let set_last_slice_value = dfg - .insert_instruction_and_results(set_last_slice_value_instr, block, None, call_stack) + .insert_instruction_and_results(set_last_slice_value_instr, block, None, call_stack.clone()) .first(); let mut slice_sizes = HashMap::default(); @@ -392,7 +399,8 @@ fn simplify_slice_push_back( slice_sizes.insert(new_slice, slice_size / element_size); let unknown = &mut HashMap::default(); - let mut value_merger = ValueMerger::new(dfg, block, &mut slice_sizes, unknown, None); + let mut value_merger = + ValueMerger::new(dfg, block, &mut slice_sizes, unknown, None, call_stack); let new_slice = value_merger.merge_values( len_not_equals_capacity, @@ -409,6 +417,7 @@ fn simplify_slice_pop_back( arguments: &[ValueId], dfg: &mut DataFlowGraph, block: BasicBlockId, + call_stack: CallStack, ) -> SimplifyResult { let element_types = match element_type.clone() { Type::Slice(element_types) | Type::Array(element_types, _) => element_types, @@ -425,7 +434,7 @@ fn simplify_slice_pop_back( let element_size = dfg.make_constant((element_count as u128).into(), Type::length_type()); let flattened_len_instr = Instruction::binary(BinaryOp::Mul, arguments[0], element_size); let mut flattened_len = dfg - .insert_instruction_and_results(flattened_len_instr, block, None, CallStack::new()) + .insert_instruction_and_results(flattened_len_instr, block, None, call_stack.clone()) .first(); flattened_len = update_slice_length(flattened_len, dfg, BinaryOp::Sub, block); @@ -438,7 +447,7 @@ fn simplify_slice_pop_back( get_last_elem_instr, block, Some(element_types.to_vec()), - CallStack::new(), + call_stack.clone(), ) .first(); results.push_front(get_last_elem); diff --git a/compiler/noirc_evaluator/src/ssa/ir/printer.rs b/compiler/noirc_evaluator/src/ssa/ir/printer.rs index f7ffe2406ec..656bd26620e 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/printer.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/printer.rs @@ -105,7 +105,12 @@ pub(crate) fn display_terminator( Some(TerminatorInstruction::Jmp { destination, arguments, call_stack: _ }) => { writeln!(f, " jmp {}({})", destination, value_list(function, arguments)) } - Some(TerminatorInstruction::JmpIf { condition, then_destination, else_destination }) => { + Some(TerminatorInstruction::JmpIf { + condition, + then_destination, + else_destination, + call_stack: _, + }) => { writeln!( f, " jmpif {} then: {}, else: {}", diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs index 4deb21ef712..288e41cb994 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs @@ -214,6 +214,7 @@ struct Context<'f> { pub(crate) struct Store { old_value: ValueId, new_value: ValueId, + call_stack: CallStack, } #[derive(Clone)] @@ -239,6 +240,8 @@ struct ConditionalContext { then_branch: ConditionalBranch, // First block of the else branch else_branch: Option, + // Call stack where the final location is that of the entire `if` expression + call_stack: CallStack, } fn flatten_function_cfg(function: &mut Function) { @@ -289,7 +292,8 @@ impl<'f> Context<'f> { if let Some(context) = self.condition_stack.last() { let previous_branch = context.else_branch.as_ref().unwrap_or(&context.then_branch); let and = Instruction::binary(BinaryOp::And, previous_branch.condition, condition); - self.insert_instruction(and, CallStack::new()) + let call_stack = self.inserter.function.dfg.get_value_call_stack(condition); + self.insert_instruction(and, call_stack) } else { condition } @@ -333,9 +337,20 @@ impl<'f> Context<'f> { ) -> Vec { let terminator = self.inserter.function.dfg[block].unwrap_terminator().clone(); match &terminator { - TerminatorInstruction::JmpIf { condition, then_destination, else_destination } => { + TerminatorInstruction::JmpIf { + condition, + then_destination, + else_destination, + call_stack, + } => { self.arguments_stack.push(vec![]); - self.if_start(condition, then_destination, else_destination, &block) + self.if_start( + condition, + then_destination, + else_destination, + &block, + call_stack.clone(), + ) } TerminatorInstruction::Jmp { destination, arguments, call_stack: _ } => { let arguments = vecmap(arguments.clone(), |value| self.inserter.resolve(value)); @@ -370,6 +385,7 @@ impl<'f> Context<'f> { then_destination: &BasicBlockId, else_destination: &BasicBlockId, if_entry: &BasicBlockId, + call_stack: CallStack, ) -> Vec { // manage conditions let old_condition = *condition; @@ -389,6 +405,7 @@ impl<'f> Context<'f> { entry_block: *if_entry, then_branch: branch, else_branch: None, + call_stack, }; self.condition_stack.push(cond_context); self.insert_current_side_effects_enabled(); @@ -400,8 +417,12 @@ impl<'f> Context<'f> { let mut cond_context = self.condition_stack.pop().unwrap(); cond_context.then_branch.last_block = *block; - let else_condition = - self.insert_instruction(Instruction::Not(cond_context.condition), CallStack::new()); + let condition_call_stack = + self.inserter.function.dfg.get_value_call_stack(cond_context.condition); + let else_condition = self.insert_instruction( + Instruction::Not(cond_context.condition), + condition_call_stack.clone(), + ); let else_condition = self.link_condition(else_condition); // Make sure the else branch sees the previous values of each store @@ -504,14 +525,16 @@ impl<'f> Context<'f> { else_condition: cond_context.else_branch.as_ref().unwrap().condition, else_value: else_arg, }; + let call_stack = cond_context.call_stack.clone(); self.inserter .function .dfg - .insert_instruction_and_results(instruction, block, None, CallStack::new()) + .insert_instruction_and_results(instruction, block, None, call_stack) .first() }); - self.merge_stores(cond_context.then_branch, cond_context.else_branch); + let call_stack = cond_context.call_stack; + self.merge_stores(cond_context.then_branch, cond_context.else_branch, call_stack); self.arguments_stack.pop(); self.arguments_stack.pop(); self.arguments_stack.push(args); @@ -538,13 +561,14 @@ impl<'f> Context<'f> { &mut self, instruction: Instruction, ctrl_typevars: Option>, + call_stack: CallStack, ) -> InsertInstructionResult { let block = self.inserter.function.entry_block(); self.inserter.function.dfg.insert_instruction_and_results( instruction, block, ctrl_typevars, - CallStack::new(), + call_stack, ) } @@ -561,7 +585,8 @@ impl<'f> Context<'f> { } }; let enable_side_effects = Instruction::EnableSideEffects { condition }; - self.insert_instruction_with_typevars(enable_side_effects, None); + let call_stack = self.inserter.function.dfg.get_value_call_stack(condition); + self.insert_instruction_with_typevars(enable_side_effects, None, call_stack); } /// Merge any store instructions found in each branch. @@ -573,6 +598,7 @@ impl<'f> Context<'f> { &mut self, then_branch: ConditionalBranch, else_branch: Option, + call_stack: CallStack, ) { // Address -> (then_value, else_value, value_before_the_if) let mut new_map = BTreeMap::new(); @@ -608,11 +634,9 @@ impl<'f> Context<'f> { else_condition, else_value: *else_case, }; - let value = self - .inserter - .function - .dfg - .insert_instruction_and_results(instruction, block, None, CallStack::new()) + let dfg = &mut self.inserter.function.dfg; + let value = dfg + .insert_instruction_and_results(instruction, block, None, call_stack.clone()) .first(); new_values.insert(address, value); @@ -622,18 +646,28 @@ impl<'f> Context<'f> { for (address, (_, _, old_value)) in &new_map { let value = new_values[address]; let address = *address; - self.insert_instruction_with_typevars(Instruction::Store { address, value }, None); + self.insert_instruction_with_typevars( + Instruction::Store { address, value }, + None, + call_stack.clone(), + ); if let Some(store) = self.store_values.get_mut(&address) { store.new_value = value; } else { - self.store_values - .insert(address, Store { old_value: *old_value, new_value: value }); + self.store_values.insert( + address, + Store { + old_value: *old_value, + new_value: value, + call_stack: call_stack.clone(), + }, + ); } } } - fn remember_store(&mut self, address: ValueId, new_value: ValueId) { + fn remember_store(&mut self, address: ValueId, new_value: ValueId, call_stack: CallStack) { if !self.local_allocations.contains(&address) { if let Some(store_value) = self.store_values.get_mut(&address) { store_value.new_value = new_value; @@ -641,10 +675,11 @@ impl<'f> Context<'f> { let load = Instruction::Load { address }; let load_type = Some(vec![self.inserter.function.dfg.type_of_value(new_value)]); - let old_value = - self.insert_instruction_with_typevars(load.clone(), load_type).first(); + let old_value = self + .insert_instruction_with_typevars(load.clone(), load_type, call_stack.clone()) + .first(); - self.store_values.insert(address, Store { old_value, new_value }); + self.store_values.insert(address, Store { old_value, new_value, call_stack }); } } } @@ -706,7 +741,7 @@ impl<'f> Context<'f> { Instruction::Constrain(lhs, rhs, message) } Instruction::Store { address, value } => { - self.remember_store(address, value); + self.remember_store(address, value, call_stack); Instruction::Store { address, value } } Instruction::RangeCheck { value, max_bit_size, assert_message } => { @@ -834,7 +869,9 @@ impl<'f> Context<'f> { for (address, store) in store_values { let address = *address; let value = store.old_value; - self.insert_instruction_with_typevars(Instruction::Store { address, value }, None); + let instruction = Instruction::Store { address, value }; + // Considering the location of undoing a store to be the same as the original store. + self.insert_instruction_with_typevars(instruction, None, store.call_stack.clone()); } } } diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index de75d34565e..90e24a1d5e3 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -20,6 +20,8 @@ pub(crate) struct ValueMerger<'a> { slice_sizes: &'a mut HashMap, array_set_conditionals: &'a mut HashMap, + + call_stack: CallStack, } impl<'a> ValueMerger<'a> { @@ -29,8 +31,16 @@ impl<'a> ValueMerger<'a> { slice_sizes: &'a mut HashMap, array_set_conditionals: &'a mut HashMap, current_condition: Option, + call_stack: CallStack, ) -> Self { - ValueMerger { dfg, block, slice_sizes, array_set_conditionals, current_condition } + ValueMerger { + dfg, + block, + slice_sizes, + array_set_conditionals, + current_condition, + call_stack, + } } /// Merge two values a and b from separate basic blocks to a single value. @@ -164,7 +174,12 @@ impl<'a> ValueMerger<'a> { let mut get_element = |array, typevars| { let get = Instruction::ArrayGet { array, index }; self.dfg - .insert_instruction_and_results(get, self.block, typevars, CallStack::new()) + .insert_instruction_and_results( + get, + self.block, + typevars, + self.call_stack.clone(), + ) .first() }; @@ -234,7 +249,7 @@ impl<'a> ValueMerger<'a> { get, self.block, typevars, - CallStack::new(), + self.call_stack.clone(), ) .first() } @@ -365,7 +380,12 @@ impl<'a> ValueMerger<'a> { let mut get_element = |array, typevars| { let get = Instruction::ArrayGet { array, index }; self.dfg - .insert_instruction_and_results(get, self.block, typevars, CallStack::new()) + .insert_instruction_and_results( + get, + self.block, + typevars, + self.call_stack.clone(), + ) .first() }; @@ -384,7 +404,12 @@ impl<'a> ValueMerger<'a> { } fn insert_instruction(&mut self, instruction: Instruction) -> InsertInstructionResult { - self.dfg.insert_instruction_and_results(instruction, self.block, None, CallStack::new()) + self.dfg.insert_instruction_and_results( + instruction, + self.block, + None, + self.call_stack.clone(), + ) } fn insert_array_set( @@ -399,7 +424,7 @@ impl<'a> ValueMerger<'a> { instruction, self.block, None, - CallStack::new(), + self.call_stack.clone(), ); if let Some(condition) = condition { diff --git a/compiler/noirc_evaluator/src/ssa/opt/inlining.rs b/compiler/noirc_evaluator/src/ssa/opt/inlining.rs index 09802713363..d78399a3e6b 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/inlining.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/inlining.rs @@ -625,9 +625,17 @@ impl<'function> PerFunctionContext<'function> { .terminate_with_jmp(destination, arguments); None } - TerminatorInstruction::JmpIf { condition, then_destination, else_destination } => { + TerminatorInstruction::JmpIf { + condition, + then_destination, + else_destination, + call_stack, + } => { let condition = self.translate_value(*condition); + let mut new_call_stack = self.context.call_stack.clone(); + new_call_stack.append(call_stack.clone()); + // See if the value of the condition is known, and if so only inline the reachable // branch. This lets us inline some recursive functions without recurring forever. let dfg = &mut self.context.builder.current_function.dfg; @@ -635,14 +643,19 @@ impl<'function> PerFunctionContext<'function> { Some(constant) => { let next_block = if constant.is_zero() { *else_destination } else { *then_destination }; + let next_block = self.translate_block(next_block, block_queue); - self.context.builder.terminate_with_jmp(next_block, vec![]); + self.context + .builder + .set_call_stack(new_call_stack) + .terminate_with_jmp(next_block, vec![]); } None => { let then_block = self.translate_block(*then_destination, block_queue); let else_block = self.translate_block(*else_destination, block_queue); self.context .builder + .set_call_stack(new_call_stack) .terminate_with_jmpif(condition, then_block, else_block); } } diff --git a/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs b/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs index c70760de85f..b1ca5fa25a0 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs @@ -68,12 +68,14 @@ impl Context { let typ = function.dfg.type_of_value(then_value); assert!(!matches!(typ, Type::Numeric(_))); + let call_stack = function.dfg.get_call_stack(instruction); let mut value_merger = ValueMerger::new( &mut function.dfg, block, &mut self.slice_sizes, &mut self.array_set_conditionals, Some(current_conditional), + call_stack, ); let value = value_merger.merge_values( diff --git a/compiler/noirc_evaluator/src/ssa/opt/simplify_cfg.rs b/compiler/noirc_evaluator/src/ssa/opt/simplify_cfg.rs index 9d5d7879dcb..0a3b2a800ca 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/simplify_cfg.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/simplify_cfg.rs @@ -15,7 +15,7 @@ use acvm::acir::AcirField; use crate::ssa::{ ir::{ - basic_block::BasicBlockId, cfg::ControlFlowGraph, dfg::CallStack, function::Function, + basic_block::BasicBlockId, cfg::ControlFlowGraph, function::Function, instruction::TerminatorInstruction, }, ssa_gen::Ssa, @@ -82,16 +82,20 @@ fn check_for_constant_jmpif( block: BasicBlockId, cfg: &mut ControlFlowGraph, ) { - if let Some(TerminatorInstruction::JmpIf { condition, then_destination, else_destination }) = - function.dfg[block].terminator() + if let Some(TerminatorInstruction::JmpIf { + condition, + then_destination, + else_destination, + call_stack, + }) = function.dfg[block].terminator() { if let Some(constant) = function.dfg.get_numeric_constant(*condition) { let destination = if constant.is_zero() { *else_destination } else { *then_destination }; let arguments = Vec::new(); - let jmp = - TerminatorInstruction::Jmp { destination, arguments, call_stack: CallStack::new() }; + let call_stack = call_stack.clone(); + let jmp = TerminatorInstruction::Jmp { destination, arguments, call_stack }; function.dfg[block].set_terminator(jmp); cfg.recompute_block(function, block); } diff --git a/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs b/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs index 5f58be41422..f3e11e04e3a 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs @@ -258,7 +258,8 @@ fn get_induction_variable(function: &Function, block: BasicBlockId) -> Result Err(CallStack::new()), + Some(terminator) => Err(terminator.call_stack()), + None => Err(CallStack::new()), } } @@ -286,9 +287,9 @@ fn unroll_loop_header<'a>( context.inline_instructions_from_block(); match context.dfg()[fresh_block].unwrap_terminator() { - TerminatorInstruction::JmpIf { condition, then_destination, else_destination } => { + TerminatorInstruction::JmpIf { condition, then_destination, else_destination, call_stack } => { let condition = *condition; - let next_blocks = context.handle_jmpif(condition, *then_destination, *else_destination); + let next_blocks = context.handle_jmpif(condition, *then_destination, *else_destination, call_stack.clone()); // If there is only 1 next block the jmpif evaluated to a single known block. // This is the expected case and lets us know if we should loop again or not. @@ -392,9 +393,17 @@ impl<'f> LoopIteration<'f> { self.visited_blocks.insert(self.source_block); match self.inserter.function.dfg[self.insert_block].unwrap_terminator() { - TerminatorInstruction::JmpIf { condition, then_destination, else_destination } => { - self.handle_jmpif(*condition, *then_destination, *else_destination) - } + TerminatorInstruction::JmpIf { + condition, + then_destination, + else_destination, + call_stack, + } => self.handle_jmpif( + *condition, + *then_destination, + *else_destination, + call_stack.clone(), + ), TerminatorInstruction::Jmp { destination, arguments, call_stack: _ } => { if self.get_original_block(*destination) == self.loop_.header { assert_eq!(arguments.len(), 1); @@ -414,6 +423,7 @@ impl<'f> LoopIteration<'f> { condition: ValueId, then_destination: BasicBlockId, else_destination: BasicBlockId, + call_stack: CallStack, ) -> Vec { let condition = self.inserter.resolve(condition); @@ -425,11 +435,7 @@ impl<'f> LoopIteration<'f> { self.source_block = self.get_original_block(destination); let arguments = Vec::new(); - let jmp = TerminatorInstruction::Jmp { - destination, - arguments, - call_stack: CallStack::new(), - }; + let jmp = TerminatorInstruction::Jmp { destination, arguments, call_stack }; self.inserter.function.dfg.set_block_terminator(self.insert_block, jmp); vec![destination] }