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
19 changes: 14 additions & 5 deletions compiler/noirc_evaluator/src/ssa/ir/dfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,12 +232,21 @@ impl DataFlowGraph {
}

fn validate_instruction(&self, instruction: &Instruction) {
if let Instruction::Binary(Binary { lhs, rhs: _, operator: BinaryOp::Lt }) = instruction {
// Assume rhs_type is the same as lhs_type
let lhs_type = self.type_of_value(*lhs);
if matches!(lhs_type, Type::Numeric(NumericType::NativeField)) {
panic!("Cannot use `lt` with field elements");
match instruction {
Instruction::Binary(Binary { lhs, rhs: _, operator: BinaryOp::Lt }) => {
// Assume rhs_type is the same as lhs_type
let lhs_type = self.type_of_value(*lhs);
if matches!(lhs_type, Type::Numeric(NumericType::NativeField)) {
panic!("Cannot use `lt` with field elements");
}
}
Instruction::ArrayGet { index, .. } | Instruction::ArraySet { index, .. } => {
let index_type = self.type_of_value(*index);
if !matches!(index_type, Type::Numeric(NumericType::Unsigned { bit_size: 32 })) {
panic!("ArrayGet/ArraySet index must be u32");
}
}
_ => (),
}
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_evaluator/src/ssa/opt/array_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
impl Function {
pub(crate) fn array_set_optimization(&mut self) {
if matches!(self.runtime(), RuntimeType::Brillig(_)) {
// Brillig is supposed to use refcounting to decide whether to mutate an array;

Check warning on line 32 in compiler/noirc_evaluator/src/ssa/opt/array_set.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (refcounting)
// array mutation was only meant for ACIR. We could use it with Brillig as well,
// but then some of the optimizations that we can do in ACIR around shared
// references have to be skipped, which makes it more cumbersome.
Expand Down Expand Up @@ -201,7 +201,7 @@
jmp b5()
b5():
v11 = load v4 -> [[Field; 5]; 2]
v12 = array_get v11, index Field 0 -> [Field; 5]
v12 = array_get v11, index u32 0 -> [Field; 5]
v14 = array_set v12, index v0, value Field 20
v15 = array_set v11, index v0, value v14
store v15 at v4
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1188,7 +1188,7 @@ mod test {
// is disabled (only gets from index 0) and thus returns the wrong result.
let src = "
acir(inline) fn main f0 {
b0(v0: u1, v1: u64):
b0(v0: u1, v1: u32):
enable_side_effects v0
v4 = make_array [Field 0, Field 1] : [Field; 2]
v5 = array_get v4, index v1 -> Field
Expand Down
36 changes: 18 additions & 18 deletions compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1430,7 +1430,7 @@ mod test {
let src = "
acir(inline) fn main f0 {
b0(v0: [u8; 2]):
v2 = array_get v0, index u8 0 -> u8
v2 = array_get v0, index u32 0 -> u8
v3 = cast v2 as u32
v4 = truncate v3 to 1 bits, max_bit_size: 32
v5 = cast v4 as u1
Expand Down Expand Up @@ -1474,30 +1474,30 @@ mod test {
assert_ssa_snapshot!(flattened_ssa, @r"
acir(inline) fn main f0 {
b0(v0: [u8; 2]):
v2 = array_get v0, index u8 0 -> u8
v2 = array_get v0, index u32 0 -> u8
v3 = cast v2 as u32
v4 = truncate v3 to 1 bits, max_bit_size: 32
v5 = cast v4 as u1
v6 = allocate -> &mut Field
store u8 0 at v6
enable_side_effects v5
v7 = cast v2 as Field
v9 = add v7, Field 1
v10 = cast v9 as u8
v11 = load v6 -> u8
v12 = not v5
v13 = cast v4 as u8
v14 = cast v12 as u8
v15 = unchecked_mul v13, v10
v8 = cast v2 as Field
v10 = add v8, Field 1
v11 = cast v10 as u8
v12 = load v6 -> u8
v13 = not v5
v14 = cast v4 as u8
v15 = cast v13 as u8
v16 = unchecked_mul v14, v11
v17 = unchecked_add v15, v16
store v17 at v6
enable_side_effects v12
v18 = load v6 -> u8
v19 = cast v12 as u8
v20 = cast v4 as u8
v21 = unchecked_mul v20, v18
store v21 at v6
v17 = unchecked_mul v15, v12
v18 = unchecked_add v16, v17
store v18 at v6
enable_side_effects v13
v19 = load v6 -> u8
v20 = cast v13 as u8
v21 = cast v4 as u8
v22 = unchecked_mul v21, v19
store v22 at v6
enable_side_effects u1 1
constrain v5 == u1 1
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ impl<'a> ValueMerger<'a> {
for (element_index, element_type) in element_types.iter().enumerate() {
let index_u32 = i * element_types.len() as u32 + element_index as u32;
let index_value = (index_u32 as u128).into();
let index = self.dfg.make_constant(index_value, NumericType::NativeField);
let index = self.dfg.make_constant(index_value, NumericType::length_type());

let typevars = Some(vec![element_type.clone()]);

Expand Down
6 changes: 3 additions & 3 deletions compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
//!
//! Repeating this algorithm for each block in the function in program order should result in
//! optimizing out most known loads. However, identifying all aliases correctly has been proven
//! undecidable in general (Landi, 1992). So this pass will not always optimize out all loads

Check warning on line 71 in compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (Landi)
//! that could theoretically be optimized out. This pass can be performed at any time in the
//! SSA optimization pipeline, although it will be more successful the simpler the program's CFG is.
//! This pass is currently performed several times to enable other passes - most notably being
Expand Down Expand Up @@ -683,7 +683,7 @@
ArrayOffset, BinaryOp, Instruction, Intrinsic, TerminatorInstruction,
},
map::Id,
types::Type,
types::{NumericType, Type},
},
opt::assert_normalized_ssa_equals,
},
Expand All @@ -697,14 +697,14 @@
// v1 = make_array [Field 1, Field 2]
// store v1 in v0
// v2 = load v0
// v3 = array_get v2, index 1
// v3 = array_get v2, index u32 1
// return v3
// }

let func_id = Id::test_new(0);
let mut builder = FunctionBuilder::new("func".into(), func_id);
let v0 = builder.insert_allocate(Type::Array(Arc::new(vec![Type::field()]), 2));
let one = builder.field_constant(FieldElement::one());
let one = builder.numeric_constant(FieldElement::one(), NumericType::length_type());
let two = builder.field_constant(FieldElement::one());

let element_type = Arc::new(vec![Type::field()]);
Expand Down
4 changes: 2 additions & 2 deletions compiler/noirc_evaluator/src/ssa/opt/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ mod test {
store v0 at v1
inc_rc v0
v2 = load v1 -> [Field; 2]
v5 = array_set v2, index u64 0, value Field 5
v5 = array_set v2, index u32 0, value Field 5
store v5 at v1
dec_rc v0
return
Expand Down Expand Up @@ -247,7 +247,7 @@ mod test {
inc_rc v1
store v1 at v0
v2 = load v1 -> [Field; 2]
v5 = array_set v2, index u64 0, value Field 5
v5 = array_set v2, index u32 0, value Field 5
store v5 at v0
v6 = load v0 -> [Field; 2]
dec_rc v1
Expand Down
81 changes: 42 additions & 39 deletions compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,10 @@ impl Context<'_, '_, '_> {
let mut r = one;
// All operations are unchecked as we're acting on Field types (which are always unchecked)
for i in 1..bit_size + 1 {
let idx = self.field_constant(FieldElement::from((bit_size - i) as i128));
let idx = self.numeric_constant(
FieldElement::from((bit_size - i) as i128),
NumericType::length_type(),
);
let b = self.insert_array_get(rhs_bits, idx, Type::bool());
let not_b = self.insert_not(b);
let b = self.insert_cast(b, NumericType::NativeField);
Expand Down Expand Up @@ -428,13 +431,13 @@ mod tests {
v4 = cast v3 as u32
v5 = cast v1 as Field
v7 = call to_le_bits(v5) -> [u1; 8]
v9 = array_get v7, index Field 7 -> u1
v9 = array_get v7, index u32 7 -> u1
v10 = not v9
v11 = cast v9 as Field
v12 = cast v10 as Field
v14 = mul Field 2, v11
v15 = add v12, v14
v17 = array_get v7, index Field 6 -> u1
v17 = array_get v7, index u32 6 -> u1
v18 = not v17
v19 = cast v17 as Field
v20 = cast v18 as Field
Expand All @@ -443,7 +446,7 @@ mod tests {
v23 = mul v21, Field 2
v24 = mul v23, v19
v25 = add v22, v24
v27 = array_get v7, index Field 5 -> u1
v27 = array_get v7, index u32 5 -> u1
v28 = not v27
v29 = cast v27 as Field
v30 = cast v28 as Field
Expand All @@ -452,7 +455,7 @@ mod tests {
v33 = mul v31, Field 2
v34 = mul v33, v29
v35 = add v32, v34
v37 = array_get v7, index Field 4 -> u1
v37 = array_get v7, index u32 4 -> u1
v38 = not v37
v39 = cast v37 as Field
v40 = cast v38 as Field
Expand All @@ -461,7 +464,7 @@ mod tests {
v43 = mul v41, Field 2
v44 = mul v43, v39
v45 = add v42, v44
v47 = array_get v7, index Field 3 -> u1
v47 = array_get v7, index u32 3 -> u1
v48 = not v47
v49 = cast v47 as Field
v50 = cast v48 as Field
Expand All @@ -470,42 +473,42 @@ mod tests {
v53 = mul v51, Field 2
v54 = mul v53, v49
v55 = add v52, v54
v56 = array_get v7, index Field 2 -> u1
v57 = not v56
v58 = cast v56 as Field
v57 = array_get v7, index u32 2 -> u1
v58 = not v57
v59 = cast v57 as Field
v60 = mul v55, v55
v61 = mul v60, v59
v62 = mul v60, Field 2
v63 = mul v62, v58
v64 = add v61, v63
v66 = array_get v7, index Field 1 -> u1
v67 = not v66
v68 = cast v66 as Field
v60 = cast v58 as Field
v61 = mul v55, v55
v62 = mul v61, v60
v63 = mul v61, Field 2
v64 = mul v63, v59
v65 = add v62, v64
v67 = array_get v7, index u32 1 -> u1
v68 = not v67
v69 = cast v67 as Field
v70 = mul v64, v64
v71 = mul v70, v69
v72 = mul v70, Field 2
v73 = mul v72, v68
v74 = add v71, v73
v76 = array_get v7, index Field 0 -> u1
v77 = not v76
v78 = cast v76 as Field
v70 = cast v68 as Field
v71 = mul v65, v65
v72 = mul v71, v70
v73 = mul v71, Field 2
v74 = mul v73, v69
v75 = add v72, v74
v77 = array_get v7, index u32 0 -> u1
v78 = not v77
v79 = cast v77 as Field
v80 = mul v74, v74
v81 = mul v80, v79
v82 = mul v80, Field 2
v83 = mul v82, v78
v84 = add v81, v83
v85 = cast v84 as u32
v86 = unchecked_mul v4, v85
v87 = cast v0 as Field
v88 = cast v86 as Field
v89 = mul v87, v88
v90 = truncate v89 to 32 bits, max_bit_size: 254
v91 = cast v90 as u32
v92 = truncate v91 to 32 bits, max_bit_size: 33
return v91
v80 = cast v78 as Field
v81 = mul v75, v75
v82 = mul v81, v80
v83 = mul v81, Field 2
v84 = mul v83, v79
v85 = add v82, v84
v86 = cast v85 as u32
v87 = unchecked_mul v4, v86
v88 = cast v0 as Field
v89 = cast v87 as Field
v90 = mul v88, v89
v91 = truncate v90 to 32 bits, max_bit_size: 254
v92 = cast v91 as u32
v93 = truncate v92 to 32 bits, max_bit_size: 33
return v92
}
");
}
Expand Down
28 changes: 12 additions & 16 deletions compiler/noirc_evaluator/src/ssa/opt/unrolling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1060,7 +1060,7 @@
use super::{BoilerplateStats, Loops, is_new_size_ok};

/// Tries to unroll all loops in each SSA function once, calling the `Function` directly,
/// bypassing the iterative loop done by the SSA which does further optimisations.

Check warning on line 1063 in compiler/noirc_evaluator/src/ssa/opt/unrolling.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (optimisations)
///
/// If any loop cannot be unrolled, it is left as-is or in a partially unrolled state.
fn try_unroll_loops(mut ssa: Ssa) -> (Ssa, Vec<RuntimeError>) {
Expand Down Expand Up @@ -1243,15 +1243,15 @@

#[test]
fn test_boilerplate_stats_6470() {
let ssa = brillig_unroll_test_case_6470(3);
let ssa = brillig_unroll_test_case_6470(2);
let stats = loop0_stats(&ssa);
assert_eq!(stats.iterations, 3);
assert_eq!(stats.all_instructions, 2 + 8); // Instructions in b1 and b3
assert_eq!(stats.iterations, 2);
assert_eq!(stats.all_instructions, 2 + 9); // Instructions in b1 and b3
assert_eq!(stats.increments, 2);
assert_eq!(stats.loads, 1);
assert_eq!(stats.stores, 1);
assert_eq!(stats.useful_instructions(), 3); // array get, add, array set
assert_eq!(stats.baseline_instructions(), 11);
assert_eq!(stats.useful_instructions(), 4); // cast, array get, add, array set
assert_eq!(stats.baseline_instructions(), 12);
assert!(stats.is_small());
}

Expand Down Expand Up @@ -1296,7 +1296,7 @@
#[test]
fn test_brillig_unroll_6470_small() {
// Few enough iterations so that we can perform the unroll.
let ssa = brillig_unroll_test_case_6470(3);
let ssa = brillig_unroll_test_case_6470(2);
let (ssa, errors) = try_unroll_loops(ssa);
assert_eq!(errors.len(), 0, "Unroll should have no errors");
assert_eq!(ssa.main().reachable_blocks().len(), 2, "The loop should be unrolled");
Expand All @@ -1319,16 +1319,11 @@
v13 = add v12, u64 1
v14 = array_set v10, index u32 1, value v13
store v14 at v3
v15 = load v3 -> [u64; 6]
v17 = array_get v0, index u32 2 -> u64
v18 = add v17, u64 1
v19 = array_set v15, index u32 2, value v18
store v19 at v3
jmp b1()
b1():
v20 = load v3 -> [u64; 6]
v15 = load v3 -> [u64; 6]
dec_rc v0
return v20
return v15
}
");
}
Expand Down Expand Up @@ -1503,9 +1498,10 @@
jmpif v7 then: b3, else: b2
b3():
v9 = load v4 -> [u64; 6]
v10 = array_get v0, index v1 -> u64
v12 = add v10, u64 1
v13 = array_set v9, index v1, value v12
v10 = cast v1 as u32
v11 = array_get v0, index v10 -> u64
v12 = add v11, u64 1
v13 = array_set v9, index v10, value v12
v15 = add v1, {idx_type} 1
store v13 at v4
v16 = add v1, {idx_type} 1 // duplicate
Expand Down
Loading
Loading