Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 46 additions & 2 deletions compiler/noirc_evaluator/src/ssa/ir/dfg/simplify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ pub(crate) fn simplify(

let array_or_slice_type = dfg.type_of_value(*array);
if matches!(array_or_slice_type, Type::Array(_, 1))
&& array_or_slice_type.flattened_size() == 1
&& array_or_slice_type.element_size() == 1
{
// If the array is of length 1 then we know the only value which can be potentially read out of it.
// We can then simply assert that the index is equal to zero and return the array's contained value.
Expand Down Expand Up @@ -336,6 +336,11 @@ pub(crate) fn simplify(
/// v4 = array_get v2, index u32 0 -> Field
/// ```
/// We then attempt to resolve the array read immediately.
///
/// Note that this does not work if the array has length 1, but contains a complex type such as tuple,
/// which consists of multiple elements. If that is the case than the `index` will most likely not be
/// a constant, but a base plus an offset, and if the array contains repeated elements of the same type
/// for example, we wouldn't be able to come up with a constant offset even if we knew the return type.
fn optimize_length_one_array_read(
dfg: &mut DataFlowGraph,
block: BasicBlockId,
Expand Down Expand Up @@ -365,7 +370,7 @@ fn optimize_length_one_array_read(
/// v3 = array_set v2, index 2, value: 7
/// v4 = array_get v3, index 1
///
/// We want to optimize `v4` to `10`. To do this we need to follow the array value
/// We want to optimize `v4` to `11`. To do this we need to follow the array value
/// through several array sets. For each array set:
/// - If the index is non-constant we fail the optimization since any index may be changed
/// - If the index is constant and is our target index, we conservatively fail the optimization
Expand All @@ -374,6 +379,10 @@ fn optimize_length_one_array_read(
/// - Otherwise, we check the array value of the array set.
/// - If the array value is constant, we use that array.
/// - If the array value is from a previous array-set, we recur.
///
/// That is, we have multiple `array_set` instructions setting various constant indexes
/// of the same array, returning a modified version. We want to go backwards until we
/// find the last `array_set` for the index we are interested in, and return the value set.
fn try_optimize_array_get_from_previous_set(
dfg: &DataFlowGraph,
mut array_id: ValueId,
Expand Down Expand Up @@ -646,6 +655,41 @@ mod tests {
"#);
}

#[test]
fn does_not_use_flattened_size_for_length_one_array_check() {
let src = "
acir(inline) fn main f0 {
b0(v0: Field, v1: u32):
v2 = make_array [v0, v0] : [Field; 2]
v3 = make_array [v2] : [[Field; 2]; 1]
v4 = make_array [] : [Field; 0]
v5 = make_array [v4, v0] : [([Field; 0], Field); 1]
v6 = array_get v3, index v1 -> [Field; 2]
v7 = add v1, u32 1
v8 = array_get v5, index v7 -> Field
return v6, v8
}
";
// The flattened size of v3 is 2, but it has 1 element -> it can be optimized.
// The flattened size of v5 is 1, but it has 2 elements -> it cannot be optimized.

let ssa = Ssa::from_str_simplifying(src).unwrap();

assert_ssa_snapshot!(ssa, @r#"
acir(inline) fn main f0 {
b0(v0: Field, v1: u32):
v2 = make_array [v0, v0] : [Field; 2]
v3 = make_array [v2] : [[Field; 2]; 1]
v4 = make_array [] : [Field; 0]
v5 = make_array [v4, v0] : [([Field; 0], Field); 1]
constrain v1 == u32 0, "Index out of bounds"
v8 = add v1, u32 1
v9 = array_get v5, index v8 -> Field
return v2, v9
}
"#);
}

#[test]
fn does_not_crash_on_truncated_division_with_large_denominators() {
// There can be invalid division instructions which have extremely large denominators
Expand Down
6 changes: 5 additions & 1 deletion compiler/noirc_evaluator/src/ssa/ir/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,11 @@ impl Type {
}
}

/// Returns the flattened size of a Type
/// Returns the flattened size of a Type.
///
/// The flattened type is mostly useful in ACIR, where nested arrays are also flattened,
/// as opposed to SSA, where only tuples get flattened into the array they are in,
/// but nested arrays appear as a value ID.
pub(crate) fn flattened_size(&self) -> u32 {
match self {
Type::Array(elements, len) => {
Expand Down
6 changes: 6 additions & 0 deletions test_programs/execution_success/regression_10141/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "regression_10141"
type = "bin"
authors = [""]

[dependencies]
2 changes: 2 additions & 0 deletions test_programs/execution_success/regression_10141/Prover.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
a = 0
return = 10
7 changes: 7 additions & 0 deletions test_programs/execution_success/regression_10141/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
fn main(a: u32) -> pub Field {
foo()[a].1 as Field
}

fn foo() -> [([u64; 0], u16); 1] {
[([], 10)]
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading