Skip to content

Commit 48cf1a7

Browse files
vezenovmTomAFrenchjfecher
authored
chore: Re-open #3258 (#3410)
Co-authored-by: Tom French <[email protected]> Co-authored-by: Tom French <[email protected]> Co-authored-by: jfecher <[email protected]>
1 parent 734a4b9 commit 48cf1a7

6 files changed

Lines changed: 862 additions & 55 deletions

File tree

compiler/noirc_evaluator/src/ssa.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ use std::{
1212
ops::Range,
1313
};
1414

15-
use crate::errors::{RuntimeError, SsaReport};
15+
use crate::{
16+
brillig::Brillig,
17+
errors::{RuntimeError, SsaReport},
18+
};
1619
use acvm::acir::{
1720
circuit::{Circuit, PublicInputs},
1821
native_types::Witness,
@@ -42,7 +45,8 @@ pub(crate) fn optimize_into_acir(
4245
print_brillig_trace: bool,
4346
) -> Result<GeneratedAcir, RuntimeError> {
4447
let abi_distinctness = program.return_distinctness;
45-
let ssa = SsaBuilder::new(program, print_ssa_passes)?
48+
49+
let ssa_builder = SsaBuilder::new(program, print_ssa_passes)?
4650
.run_pass(Ssa::defunctionalize, "After Defunctionalization:")
4751
.run_pass(Ssa::inline_functions, "After Inlining:")
4852
// Run mem2reg with the CFG separated into blocks
@@ -59,10 +63,17 @@ pub(crate) fn optimize_into_acir(
5963
// Run mem2reg once more with the flattened CFG to catch any remaining loads/stores
6064
.run_pass(Ssa::mem2reg, "After Mem2Reg:")
6165
.run_pass(Ssa::fold_constants, "After Constant Folding:")
62-
.run_pass(Ssa::dead_instruction_elimination, "After Dead Instruction Elimination:")
66+
.run_pass(Ssa::dead_instruction_elimination, "After Dead Instruction Elimination:");
67+
68+
let brillig = ssa_builder.to_brillig(print_brillig_trace);
69+
70+
// Split off any passes the are not necessary for Brillig generation but are necessary for ACIR generation.
71+
// We only need to fill out nested slices as we need to have a known length when dealing with memory operations
72+
// in ACIR gen while this is not necessary in the Brillig IR.
73+
let ssa = ssa_builder
74+
.run_pass(Ssa::fill_internal_slices, "After Fill Internal Slice Dummy Data:")
6375
.finish();
6476

65-
let brillig = ssa.to_brillig(print_brillig_trace);
6677
let last_array_uses = ssa.find_last_array_uses();
6778
ssa.into_acir(brillig, abi_distinctness, &last_array_uses)
6879
}
@@ -156,6 +167,10 @@ impl SsaBuilder {
156167
Ok(self.print(msg))
157168
}
158169

170+
fn to_brillig(&self, print_brillig_trace: bool) -> Brillig {
171+
self.ssa.to_brillig(print_brillig_trace)
172+
}
173+
159174
fn print(self, msg: &str) -> Self {
160175
if self.print_ssa_passes {
161176
println!("{msg}\n{}", self.ssa);

compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs

Lines changed: 62 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,9 @@ impl Context {
424424
let rhs_var = read_from_index(rhs_block_id, i)?;
425425
Ok((lhs_var, rhs_var))
426426
}),
427-
_ => unreachable!("ICE: lhs and rhs should be of the same type"),
427+
_ => {
428+
unreachable!("ICE: lhs and rhs should be of the same type")
429+
}
428430
}
429431
}
430432

@@ -502,7 +504,7 @@ impl Context {
502504
self.initialize_array(block_id, len, Some(output.clone()))?;
503505
}
504506
AcirValue::DynamicArray(_) => {
505-
unreachable!("The output from an intrinsic call is expected to be a single value or an array but got {output:?}");
507+
// Do nothing as a dynamic array returned from a slice intrinsic should already be initialized
506508
}
507509
AcirValue::Var(_, _) => {
508510
// Do nothing
@@ -1018,7 +1020,8 @@ impl Context {
10181020
}
10191021
}
10201022

1021-
let element_type_sizes = self.init_element_type_sizes_array(&array_typ, array_id, dfg)?;
1023+
let element_type_sizes =
1024+
self.init_element_type_sizes_array(&array_typ, array_id, None, dfg)?;
10221025
let result_value = AcirValue::DynamicArray(AcirDynamicArray {
10231026
block_id: result_block_id,
10241027
len: array_len,
@@ -1105,6 +1108,7 @@ impl Context {
11051108
&mut self,
11061109
array_typ: &Type,
11071110
array_id: ValueId,
1111+
array_acir_value: Option<AcirValue>,
11081112
dfg: &DataFlowGraph,
11091113
) -> Result<BlockId, RuntimeError> {
11101114
let element_type_sizes = self.internal_block_id(&array_id);
@@ -1132,7 +1136,11 @@ impl Context {
11321136
Value::Instruction { .. } | Value::Param { .. } => {
11331137
// An instruction representing the slice means it has been processed previously during ACIR gen.
11341138
// Use the previously defined result of an array operation to fetch the internal type information.
1135-
let array_acir_value = self.convert_value(array_id, dfg);
1139+
let array_acir_value = if let Some(array_acir_value) = array_acir_value {
1140+
array_acir_value
1141+
} else {
1142+
self.convert_value(array_id, dfg)
1143+
};
11361144
match array_acir_value {
11371145
AcirValue::DynamicArray(AcirDynamicArray {
11381146
element_type_sizes: inner_elem_type_sizes,
@@ -1274,7 +1282,8 @@ impl Context {
12741282
var_index: AcirVar,
12751283
dfg: &DataFlowGraph,
12761284
) -> Result<AcirVar, RuntimeError> {
1277-
let element_type_sizes = self.init_element_type_sizes_array(array_typ, array_id, dfg)?;
1285+
let element_type_sizes =
1286+
self.init_element_type_sizes_array(array_typ, array_id, None, dfg)?;
12781287

12791288
let predicate_index =
12801289
self.acir_context.mul_var(var_index, self.current_side_effects_enabled_var)?;
@@ -1728,26 +1737,50 @@ impl Context {
17281737
}
17291738
Intrinsic::SlicePushBack => {
17301739
let slice_length = self.convert_value(arguments[0], dfg).into_var()?;
1740+
let (array_id, array_typ, _) =
1741+
self.check_array_is_initialized(arguments[1], dfg)?;
17311742
let slice = self.convert_value(arguments[1], dfg);
1732-
// TODO(#2461): make sure that we have handled nested struct inputs
1733-
let element = self.convert_value(arguments[2], dfg);
17341743

1744+
// TODO(#3364): make sure that we have handled nested struct inputs
1745+
let element = self.convert_value(arguments[2], dfg);
17351746
let one = self.acir_context.add_constant(FieldElement::one());
17361747
let new_slice_length = self.acir_context.add_var(slice_length, one)?;
17371748

1749+
// We attach the element no matter what in case len == capacity, as otherwise we
1750+
// may get an out of bounds error.
17381751
let mut new_slice = Vector::new();
1739-
self.slice_intrinsic_input(&mut new_slice, slice)?;
1740-
new_slice.push_back(element);
1741-
1742-
Ok(vec![
1743-
AcirValue::Var(new_slice_length, AcirType::field()),
1744-
AcirValue::Array(new_slice),
1745-
])
1752+
self.slice_intrinsic_input(&mut new_slice, slice.clone())?;
1753+
new_slice.push_back(element.clone());
1754+
1755+
// TODO(#3364): This works for non-nested outputs
1756+
let len = Self::flattened_value_size(&slice);
1757+
let new_elem_size = Self::flattened_value_size(&element);
1758+
let new_slice_val = AcirValue::Array(new_slice);
1759+
let result_block_id = self.block_id(&result_ids[1]);
1760+
self.initialize_array(
1761+
result_block_id,
1762+
len + new_elem_size,
1763+
Some(new_slice_val.clone()),
1764+
)?;
1765+
let mut var_index = slice_length;
1766+
self.array_set_value(element, result_block_id, &mut var_index)?;
1767+
1768+
let result = AcirValue::DynamicArray(AcirDynamicArray {
1769+
block_id: result_block_id,
1770+
len: len + new_elem_size,
1771+
element_type_sizes: self.init_element_type_sizes_array(
1772+
&array_typ,
1773+
array_id,
1774+
Some(new_slice_val),
1775+
dfg,
1776+
)?,
1777+
});
1778+
Ok(vec![AcirValue::Var(new_slice_length, AcirType::field()), result])
17461779
}
17471780
Intrinsic::SlicePushFront => {
17481781
let slice_length = self.convert_value(arguments[0], dfg).into_var()?;
1749-
let slice = self.convert_value(arguments[1], dfg);
1750-
// TODO(#2461): make sure that we have handled nested struct inputs
1782+
let slice: AcirValue = self.convert_value(arguments[1], dfg);
1783+
// TODO(#3364): make sure that we have handled nested struct inputs
17511784
let element = self.convert_value(arguments[2], dfg);
17521785

17531786
let one = self.acir_context.add_constant(FieldElement::one());
@@ -1769,12 +1802,18 @@ impl Context {
17691802
let one = self.acir_context.add_constant(FieldElement::one());
17701803
let new_slice_length = self.acir_context.sub_var(slice_length, one)?;
17711804

1805+
let (_, _, block_id) = self.check_array_is_initialized(arguments[1], dfg)?;
1806+
let mut var_index = new_slice_length;
1807+
let elem = self.array_get_value(
1808+
&dfg.type_of_value(result_ids[2]),
1809+
block_id,
1810+
&mut var_index,
1811+
&[],
1812+
)?;
1813+
1814+
// TODO(#3364): make sure that we have handled nested struct inputs
17721815
let mut new_slice = Vector::new();
17731816
self.slice_intrinsic_input(&mut new_slice, slice)?;
1774-
// TODO(#2461): make sure that we have handled nested struct inputs
1775-
let elem = new_slice
1776-
.pop_back()
1777-
.expect("There are no elements in this slice to be removed");
17781817

17791818
Ok(vec![
17801819
AcirValue::Var(new_slice_length, AcirType::field()),
@@ -1791,7 +1830,7 @@ impl Context {
17911830

17921831
let mut new_slice = Vector::new();
17931832
self.slice_intrinsic_input(&mut new_slice, slice)?;
1794-
// TODO(#2461): make sure that we have handled nested struct inputs
1833+
// TODO(#3364): make sure that we have handled nested struct inputs
17951834
let elem = new_slice
17961835
.pop_front()
17971836
.expect("There are no elements in this slice to be removed");
@@ -1831,7 +1870,7 @@ impl Context {
18311870
// they are attempting to insert at too large of an index.
18321871
// This check prevents a panic inside of the im::Vector insert method.
18331872
if index <= new_slice.len() {
1834-
// TODO(#2461): make sure that we have handled nested struct inputs
1873+
// TODO(#3364): make sure that we have handled nested struct inputs
18351874
new_slice.insert(index, element);
18361875
}
18371876

@@ -1869,7 +1908,7 @@ impl Context {
18691908
// they are attempting to remove at too large of an index.
18701909
// This check prevents a panic inside of the im::Vector remove method.
18711910
let removed_elem = if index < new_slice.len() {
1872-
// TODO(#2461): make sure that we have handled nested struct inputs
1911+
// TODO(#3364): make sure that we have handled nested struct inputs
18731912
new_slice.remove(index)
18741913
} else {
18751914
// This is a dummy value which should never be used if the appropriate

0 commit comments

Comments
 (0)