Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inlining pass produces invalid SSA(SSA Refactor) #1758

Closed
sirasistant opened this issue Jun 20, 2023 · 2 comments
Closed

Inlining pass produces invalid SSA(SSA Refactor) #1758

sirasistant opened this issue Jun 20, 2023 · 2 comments
Assignees
Labels
bug Something isn't working refactor ssa

Comments

@sirasistant
Copy link
Contributor

sirasistant commented Jun 20, 2023

Aim

Creating a struct that has a serialize function and a hash function, and the hash function uses the result of serialization to hash.

Expected Behavior

The following should not panic on test:

struct BoundedVec<T, MaxLen> {
    storage: [T; MaxLen],
    len: comptime Field,
}

impl<T, MaxLen> BoundedVec<T, MaxLen> {
    fn new(initial_value: T) -> Self {
        BoundedVec { storage: [initial_value; MaxLen], len: 0 }
    }

    fn get(mut self: Self, index: comptime Field) -> T {
        assert(index as u64 < self.len as u64);
        self.storage[index]
    }

    fn push(mut self: Self, elem: T) -> Self {
        assert(self.len as u64 < MaxLen as u64);

        self.storage[self.len] = elem;
        self.len += 1;
        self
    }

    fn push_array<Len>(mut self: Self, array: [T; Len]) -> Self {
        let newLen = self.len + array.len();
        assert(newLen as u64 <= MaxLen as u64);
        for i in 0..array.len() {
            self.storage[self.len + i] = array[i];
        }
        self.len = newLen;
        self
    }

    fn pop(mut self: Self) -> (Self, T) {
        assert(self.len as u64 > 0);

        let elem = self.storage[self.len - 1];
        self.len -= 1;
        (self, elem)
    }
}

#[test]
fn test_vec() {
    let vec: BoundedVec<Field, 3> = BoundedVec::new(0);
    assert(vec.len == 0);
    let vec1 = vec.push(1);
    assert(vec1.len == 1);
    let vec2 = vec1.push(1);
    assert(vec2.len == 2);
    let vec3 = vec2.push(1);
    assert(vec3.len == 3);
    let (_newVec, x) = vec3.pop();
    assert(x == 1);
}

global FOO_LENGTH = 4;

struct Foo {
    return_values: [Field; 2],
    foo: Field,
    bar: Field,
}

impl Foo {
    fn hash(self) -> Field {
        let serialized = self.serialize();
        dep::std::hash::pedersen_with_separator(serialized, 27)[0]
    }

    fn serialize(self) -> [Field; FOO_LENGTH] {
        let mut fields: BoundedVec<Field, FOO_LENGTH> = BoundedVec::new(0); 
        fields = fields.push_array(self.return_values);
        fields = fields.push(self.foo);
        fields = fields.push(self.bar);
        fields.storage
    }
}

#[test]
fn test_foo() {
    let foo = Foo {
        return_values: [0; 2],
        foo: 0,
        bar: 0,
    };
    assert(foo.hash() == 0);
}


fn main(x : Field, y : pub Field) {
    assert(x != y);
}

Bug

test_foo panics on runtime:

The application panicked (crashed).
Message:  internal error: entered unreachable code: ICE: Should have been in cache v75 Instruction { instruction: Id(91), position: 0, typ: Array([Numeric(NativeField)], 10) }
Location: crates/noirc_evaluator/src/ssa_refactor/acir_gen/mod.rs:364

SSA seems to break after inlining:

Initial SSA:
fn test_foo f0 {
  b0():
    v3 = call f1([Field 0, Field 0], Field 0, Field 0)
    v4 = eq v3, Field 0
    constrain v4
    return 
}
fn hash f1 {
  b0(v0: [Field; 2], v1: Field, v2: Field):
    v4 = call f2(v0, v1, v2)
    v7 = call pedersen(v4, u32 27)
    v10 = array_get v7, index Field 0
    return v10
}
fn serialize f2 {
  b0(v0: [Field; 2], v1: Field, v2: Field):
    v5, v6 = call f3(Field 0)
    v7 = allocate
    store v5 at v7
    v8 = allocate
    store v6 at v8
    v9 = load v7
    v10 = load v8
    v12, v13 = call f4(v9, v10, v0)
    store v12 at v7
    store v13 at v8
    v14 = load v7
    v15 = load v8
    v17, v18 = call f5(v14, v15, v1)
    store v17 at v7
    store v18 at v8
    v19 = load v7
    v20 = load v8
    v22, v23 = call f5(v19, v20, v2)
    store v22 at v7
    store v23 at v8
    v24 = load v7
    v25 = load v8
    return v24
}
fn new f3 {
  b0(v0: Field):
    return [v0, v0, v0, v0], Field 0
}
fn push_array f4 {
  b0(v0: [Field; 4], v2: Field, v4: [Field; 2]):
    v1 = allocate
    store v0 at v1
    v3 = allocate
    store v2 at v3
    v5 = load v1
    v6 = load v3
    v8 = add v6, Field 2
    v9 = cast v8 as u64
    v12 = lt u64 4, v9
    v13 = not v12
    constrain v13
    jmp b1(Field 0)
  b1(v14: Field):
    v16 = lt v14, Field 2
    jmpif v16 then: b2, else: b3
  b2():
    v17 = load v1
    v18 = load v1
    v19 = load v3
    v20 = add v19, v14
    v22 = array_get v4, index v14
    v23 = array_set v17, index v20, value v22
    store v23 at v1
    v24 = load v3
    store v24 at v3
    v25 = add v14, Field 1
    jmp b1(v25)
  b3():
    v26 = load v1
    store v26 at v1
    store v8 at v3
    v27 = load v1
    v28 = load v3
    return v27, v28
}
fn push f5 {
  b0(v0: [Field; 4], v2: Field, v4: Field):
    v1 = allocate
    store v0 at v1
    v3 = allocate
    store v2 at v3
    v5 = load v1
    v6 = load v3
    v7 = cast v6 as u64
    v10 = lt v7, u64 4
    constrain v10
    v11 = load v1
    v12 = load v1
    v13 = load v3
    v14 = array_set v11, index v13, value v4
    store v14 at v1
    v15 = load v3
    store v15 at v3
    v16 = load v1
    v17 = load v3
    v19 = add v17, Field 1
    v20 = load v1
    store v20 at v1
    store v19 at v3
    v21 = load v1
    v22 = load v3
    return v21, v22
}

After Inlining:
fn test_foo f6 {
  b0():
    v6 = allocate
    store [Field 0, Field 0, Field 0, Field 0] at v6
    v7 = allocate
    store Field 0 at v7
    v8 = load v6
    v9 = load v7
    v11 = allocate
    store v8 at v11
    v12 = allocate
    store v9 at v12
    v13 = load v11
    v14 = load v12
    v16 = add v14, Field 2
    v17 = cast v16 as u64
    v19 = lt u64 4, v17
    v20 = not v19
    constrain v20
    v79 = call pedersen(v75, u32 27)
    v80 = array_get v79, index Field 0
    v81 = eq v80, Field 0
    constrain v81
    return 
}

To Reproduce

Installation Method

None

Nargo Version

No response

Additional Context

No response

Would you like to submit a PR for this Issue?

No

Support Needs

No response

@sirasistant sirasistant added the bug Something isn't working label Jun 20, 2023
@github-project-automation github-project-automation bot moved this to 📋 Backlog in Noir Jun 20, 2023
@sirasistant sirasistant changed the title Inlining pass produces invalid SSA (SSA Refactor Inlining pass produces invalid SSA(SSA Refactor) Jun 20, 2023
@joss-aztec
Copy link
Contributor

I believe this is fixed by #1747

@sirasistant
Copy link
Contributor Author

Closing after verifying that #1747 did indeed fix the issue!

@github-project-automation github-project-automation bot moved this from 📋 Backlog to ✅ Done in Noir Jun 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working refactor ssa
Projects
Archived in project
Development

No branches or pull requests

4 participants