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
32 changes: 32 additions & 0 deletions compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2090,4 +2090,36 @@ mod test {
ssa.interpret(vec![Value::from_constant(1_u32.into(), NumericType::unsigned(32)).unwrap()])
.unwrap();
}

#[test]
fn do_not_deduplicate_call_with_array_set_brillig() {
let src = "
brillig(inline) fn main f0 {
b0(v0: u32):
v2 = make_array [Field 1, Field 2] : [Field; 2]
call f1(v2, Field 9)
v7 = array_set v2, index v0, value Field 7
call f1(v2, Field 9)
v9 = array_get v2, index v0 -> Field
constrain v9 == Field 9
return
}
brillig(inline) fn mutator f1 {
b0(v0: [Field; 2], v1: Field):
v3 = array_set v0, index u32 0, value v1
return
}
";
let ssa = Ssa::from_str(src).unwrap();
ssa.interpret(vec![Value::from_constant(0_u32.into(), NumericType::unsigned(32)).unwrap()])
.unwrap();

let ssa = ssa.purity_analysis();
ssa.interpret(vec![Value::from_constant(0_u32.into(), NumericType::unsigned(32)).unwrap()])
.unwrap();

let ssa = ssa.fold_constants_using_constraints();
ssa.interpret(vec![Value::from_constant(0_u32.into(), NumericType::unsigned(32)).unwrap()])
.unwrap();
}
}
68 changes: 64 additions & 4 deletions compiler/noirc_evaluator/src/ssa/opt/pure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,18 @@ impl Function {
// For both cases we can still treat them as pure if the arguments are known
// constants.
ins @ (Instruction::Binary(_)
| Instruction::ArrayGet { .. }
| Instruction::ArraySet { .. }) => {
| Instruction::ArrayGet { .. }) => {
if ins.requires_acir_gen_predicate(&self.dfg) {
result = Purity::PureWithPredicate;
}
}
ins @ Instruction::ArraySet { array, .. } => {
if self.runtime().is_brillig() && (self.parameters().contains(array) || self.dfg.is_global(*array)) {
return Purity::Impure;
} else if ins.requires_acir_gen_predicate(&self.dfg) {
result = Purity::PureWithPredicate;
}
}
Instruction::Call { func, .. } => {
match &self.dfg[*func] {
Value::Function(_) => {
Expand Down Expand Up @@ -198,8 +204,12 @@ impl Function {
| Instruction::MakeArray { .. }
| Instruction::Noop => (),

Instruction::IncrementRc { .. }
| Instruction::DecrementRc { .. } => return Purity::Impure,
Instruction::IncrementRc { value }
| Instruction::DecrementRc { value } => {
if self.parameters().contains(value) || self.dfg.is_global(*value) {
return Purity::Impure
}
}
};
}

Expand Down Expand Up @@ -529,6 +539,56 @@ mod test {
assert_eq!(purities[&FunctionId::test_new(1)], Purity::Impure);
}

#[test]
fn brillig_array_set_is_impure() {
let src = r#"
brillig(inline) fn mutator f0 {
b0(v0: [Field; 2]):
inc_rc v0
v3 = array_set v0, index u32 0, value Field 5
return v3
}
// We wouldn't produce this code. This is to ensure `array_set` on a function parameter is marked impure.
brillig(inline) fn mutator f1 {
b0(v0: [Field; 2]):
v3 = array_set v0, index u32 0, value Field 5
return v3
}
"#;

let ssa = Ssa::from_str(src).unwrap();
let ssa = ssa.purity_analysis();

let purities = &ssa.main().dfg.function_purities;
assert_eq!(purities[&FunctionId::test_new(0)], Purity::Impure);
assert_eq!(purities[&FunctionId::test_new(1)], Purity::Impure);
}

#[test]
fn brillig_array_set_on_local_array_pure() {
let src = r#"
brillig(inline) fn mutator f0 {
b0(v0: [Field; 2]):
v3 = array_set v0, index u32 0, value Field 5
return v3
}
brillig(inline) fn mutator f1 {
b0():
v2 = make_array [Field 1, Field 2] : [Field; 2]
v5 = array_set v2, index u32 0, value Field 5
return v5
}
"#;

let ssa = Ssa::from_str(src).unwrap();
let ssa = ssa.purity_analysis();

let purities = &ssa.main().dfg.function_purities;
assert_eq!(purities[&FunctionId::test_new(0)], Purity::Impure);
// Brillig functions have a starting purity of PureWithPredicate
assert_eq!(purities[&FunctionId::test_new(1)], Purity::PureWithPredicate);
}

#[test]
fn direct_brillig_recursion_marks_functions_pure_with_predicate() {
let src = r#"
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Loading