Skip to content

inc_rc instructions should not be considered impure in brillig entrypoint functions #11405

@TomAFrench

Description

@TomAFrench

This particular case is caused by #11403 but the knock-on effects are different enough that I think it warrants a separate issue.

Consider the program below.

fn main(b: Field) {
    unsafe {
        assert_eq(func_4(([0, 0], b)), func_4(([0, 0], b)));
    }
}

unconstrained fn func_4(b: ([Field; 2], Field)) -> Field {
    let (_, _) = b;
    b.1
}

This compiles to the SSA

acir(inline) impure fn main f0 {
  b0(v0: Field):
    v2 = make_array [Field 0, Field 0] : [Field; 2]
    v4 = call f1(v2, v0) -> Field
    v5 = call f1(v2, v0) -> Field
    constrain v4 == v5
    return
}
brillig(inline) impure fn func_4 f1 {
  b0(v0: [Field; 2], v1: Field):
    inc_rc v0
    inc_rc v0
    return v1
}

func_4 is listed as impure here because it contains inc_rc instructions and so mutates the reference counter for the array v0. This is expected in the case where func_4 is potentially called by other brillig functions as the inc_rc instructions will affect the arrays constructed by those other functions.

However in this case func_4 set up these arrays itself and therefore "owns" them. Therefore func_4 is in fact pure. Despite this however we don't end up deduplicating the two calls to func_4 from main because we always consider a function which contains an inc_rc instruction to be impure.

We should modify our concept of purity so that if a function is incrementing a reference counter to a array which is has created (i.e. make_array instruction or received from an ACIR function) then this is still considered pure.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions