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
28 changes: 26 additions & 2 deletions compiler/noirc_evaluator/src/acir/call/intrinsics/slice_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,15 +317,39 @@ impl Context<'_> {
let result_block_id = self.block_id(result_ids[1]);
self.initialize_array(result_block_id, slice_size, None)?;
let mut current_insert_index = 0;

// This caches each `is_after_insert` var for each index for an optimization that is
// explained below, above `is_after_insert`.
let mut cached_is_after_inserts = Vec::with_capacity(slice_size);

for i in 0..slice_size {
let current_index = self.acir_context.add_constant(i);

// Check that we are above the lower bound of the insertion index
let is_after_insert =
self.acir_context.more_than_eq_var(current_index, flat_user_index, 64)?;
cached_is_after_inserts.push(is_after_insert);

// Check that we are below the upper bound of the insertion index
let is_before_insert =
self.acir_context.less_than_var(current_index, max_flat_user_index, 64)?;
let is_before_insert = if i >= inner_elem_size_usize {
// Optimization: we first note that `max_flat_user_index = flat_user_index + inner_elem_size`.
// Then we note that at each index we do these comparisons:
// - is_after_insert: `i >= flat_user_index`
// - is_before_insert: `i < (flat_user_index + inner_elem_size)`
//
// As `i` is incremented, for example to `i + n`, we get:
// - is_before_insert: `i + n < (flat_user_index + inner_elem_size)`
// If `n == inner_elem_size` then we have:
// - is_before_insert: `i + n < (flat_user_index + n)` which is equivalent to:
// - is_before_insert: `i < flat_user_index`
// Then we note that this is the opposite of `i >= flat_user_index`.
// So once `i >= inner_elem_size` we can use the previously made comparisons, negated,
// instead of performing them again (for dynamic indexes they incur a brillig call).
let cached_is_after_insert = cached_is_after_inserts[i - inner_elem_size_usize];
self.acir_context.sub_var(one, cached_is_after_insert)?
} else {
self.acir_context.less_than_var(current_index, max_flat_user_index, 64)?
};

// Read from the original slice the value we want to insert into our new slice.
// We need to make sure that we read the previous element when our current index is greater than insertion index.
Expand Down
66 changes: 27 additions & 39 deletions compiler/noirc_evaluator/src/acir/tests/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ fn slice_pop_front() {
}

#[test]
fn slice_insert() {
fn slice_insert_no_predicate() {
let src = "
acir(inline) predicate_pure fn main f0 {
b0(v0: u32, v1: u32):
Expand Down Expand Up @@ -222,45 +222,33 @@ fn slice_insert() {
BLACKBOX::RANGE input: w14, bits: 1
BLACKBOX::RANGE input: w15, bits: 64
ASSERT w15 = -w1 - 18446744073709551616*w14 + 18446744073709551617
BRILLIG CALL func: 0, inputs: [-w1 + 18446744073709551616, 18446744073709551616], outputs: [w16, w17]
BLACKBOX::RANGE input: w16, bits: 1
BLACKBOX::RANGE input: w17, bits: 64
ASSERT w17 = -w1 - 18446744073709551616*w16 + 18446744073709551616
ASSERT w18 = -w14 + 1
READ w19 = b1[w18]
ASSERT w20 = w14*w16 - w14 + 1
ASSERT w21 = 1
ASSERT w22 = -10*w14*w16 + w19*w20 + 10*w14
WRITE b2[w21] = w22
BRILLIG CALL func: 0, inputs: [-w1 + 18446744073709551618, 18446744073709551616], outputs: [w23, w24]
BLACKBOX::RANGE input: w23, bits: 1
BLACKBOX::RANGE input: w24, bits: 64
ASSERT w24 = -w1 - 18446744073709551616*w23 + 18446744073709551618
BRILLIG CALL func: 0, inputs: [-w1 + 18446744073709551617, 18446744073709551616], outputs: [w25, w26]
BLACKBOX::RANGE input: w25, bits: 1
BLACKBOX::RANGE input: w26, bits: 64
ASSERT w26 = -w1 - 18446744073709551616*w25 + 18446744073709551617
ASSERT w27 = -w23 + 2
READ w28 = b1[w27]
ASSERT w29 = w23*w25 - w23 + 1
ASSERT w30 = -10*w23*w25 + w28*w29 + 10*w23
WRITE b2[w2] = w30
BRILLIG CALL func: 0, inputs: [-w1 + 18446744073709551619, 18446744073709551616], outputs: [w31, w32]
BLACKBOX::RANGE input: w31, bits: 1
BLACKBOX::RANGE input: w32, bits: 64
ASSERT w32 = -w1 - 18446744073709551616*w31 + 18446744073709551619
BRILLIG CALL func: 0, inputs: [-w1 + 18446744073709551618, 18446744073709551616], outputs: [w33, w34]
BLACKBOX::RANGE input: w33, bits: 1
BLACKBOX::RANGE input: w34, bits: 64
ASSERT w34 = -w1 - 18446744073709551616*w33 + 18446744073709551618
ASSERT w35 = -w31 + 3
READ w36 = b1[w35]
ASSERT w37 = w31*w33 - w31 + 1
ASSERT w38 = -10*w31*w33 + w36*w37 + 10*w31
WRITE b2[w3] = w38
ASSERT w16 = -w14 + 1
READ w17 = b1[w16]
ASSERT w18 = w7*w14 - w14 + 1
ASSERT w19 = 1
ASSERT w20 = -10*w7*w14 + w17*w18 + 10*w14
WRITE b2[w19] = w20
BRILLIG CALL func: 0, inputs: [-w1 + 18446744073709551618, 18446744073709551616], outputs: [w21, w22]
BLACKBOX::RANGE input: w21, bits: 1
BLACKBOX::RANGE input: w22, bits: 64
ASSERT w22 = -w1 - 18446744073709551616*w21 + 18446744073709551618
ASSERT w23 = -w21 + 2
READ w24 = b1[w23]
ASSERT w25 = w14*w21 - w21 + 1
ASSERT w26 = -10*w14*w21 + w24*w25 + 10*w21
WRITE b2[w2] = w26
BRILLIG CALL func: 0, inputs: [-w1 + 18446744073709551619, 18446744073709551616], outputs: [w27, w28]
BLACKBOX::RANGE input: w27, bits: 1
BLACKBOX::RANGE input: w28, bits: 64
ASSERT w28 = -w1 - 18446744073709551616*w27 + 18446744073709551619
ASSERT w29 = -w27 + 3
READ w30 = b1[w29]
ASSERT w31 = w21*w27 - w27 + 1
ASSERT w32 = -10*w21*w27 + w30*w31 + 10*w27
WRITE b2[w3] = w32
ASSERT w1 = 4
ASSERT w39 = 20
WRITE b2[w0] = w39
ASSERT w33 = 20
WRITE b2[w0] = w33

unconstrained func 0: directive_integer_quotient
0: @10 = const u32 2
Expand Down
Loading