Skip to content

Commit 521f5ce

Browse files
authored
fix: avoid creating unnecessary memory blocks (#7114)
1 parent 548be74 commit 521f5ce

File tree

4 files changed

+67
-45
lines changed

4 files changed

+67
-45
lines changed

compiler/noirc_evaluator/src/acir/mod.rs

+61-43
Original file line numberDiff line numberDiff line change
@@ -1069,8 +1069,7 @@ impl<'a> Context<'a> {
10691069
// Ensure that array id is fully resolved.
10701070
let array = dfg.resolve(array);
10711071

1072-
let array_id = dfg.resolve(array);
1073-
let array_typ = dfg.type_of_value(array_id);
1072+
let array_typ = dfg.type_of_value(array);
10741073
// Compiler sanity checks
10751074
assert!(!array_typ.is_nested_slice(), "ICE: Nested slice type has reached ACIR generation");
10761075
let (Type::Array(_, _) | Type::Slice(_)) = &array_typ else {
@@ -1125,15 +1124,7 @@ impl<'a> Context<'a> {
11251124
index: ValueId,
11261125
store_value: Option<ValueId>,
11271126
) -> Result<bool, RuntimeError> {
1128-
let array_id = dfg.resolve(array);
1129-
let array_typ = dfg.type_of_value(array_id);
1130-
// Compiler sanity checks
1131-
assert!(!array_typ.is_nested_slice(), "ICE: Nested slice type has reached ACIR generation");
1132-
let (Type::Array(_, _) | Type::Slice(_)) = &array_typ else {
1133-
unreachable!("ICE: expected array or slice type");
1134-
};
1135-
1136-
match self.convert_value(array_id, dfg) {
1127+
match self.convert_value(array, dfg) {
11371128
AcirValue::Var(acir_var, _) => {
11381129
Err(RuntimeError::InternalError(InternalError::Unexpected {
11391130
expected: "an array value".to_string(),
@@ -2231,45 +2222,41 @@ impl<'a> Context<'a> {
22312222
Intrinsic::AsSlice => {
22322223
let slice_contents = arguments[0];
22332224
let slice_typ = dfg.type_of_value(slice_contents);
2234-
let block_id = self.ensure_array_is_initialized(slice_contents, dfg)?;
22352225
assert!(!slice_typ.is_nested_slice(), "ICE: Nested slice used in ACIR generation");
22362226

2237-
let result_block_id = self.block_id(&result_ids[1]);
22382227
let acir_value = self.convert_value(slice_contents, dfg);
2228+
let (slice_length, result) = match acir_value {
2229+
AcirValue::Var(_, _) => {
2230+
unreachable!("ICE: cannot call `as_slice` on non-array type")
2231+
}
2232+
array @ AcirValue::Array(_) => {
2233+
let array_len = if !slice_typ.contains_slice_element() {
2234+
slice_typ.flattened_size() as usize
2235+
} else {
2236+
self.flattened_slice_size(slice_contents, dfg)
2237+
};
2238+
(array_len, array)
2239+
}
2240+
AcirValue::DynamicArray(source_array) => {
2241+
let result_block_id = self.block_id(&result_ids[1]);
2242+
self.copy_dynamic_array(
2243+
source_array.block_id,
2244+
result_block_id,
2245+
source_array.len,
2246+
)?;
22392247

2240-
let array_len = if !slice_typ.contains_slice_element() {
2241-
slice_typ.flattened_size() as usize
2242-
} else {
2243-
self.flattened_slice_size(slice_contents, dfg)
2244-
};
2245-
let slice_length = self.acir_context.add_constant(array_len);
2246-
self.copy_dynamic_array(block_id, result_block_id, array_len)?;
2248+
let array = AcirValue::DynamicArray(AcirDynamicArray {
2249+
block_id: result_block_id,
2250+
len: source_array.len,
2251+
value_types: source_array.value_types,
2252+
element_type_sizes: source_array.element_type_sizes,
2253+
});
22472254

2248-
let element_type_sizes = if !can_omit_element_sizes_array(&slice_typ) {
2249-
Some(self.init_element_type_sizes_array(
2250-
&slice_typ,
2251-
slice_contents,
2252-
Some(&acir_value),
2253-
dfg,
2254-
)?)
2255-
} else {
2256-
None
2255+
(source_array.len, array)
2256+
}
22572257
};
22582258

2259-
let value_types = self.convert_value(slice_contents, dfg).flat_numeric_types();
2260-
assert!(
2261-
array_len == value_types.len(),
2262-
"AsSlice: unexpected length difference: {:?} != {:?}",
2263-
array_len,
2264-
value_types.len()
2265-
);
2266-
2267-
let result = AcirValue::DynamicArray(AcirDynamicArray {
2268-
block_id: result_block_id,
2269-
len: value_types.len(),
2270-
value_types,
2271-
element_type_sizes,
2272-
});
2259+
let slice_length = self.acir_context.add_constant(slice_length);
22732260
Ok(vec![AcirValue::Var(slice_length, AcirType::field()), result])
22742261
}
22752262
Intrinsic::SlicePushBack => {
@@ -3709,4 +3696,35 @@ mod test {
37093696
}
37103697
}
37113698
}
3699+
3700+
#[test]
3701+
fn does_not_generate_memory_blocks_without_dynamic_accesses() {
3702+
let src = "
3703+
acir(inline) fn main f0 {
3704+
b0(v0: [Field; 2]):
3705+
v2, v3 = call as_slice(v0) -> (u32, [Field])
3706+
call f1(u32 2, v3)
3707+
v7 = array_get v0, index u32 0 -> Field
3708+
constrain v7 == Field 0
3709+
return
3710+
}
3711+
3712+
brillig(inline) fn foo f1 {
3713+
b0(v0: u32, v1: [Field]):
3714+
return
3715+
}
3716+
";
3717+
let ssa = Ssa::from_str(src).unwrap();
3718+
let brillig = ssa.to_brillig(false);
3719+
3720+
let (acir_functions, _brillig_functions, _, _) = ssa
3721+
.into_acir(&brillig, ExpressionWidth::default())
3722+
.expect("Should compile manually written SSA into ACIR");
3723+
3724+
assert_eq!(acir_functions.len(), 1);
3725+
3726+
// Check that no memory opcodes were emitted.
3727+
let main = &acir_functions[0];
3728+
assert!(!main.opcodes().iter().any(|opcode| matches!(opcode, Opcode::MemoryOp { .. })));
3729+
}
37123730
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
index = 1
2+
value = 1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
fn main(args: [Field; 2]) {
1+
fn main(value: Field, index: u32) {
2+
let mut args = &[0, 1];
3+
args[index] = value;
24
/// Safety: n/a
35
unsafe { store(args) };
46
// Dummy test to remove the 'underconstraint bug'
57
assert(args[0] + args[1] != 0);
68
}
79

8-
pub unconstrained fn store(_: [Field]) {}
10+
pub unconstrained fn store(_: [Field]) {}

0 commit comments

Comments
 (0)