diff --git a/compiler/noirc_evaluator/src/acir/mod.rs b/compiler/noirc_evaluator/src/acir/mod.rs index 798ecad9f5..e7b011b6d7 100644 --- a/compiler/noirc_evaluator/src/acir/mod.rs +++ b/compiler/noirc_evaluator/src/acir/mod.rs @@ -1842,7 +1842,7 @@ impl<'a> Context<'a> { } } - let call_stack = dfg.get_call_stack(call_stack); + let call_stack = dfg.call_stack_data.get_call_stack(call_stack); let warnings = if has_constant_return { vec![SsaReport::Warning(InternalWarning::ReturnConstant { call_stack })] } else { @@ -2934,7 +2934,8 @@ mod test { // Set a call stack for testing whether `brillig_locations` in the `GeneratedAcir` was accurately set. let mut stack = CallStack::unit(Location::dummy()); stack.push_back(Location::dummy()); - let call_stack = builder.current_function.dfg.get_or_insert_locations(stack); + let call_stack = + builder.current_function.dfg.call_stack_data.get_or_insert_locations(stack); builder.set_call_stack(call_stack); let foo_v0 = builder.add_parameter(Type::field()); diff --git a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs index 0c58f27447..855034cedd 100644 --- a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs @@ -85,7 +85,8 @@ impl FunctionBuilder { self.current_block = new_function.entry_block(); let old_function = std::mem::replace(&mut self.current_function, new_function); // Copy the call stack to the new function - self.call_stack = self.current_function.dfg.get_or_insert_locations(call_stack); + self.call_stack = + self.current_function.dfg.call_stack_data.get_or_insert_locations(call_stack); self.finished_functions.push(old_function); } @@ -199,7 +200,7 @@ impl FunctionBuilder { } pub(crate) fn set_location(&mut self, location: Location) -> &mut FunctionBuilder { - self.call_stack = self.current_function.dfg.add_location_to_root(location); + self.call_stack = self.current_function.dfg.call_stack_data.add_location_to_root(location); self } diff --git a/compiler/noirc_evaluator/src/ssa/ir/call_stack.rs b/compiler/noirc_evaluator/src/ssa/ir/call_stack.rs index daf8dc8250..cadfb5d8e2 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/call_stack.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/call_stack.rs @@ -23,56 +23,92 @@ impl CallStackId { pub(crate) fn is_root(&self) -> bool { self.0 == 0 } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub(crate) struct LocationNode { + pub(crate) parent: Option, + pub(crate) children: Vec, + pub(crate) value: Location, +} +#[derive(Debug, Default, Clone, Serialize, Deserialize)] +pub(crate) struct CallStackHelper { + locations: Vec, +} + +impl CallStackHelper { /// Construct a CallStack from a CallStackId - pub(crate) fn get_call_stack(&self, locations: &[LocationNode]) -> CallStack { - let mut call_stack = im::Vector::new(); - let mut current_location = *self; - while let Some(parent) = locations[current_location.index()].parent { - call_stack.push_back(locations[current_location.index()].value); - current_location = parent; + pub(crate) fn get_call_stack(&self, mut call_stack: CallStackId) -> CallStack { + let mut result = im::Vector::new(); + while let Some(parent) = self.locations[call_stack.index()].parent { + result.push_back(self.locations[call_stack.index()].value); + call_stack = parent; + } + result + } + + /// Returns a new CallStackId which extends the call_stack with the provided call_stack. + pub(crate) fn extend_call_stack( + &mut self, + mut call_stack: CallStackId, + locations: &CallStack, + ) -> CallStackId { + for location in locations { + call_stack = self.add_child(call_stack, *location); } call_stack } /// Adds a location to the call stack - pub(crate) fn add_child( - &self, - location: Location, - locations: &mut Vec, - ) -> CallStackId { - if let Some(result) = locations[self.index()] + pub(crate) fn add_child(&mut self, call_stack: CallStackId, location: Location) -> CallStackId { + if let Some(result) = self.locations[call_stack.index()] .children .iter() .rev() .take(1000) - .find(|child| locations[child.index()].value == location) + .find(|child| self.locations[child.index()].value == location) { return *result; } - locations.push(LocationNode { parent: Some(*self), children: vec![], value: location }); - let new_location = CallStackId::new(locations.len() - 1); - locations[self.index()].children.push(new_location); + self.locations.push(LocationNode { + parent: Some(call_stack), + children: vec![], + value: location, + }); + let new_location = CallStackId::new(self.locations.len() - 1); + self.locations[call_stack.index()].children.push(new_location); new_location } - /// Returns a new CallStackId which extends the current one with the provided call_stack. - pub(crate) fn extend( + /// Retrieve the CallStackId corresponding to call_stack with the last 'len' locations removed. + pub(crate) fn unwind_call_stack( &self, - call_stack: &CallStack, - locations: &mut Vec, + mut call_stack: CallStackId, + mut len: usize, ) -> CallStackId { - let mut result = *self; - for location in call_stack { - result = result.add_child(*location, locations); + while len > 0 { + if let Some(parent) = self.locations[call_stack.index()].parent { + len -= 1; + call_stack = parent; + } else { + break; + } } - result + call_stack } -} -#[derive(Debug, Clone, Serialize, Deserialize)] -pub(crate) struct LocationNode { - pub(crate) parent: Option, - pub(crate) children: Vec, - pub(crate) value: Location, + pub(crate) fn add_location_to_root(&mut self, location: Location) -> CallStackId { + if self.locations.is_empty() { + self.locations.push(LocationNode { parent: None, children: vec![], value: location }); + CallStackId::root() + } else { + self.add_child(CallStackId::root(), location) + } + } + + /// Get (or create) a CallStackId corresponding to the given locations + pub(crate) fn get_or_insert_locations(&mut self, locations: CallStack) -> CallStackId { + self.extend_call_stack(CallStackId::root(), &locations) + } } diff --git a/compiler/noirc_evaluator/src/ssa/ir/dfg.rs b/compiler/noirc_evaluator/src/ssa/ir/dfg.rs index bd2f5e44e4..72ba369f98 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/dfg.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/dfg.rs @@ -4,7 +4,7 @@ use crate::ssa::{function_builder::data_bus::DataBus, ir::instruction::SimplifyR use super::{ basic_block::{BasicBlock, BasicBlockId}, - call_stack::{CallStack, CallStackId, LocationNode}, + call_stack::{CallStack, CallStackHelper, CallStackId}, function::FunctionId, instruction::{ Instruction, InstructionId, InstructionResultType, Intrinsic, TerminatorInstruction, @@ -94,7 +94,7 @@ pub(crate) struct DataFlowGraph { #[serde(skip)] locations: HashMap, - location_array: Vec, + pub(crate) call_stack_data: CallStackHelper, #[serde(skip)] pub(crate) data_bus: DataBus, @@ -489,7 +489,7 @@ impl DataFlowGraph { pub(crate) fn get_instruction_call_stack(&self, instruction: InstructionId) -> CallStack { let call_stack = self.get_instruction_call_stack_id(instruction); - self.get_call_stack(call_stack) + self.call_stack_data.get_call_stack(call_stack) } pub(crate) fn get_instruction_call_stack_id(&self, instruction: InstructionId) -> CallStackId { @@ -502,29 +502,11 @@ impl DataFlowGraph { location: Location, ) { let call_stack = self.locations.entry(instruction).or_default(); - call_stack.add_child(location, &mut self.location_array); + *call_stack = self.call_stack_data.add_child(*call_stack, location); } - pub(crate) fn add_location_to_root(&mut self, location: Location) -> CallStackId { - if self.location_array.is_empty() { - self.location_array.push(LocationNode { - parent: None, - children: vec![], - value: location, - }); - CallStackId::root() - } else { - CallStackId::root().add_child(location, &mut self.location_array) - } - } - - /// Get (or create) a CallStackId corresponding to the given locations - pub(crate) fn get_or_insert_locations(&mut self, locations: CallStack) -> CallStackId { - let mut result = CallStackId::root(); - for location in locations { - result = result.add_child(location, &mut self.location_array); - } - result + pub(crate) fn get_call_stack(&self, call_stack: CallStackId) -> CallStack { + self.call_stack_data.get_call_stack(call_stack) } pub(crate) fn get_value_call_stack(&self, value: ValueId) -> CallStack { @@ -543,35 +525,6 @@ impl DataFlowGraph { } } - pub(crate) fn get_call_stack(&self, call_stack: CallStackId) -> CallStack { - call_stack.get_call_stack(&self.location_array) - } - - pub(crate) fn extend_call_stack( - &mut self, - call_stack: CallStackId, - locations: &CallStack, - ) -> CallStackId { - call_stack.extend(locations, &mut self.location_array) - } - - // Retrieve the CallStackId corresponding to call_stack with the last 'len' locations removed. - pub(crate) fn unwind_call_stack( - &self, - mut call_stack: CallStackId, - mut len: usize, - ) -> CallStackId { - while len > 0 { - if let Some(parent) = self.location_array[call_stack.index()].parent { - len -= 1; - call_stack = parent; - } else { - break; - } - } - call_stack - } - /// True if the given ValueId refers to a (recursively) constant value pub(crate) fn is_constant(&self, argument: ValueId) -> bool { match &self[self.resolve(argument)] { diff --git a/compiler/noirc_evaluator/src/ssa/ir/function.rs b/compiler/noirc_evaluator/src/ssa/ir/function.rs index 189331a5ac..49217c7a8b 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/function.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/function.rs @@ -87,7 +87,7 @@ impl Function { pub(crate) fn new(name: String, id: FunctionId) -> Self { let mut dfg = DataFlowGraph::default(); // Adds root node for the location tree - dfg.add_location_to_root(Location::dummy()); + dfg.call_stack_data.add_location_to_root(Location::dummy()); let entry_block = dfg.make_block(); Self { name, id, entry_block, dfg, runtime: RuntimeType::Acir(InlineType::default()) } } diff --git a/compiler/noirc_evaluator/src/ssa/opt/inlining.rs b/compiler/noirc_evaluator/src/ssa/opt/inlining.rs index 0f638a8964..11201fc8f8 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/inlining.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/inlining.rs @@ -668,6 +668,7 @@ impl<'function> PerFunctionContext<'function> { .builder .current_function .dfg + .call_stack_data .extend_call_stack(self.context.call_stack, &call_stack); self.context.call_stack = new_call_stack; @@ -677,6 +678,7 @@ impl<'function> PerFunctionContext<'function> { .builder .current_function .dfg + .call_stack_data .unwind_call_stack(self.context.call_stack, call_stack_len); let new_results = InsertInstructionResult::Results(call_id, &new_results); @@ -695,6 +697,7 @@ impl<'function> PerFunctionContext<'function> { .builder .current_function .dfg + .call_stack_data .extend_call_stack(call_stack, &source_call_stack); let results = self.source_function.dfg.instruction_results(id); let results = vecmap(results, |id| self.source_function.dfg.resolve(*id)); @@ -758,6 +761,7 @@ impl<'function> PerFunctionContext<'function> { .builder .current_function .dfg + .call_stack_data .extend_call_stack(self.context.call_stack, &call_stack); self.context @@ -779,6 +783,7 @@ impl<'function> PerFunctionContext<'function> { .builder .current_function .dfg + .call_stack_data .extend_call_stack(self.context.call_stack, &call_stack); // See if the value of the condition is known, and if so only inline the reachable @@ -816,12 +821,14 @@ impl<'function> PerFunctionContext<'function> { let block_id = self.context.builder.current_block(); if self.inlining_entry { - let call_stack = self.source_function.dfg.get_call_stack(*call_stack); + let call_stack = + self.source_function.dfg.call_stack_data.get_call_stack(*call_stack); let new_call_stack = self .context .builder .current_function .dfg + .call_stack_data .extend_call_stack(self.context.call_stack, &call_stack); self.context diff --git a/compiler/noirc_evaluator/src/ssa/opt/normalize_value_ids.rs b/compiler/noirc_evaluator/src/ssa/opt/normalize_value_ids.rs index ea640042ed..f8ad5eafbf 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/normalize_value_ids.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/normalize_value_ids.rs @@ -88,7 +88,8 @@ impl Context { let call_stack = old_function.dfg.get_instruction_call_stack_id(old_instruction_id); let locations = old_function.dfg.get_call_stack(call_stack); - let new_call_stack = new_function.dfg.get_or_insert_locations(locations); + let new_call_stack = + new_function.dfg.call_stack_data.get_or_insert_locations(locations); let old_results = old_function.dfg.instruction_results(old_instruction_id); let ctrl_typevars = instruction @@ -116,7 +117,8 @@ impl Context { .map_values(|value| self.new_ids.map_value(new_function, old_function, value)); terminator.mutate_blocks(|old_block| self.new_ids.blocks[&old_block]); let locations = old_function.dfg.get_call_stack(terminator.call_stack()); - let new_call_stack = new_function.dfg.get_or_insert_locations(locations); + let new_call_stack = + new_function.dfg.call_stack_data.get_or_insert_locations(locations); terminator.set_call_stack(new_call_stack); new_function.dfg.set_block_terminator(new_block_id, terminator); } diff --git a/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs index 07457e0e80..d3821158b8 100644 --- a/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs @@ -91,8 +91,12 @@ pub(crate) fn generate_ssa( None, ); } - let return_call_stack = - function_context.builder.current_function.dfg.add_location_to_root(return_location); + let return_call_stack = function_context + .builder + .current_function + .dfg + .call_stack_data + .add_location_to_root(return_location); let return_instruction = function_context.builder.current_function.dfg[block].unwrap_terminator_mut();