Skip to main content
Version: dev

Reading SSA IR

info

These docs are written primarily for those working on the Noir compiler. As Noir is open source project we have made these public so others may benefit but note that we assume

These docs may be incomplete or out of date relative to the current release of the Noir compiler.

Printing the SSA

As an example program, we're going to be using array_if_cond_simple which exists as part of the Noir test suite here.

fn main(x: bool, mut y: [u32; 30]) {
if x {
y[0] = 1;
}

let z = y[0] + y[1];
assert(z == 1);
}

This is a nice example as this program has some control flow which needs to be flattened. The state of the program's SSA after each optimization pass can be printed by using the CLI flag nargo compile --show-ssa. The output generated by compiling with this flag is shown below:

Full SSA output
After Initial SSA:
acir(inline) fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
store v1 at v2
jmpif v0 then: b1, else: b2
b1():
v3 = load v2 -> [u32; 30]
v6 = array_set v3, index u32 0, value u32 1
store v6 at v2
jmp b2()
b2():
v7 = load v2 -> [u32; 30]
v8 = array_get v7, index u32 0 -> u32
v9 = load v2 -> [u32; 30]
v10 = array_get v9, index u32 1 -> u32
v11 = add v8, v10
v12 = eq v11, u32 1
constrain v11 == u32 1
return
}

After Removing Unreachable Functions (1st):
acir(inline) fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
store v1 at v2
jmpif v0 then: b1, else: b2
b1():
v3 = load v2 -> [u32; 30]
v6 = array_set v3, index u32 0, value u32 1
store v6 at v2
jmp b2()
b2():
v7 = load v2 -> [u32; 30]
v8 = array_get v7, index u32 0 -> u32
v9 = load v2 -> [u32; 30]
v10 = array_get v9, index u32 1 -> u32
v11 = add v8, v10
v12 = eq v11, u32 1
constrain v11 == u32 1
return
}

After Defunctionalization:
acir(inline) fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
store v1 at v2
jmpif v0 then: b1, else: b2
b1():
v3 = load v2 -> [u32; 30]
v6 = array_set v3, index u32 0, value u32 1
store v6 at v2
jmp b2()
b2():
v7 = load v2 -> [u32; 30]
v8 = array_get v7, index u32 0 -> u32
v9 = load v2 -> [u32; 30]
v10 = array_get v9, index u32 1 -> u32
v11 = add v8, v10
v12 = eq v11, u32 1
constrain v11 == u32 1
return
}

After Inlining simple functions:
acir(inline) fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
store v1 at v2
jmpif v0 then: b1, else: b2
b1():
v3 = load v2 -> [u32; 30]
v6 = array_set v3, index u32 0, value u32 1
store v6 at v2
jmp b2()
b2():
v7 = load v2 -> [u32; 30]
v8 = array_get v7, index u32 0 -> u32
v9 = load v2 -> [u32; 30]
v10 = array_get v9, index u32 1 -> u32
v11 = add v8, v10
v12 = eq v11, u32 1
constrain v11 == u32 1
return
}

After Removing Paired rc_inc & rc_decs:
acir(inline) fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
store v1 at v2
jmpif v0 then: b1, else: b2
b1():
v3 = load v2 -> [u32; 30]
v6 = array_set v3, index u32 0, value u32 1
store v6 at v2
jmp b2()
b2():
v7 = load v2 -> [u32; 30]
v8 = array_get v7, index u32 0 -> u32
v9 = load v2 -> [u32; 30]
v10 = array_get v9, index u32 1 -> u32
v11 = add v8, v10
v12 = eq v11, u32 1
constrain v11 == u32 1
return
}

After Preprocessing Functions:
acir(inline) fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
store v1 at v2
jmpif v0 then: b1, else: b2
b1():
v3 = load v2 -> [u32; 30]
v6 = array_set v3, index u32 0, value u32 1
store v6 at v2
jmp b2()
b2():
v7 = load v2 -> [u32; 30]
v8 = array_get v7, index u32 0 -> u32
v9 = load v2 -> [u32; 30]
v10 = array_get v9, index u32 1 -> u32
v11 = add v8, v10
v12 = eq v11, u32 1
constrain v11 == u32 1
return
}

After Inlining (1st):
acir(inline) fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
store v1 at v2
jmpif v0 then: b1, else: b2
b1():
v3 = load v2 -> [u32; 30]
v6 = array_set v3, index u32 0, value u32 1
store v6 at v2
jmp b2()
b2():
v7 = load v2 -> [u32; 30]
v8 = array_get v7, index u32 0 -> u32
v9 = load v2 -> [u32; 30]
v10 = array_get v9, index u32 1 -> u32
v11 = add v8, v10
v12 = eq v11, u32 1
constrain v11 == u32 1
return
}

After Mem2Reg (2nd):
acir(inline) fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
store v1 at v2
jmpif v0 then: b1, else: b2
b1():
v5 = array_set v1, index u32 0, value u32 1
store v5 at v2
jmp b2()
b2():
v6 = load v2 -> [u32; 30]
v7 = array_get v6, index u32 0 -> u32
v8 = array_get v6, index u32 1 -> u32
v9 = add v7, v8
v10 = eq v9, u32 1
constrain v9 == u32 1
return
}

After Simplifying (1st):
acir(inline) fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
store v1 at v2
jmpif v0 then: b1, else: b2
b1():
v5 = array_set v1, index u32 0, value u32 1
store v5 at v2
jmp b2()
b2():
v6 = load v2 -> [u32; 30]
v7 = array_get v6, index u32 0 -> u32
v8 = array_get v6, index u32 1 -> u32
v9 = add v7, v8
v10 = eq v9, u32 1
constrain v9 == u32 1
return
}

After `as_slice` optimization:
acir(inline) fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
store v1 at v2
jmpif v0 then: b1, else: b2
b1():
v5 = array_set v1, index u32 0, value u32 1
store v5 at v2
jmp b2()
b2():
v6 = load v2 -> [u32; 30]
v7 = array_get v6, index u32 0 -> u32
v8 = array_get v6, index u32 1 -> u32
v9 = add v7, v8
v10 = eq v9, u32 1
constrain v9 == u32 1
return
}

After Removing Unreachable Functions (2nd):
acir(inline) fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
store v1 at v2
jmpif v0 then: b1, else: b2
b1():
v5 = array_set v1, index u32 0, value u32 1
store v5 at v2
jmp b2()
b2():
v6 = load v2 -> [u32; 30]
v7 = array_get v6, index u32 0 -> u32
v8 = array_get v6, index u32 1 -> u32
v9 = add v7, v8
v10 = eq v9, u32 1
constrain v9 == u32 1
return
}

After `static_assert` and `assert_constant`:
acir(inline) fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
store v1 at v2
jmpif v0 then: b1, else: b2
b1():
v5 = array_set v1, index u32 0, value u32 1
store v5 at v2
jmp b2()
b2():
v6 = load v2 -> [u32; 30]
v7 = array_get v6, index u32 0 -> u32
v8 = array_get v6, index u32 1 -> u32
v9 = add v7, v8
v10 = eq v9, u32 1
constrain v9 == u32 1
return
}

After Purity Analysis:
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
store v1 at v2
jmpif v0 then: b1, else: b2
b1():
v5 = array_set v1, index u32 0, value u32 1
store v5 at v2
jmp b2()
b2():
v6 = load v2 -> [u32; 30]
v7 = array_get v6, index u32 0 -> u32
v8 = array_get v6, index u32 1 -> u32
v9 = add v7, v8
v10 = eq v9, u32 1
constrain v9 == u32 1
return
}

After Loop Invariant Code Motion:
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
store v1 at v2
jmpif v0 then: b1, else: b2
b1():
v5 = array_set v1, index u32 0, value u32 1
store v5 at v2
jmp b2()
b2():
v6 = load v2 -> [u32; 30]
v7 = array_get v6, index u32 0 -> u32
v8 = array_get v6, index u32 1 -> u32
v9 = add v7, v8
v10 = eq v9, u32 1
constrain v9 == u32 1
return
}

After Unrolling:
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
store v1 at v2
jmpif v0 then: b1, else: b2
b1():
v5 = array_set v1, index u32 0, value u32 1
store v5 at v2
jmp b2()
b2():
v6 = load v2 -> [u32; 30]
v7 = array_get v6, index u32 0 -> u32
v8 = array_get v6, index u32 1 -> u32
v9 = add v7, v8
v10 = eq v9, u32 1
constrain v9 == u32 1
return
}

After Simplifying (2nd):
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
store v1 at v2
jmpif v0 then: b1, else: b2
b1():
v5 = array_set v1, index u32 0, value u32 1
store v5 at v2
jmp b2()
b2():
v6 = load v2 -> [u32; 30]
v7 = array_get v6, index u32 0 -> u32
v8 = array_get v6, index u32 1 -> u32
v9 = add v7, v8
v10 = eq v9, u32 1
constrain v9 == u32 1
return
}

After Mem2Reg (3rd):
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
store v1 at v2
jmpif v0 then: b1, else: b2
b1():
v5 = array_set v1, index u32 0, value u32 1
store v5 at v2
jmp b2()
b2():
v6 = load v2 -> [u32; 30]
v7 = array_get v6, index u32 0 -> u32
v8 = array_get v6, index u32 1 -> u32
v9 = add v7, v8
v10 = eq v9, u32 1
constrain v9 == u32 1
return
}

After Flattening:
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
store v1 at v2
enable_side_effects v0
v5 = array_set v1, index u32 0, value u32 1
v6 = load v2 -> [u32; 30]
v7 = not v0
v8 = if v0 then v5 else (if v7) v6
store v8 at v2
enable_side_effects u1 1
v10 = load v2 -> [u32; 30]
v11 = array_get v10, index u32 0 -> u32
v12 = array_get v10, index u32 1 -> u32
v13 = add v11, v12
v14 = eq v13, u32 1
constrain v13 == u32 1
return
}

After Removing Bit Shifts:
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
store v1 at v2
enable_side_effects v0
v5 = array_set v1, index u32 0, value u32 1
v6 = load v2 -> [u32; 30]
v7 = not v0
v8 = if v0 then v5 else (if v7) v6
store v8 at v2
enable_side_effects u1 1
v10 = load v2 -> [u32; 30]
v11 = array_get v10, index u32 0 -> u32
v12 = array_get v10, index u32 1 -> u32
v13 = add v11, v12
v14 = eq v13, u32 1
constrain v13 == u32 1
return
}

After Mem2Reg (4th):
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
enable_side_effects v0
v5 = array_set v1, index u32 0, value u32 1
v6 = not v0
v7 = if v0 then v5 else (if v6) v1
enable_side_effects u1 1
v9 = array_get v7, index u32 0 -> u32
v10 = array_get v7, index u32 1 -> u32
v11 = add v9, v10
v12 = eq v11, u32 1
constrain v11 == u32 1
return
}

After Inlining (2nd):
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
enable_side_effects v0
v5 = array_set v1, index u32 0, value u32 1
v6 = not v0
v7 = if v0 then v5 else (if v6) v1
enable_side_effects u1 1
v9 = array_get v7, index u32 0 -> u32
v10 = array_get v7, index u32 1 -> u32
v11 = add v9, v10
v12 = eq v11, u32 1
constrain v11 == u32 1
return
}

After Remove IfElse:
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
enable_side_effects v0
v5 = array_set v1, index u32 0, value u32 1
v6 = not v0
enable_side_effects v0
v7 = array_get v1, index u32 0 -> u32
v8 = cast v0 as u32
v9 = cast v6 as u32
v10 = unchecked_mul v9, v7
v11 = unchecked_add v8, v10
v12 = array_set v5, index u32 0, value v11
enable_side_effects v0
enable_side_effects u1 1
v14 = array_get v12, index u32 0 -> u32
v15 = array_get v12, index u32 1 -> u32
v16 = add v14, v15
v17 = eq v16, u32 1
constrain v16 == u32 1
return
}

After Purity Analysis (2nd):
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
enable_side_effects v0
v5 = array_set v1, index u32 0, value u32 1
v6 = not v0
enable_side_effects v0
v7 = array_get v1, index u32 0 -> u32
v8 = cast v0 as u32
v9 = cast v6 as u32
v10 = unchecked_mul v9, v7
v11 = unchecked_add v8, v10
v12 = array_set v5, index u32 0, value v11
enable_side_effects v0
enable_side_effects u1 1
v14 = array_get v12, index u32 0 -> u32
v15 = array_get v12, index u32 1 -> u32
v16 = add v14, v15
v17 = eq v16, u32 1
constrain v16 == u32 1
return
}

After Constant Folding:
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
enable_side_effects v0
v5 = array_set v1, index u32 0, value u32 1
v6 = not v0
enable_side_effects v0
v7 = array_get v1, index u32 0 -> u32
v8 = cast v0 as u32
v9 = cast v6 as u32
v10 = unchecked_mul v9, v7
v11 = unchecked_add v8, v10
v12 = array_set v5, index u32 0, value v11
enable_side_effects u1 1
v14 = array_get v12, index u32 1 -> u32
v15 = add v11, v14
v16 = eq v15, u32 1
constrain v15 == u32 1
return
}

After Simplify conditionals for unconstrained:
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
enable_side_effects v0
v5 = array_set v1, index u32 0, value u32 1
v6 = not v0
enable_side_effects v0
v7 = array_get v1, index u32 0 -> u32
v8 = cast v0 as u32
v9 = cast v6 as u32
v10 = unchecked_mul v9, v7
v11 = unchecked_add v8, v10
v12 = array_set v5, index u32 0, value v11
enable_side_effects u1 1
v14 = array_get v12, index u32 1 -> u32
v15 = add v11, v14
v16 = eq v15, u32 1
constrain v15 == u32 1
return
}

After EnableSideEffectsIf removal:
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
enable_side_effects v0
v5 = array_set v1, index u32 0, value u32 1
v6 = not v0
v7 = array_get v1, index u32 0 -> u32
v8 = cast v0 as u32
v9 = cast v6 as u32
v10 = unchecked_mul v9, v7
v11 = unchecked_add v8, v10
v12 = array_set v5, index u32 0, value v11
enable_side_effects u1 1
v14 = array_get v12, index u32 1 -> u32
v15 = add v11, v14
v16 = eq v15, u32 1
constrain v15 == u32 1
return
}

After Constraint Folding:
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
enable_side_effects v0
v5 = array_set v1, index u32 0, value u32 1
v6 = not v0
v7 = array_get v1, index u32 0 -> u32
v8 = cast v0 as u32
v9 = cast v6 as u32
v10 = unchecked_mul v9, v7
v11 = unchecked_add v8, v10
v12 = array_set v5, index u32 0, value v11
enable_side_effects u1 1
v14 = array_get v12, index u32 1 -> u32
v15 = add v11, v14
v16 = eq v15, u32 1
constrain v15 == u32 1
return
}

After Adding constrain not equal:
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
enable_side_effects v0
v5 = array_set v1, index u32 0, value u32 1
v6 = not v0
v7 = array_get v1, index u32 0 -> u32
v8 = cast v0 as u32
v9 = cast v6 as u32
v10 = unchecked_mul v9, v7
v11 = unchecked_add v8, v10
v12 = array_set v5, index u32 0, value v11
enable_side_effects u1 1
v14 = array_get v12, index u32 1 -> u32
v15 = add v11, v14
v16 = eq v15, u32 1
constrain v15 == u32 1
return
}

After Check u128 mul overflow:
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
enable_side_effects v0
v5 = array_set v1, index u32 0, value u32 1
v6 = not v0
v7 = array_get v1, index u32 0 -> u32
v8 = cast v0 as u32
v9 = cast v6 as u32
v10 = unchecked_mul v9, v7
v11 = unchecked_add v8, v10
v12 = array_set v5, index u32 0, value v11
enable_side_effects u1 1
v14 = array_get v12, index u32 1 -> u32
v15 = add v11, v14
v16 = eq v15, u32 1
constrain v15 == u32 1
return
}

After Dead Instruction Elimination (1st):
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
enable_side_effects v0
v4 = array_set v1, index u32 0, value u32 1
v5 = not v0
v6 = array_get v1, index u32 0 -> u32
v7 = cast v0 as u32
v8 = cast v5 as u32
v9 = unchecked_mul v8, v6
v10 = unchecked_add v7, v9
v11 = array_set v4, index u32 0, value v10
enable_side_effects u1 1
v13 = array_get v11, index u32 1 -> u32
v14 = add v10, v13
constrain v14 == u32 1
return
}

After Simplifying (3rd)::
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
enable_side_effects v0
v4 = array_set v1, index u32 0, value u32 1
v5 = not v0
v6 = array_get v1, index u32 0 -> u32
v7 = cast v0 as u32
v8 = cast v5 as u32
v9 = unchecked_mul v8, v6
v10 = unchecked_add v7, v9
v11 = array_set v4, index u32 0, value v10
enable_side_effects u1 1
v13 = array_get v11, index u32 1 -> u32
v14 = add v10, v13
constrain v14 == u32 1
return
}

After Array Set Optimizations:
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
enable_side_effects v0
v4 = array_set v1, index u32 0, value u32 1
v5 = not v0
v6 = array_get v1, index u32 0 -> u32
v7 = cast v0 as u32
v8 = cast v5 as u32
v9 = unchecked_mul v8, v6
v10 = unchecked_add v7, v9
v11 = array_set mut v4, index u32 0, value v10
enable_side_effects u1 1
v13 = array_get v11, index u32 1 -> u32
v14 = add v10, v13
constrain v14 == u32 1
return
}

After Brillig Entry Point Analysis:
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
enable_side_effects v0
v4 = array_set v1, index u32 0, value u32 1
v5 = not v0
v6 = array_get v1, index u32 0 -> u32
v7 = cast v0 as u32
v8 = cast v5 as u32
v9 = unchecked_mul v8, v6
v10 = unchecked_add v7, v9
v11 = array_set mut v4, index u32 0, value v10
enable_side_effects u1 1
v13 = array_get v11, index u32 1 -> u32
v14 = add v10, v13
constrain v14 == u32 1
return
}

After Removing Unreachable Functions (3rd):
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
enable_side_effects v0
v4 = array_set v1, index u32 0, value u32 1
v5 = not v0
v6 = array_get v1, index u32 0 -> u32
v7 = cast v0 as u32
v8 = cast v5 as u32
v9 = unchecked_mul v8, v6
v10 = unchecked_add v7, v9
v11 = array_set mut v4, index u32 0, value v10
enable_side_effects u1 1
v13 = array_get v11, index u32 1 -> u32
v14 = add v10, v13
constrain v14 == u32 1
return
}

After Brillig Array Get Optimizations:
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
enable_side_effects v0
v4 = array_set v1, index u32 0, value u32 1
v5 = not v0
v6 = array_get v1, index u32 0 -> u32
v7 = cast v0 as u32
v8 = cast v5 as u32
v9 = unchecked_mul v8, v6
v10 = unchecked_add v7, v9
v11 = array_set mut v4, index u32 0, value v10
enable_side_effects u1 1
v13 = array_get v11, index u32 1 -> u32
v14 = add v10, v13
constrain v14 == u32 1
return
}

After Dead Instruction Elimination (2nd):
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
enable_side_effects v0
v4 = array_set v1, index u32 0, value u32 1
v5 = not v0
v6 = array_get v1, index u32 0 -> u32
v7 = cast v0 as u32
v8 = cast v5 as u32
v9 = unchecked_mul v8, v6
v10 = unchecked_add v7, v9
v11 = array_set mut v4, index u32 0, value v10
enable_side_effects u1 1
v13 = array_get v11, index u32 1 -> u32
v14 = add v10, v13
constrain v14 == u32 1
return
}

After Inlining Brillig Calls Inlining:
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
enable_side_effects v0
v4 = array_set v1, index u32 0, value u32 1
v5 = not v0
v6 = array_get v1, index u32 0 -> u32
v7 = cast v0 as u32
v8 = cast v5 as u32
v9 = unchecked_mul v8, v6
v10 = unchecked_add v7, v9
v11 = array_set mut v4, index u32 0, value v10
enable_side_effects u1 1
v13 = array_get v11, index u32 1 -> u32
v14 = add v10, v13
constrain v14 == u32 1
return
}

After Removing Unreachable Functions (4th):
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
enable_side_effects v0
v4 = array_set v1, index u32 0, value u32 1
v5 = not v0
v6 = array_get v1, index u32 0 -> u32
v7 = cast v0 as u32
v8 = cast v5 as u32
v9 = unchecked_mul v8, v6
v10 = unchecked_add v7, v9
v11 = array_set mut v4, index u32 0, value v10
enable_side_effects u1 1
v13 = array_get v11, index u32 1 -> u32
v14 = add v10, v13
constrain v14 == u32 1
return
}

After Dead Instruction Elimination (3rd):
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
enable_side_effects v0
v4 = array_set v1, index u32 0, value u32 1
v5 = not v0
v6 = array_get v1, index u32 0 -> u32
v7 = cast v0 as u32
v8 = cast v5 as u32
v9 = unchecked_mul v8, v6
v10 = unchecked_add v7, v9
v11 = array_set mut v4, index u32 0, value v10
enable_side_effects u1 1
v13 = array_get v11, index u32 1 -> u32
v14 = add v10, v13
constrain v14 == u32 1
return
}

This is pretty large so we can also print out the state of the SSA after individual passes using nargo copmile --show-ssa-pass <pattern> where <pattern> is a string which will be compared to the names of the SSA passes in a case-insensitive manner. e.g. `nargo compile --show-ssa-pass dead" will print out all of the dead instruction elimination (DIE) passes due to it matching "dead".

After Dead Instruction Elimination (1st):
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
enable_side_effects v0
v4 = array_set v1, index u32 0, value u32 1
v5 = not v0
v6 = array_get v1, index u32 0 -> u32
v7 = cast v0 as u32
v8 = cast v5 as u32
v9 = unchecked_mul v8, v6
v10 = unchecked_add v7, v9
v11 = array_set v4, index u32 0, value v10
enable_side_effects u1 1
v13 = array_get v11, index u32 1 -> u32
v14 = add v10, v13
constrain v14 == u32 1
return
}

After Dead Instruction Elimination (2nd):
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
enable_side_effects v0
v4 = array_set v1, index u32 0, value u32 1
v5 = not v0
v6 = array_get v1, index u32 0 -> u32
v7 = cast v0 as u32
v8 = cast v5 as u32
v9 = unchecked_mul v8, v6
v10 = unchecked_add v7, v9
v11 = array_set mut v4, index u32 0, value v10
enable_side_effects u1 1
v13 = array_get v11, index u32 1 -> u32
v14 = add v10, v13
constrain v14 == u32 1
return
}

After Dead Instruction Elimination (3rd):
acir(inline) predicate_pure fn main f0 {
b0(v0: u1, v1: [u32; 30]):
enable_side_effects v0
v4 = array_set v1, index u32 0, value u32 1
v5 = not v0
v6 = array_get v1, index u32 0 -> u32
v7 = cast v0 as u32
v8 = cast v5 as u32
v9 = unchecked_mul v8, v6
v10 = unchecked_add v7, v9
v11 = array_set mut v4, index u32 0, value v10
enable_side_effects u1 1
v13 = array_get v11, index u32 1 -> u32
v14 = add v10, v13
constrain v14 == u32 1
return
}

Here we've just printed out the three DIE passes as they all match the pattern we've provided. If we just wanted the last then we can give a more specific patten such as nargo compile --show-ssa-pass "Dead Instruction Elimination (3rd)"

This can be very useful if you want to just see the final SSA for the program before ACIR generation.

Reading SSA output

After Initial SSA:
acir(inline) fn main f0 {
b0(v0: u1, v1: [u32; 30]):
v2 = allocate -> &mut [u32; 30]
store v1 at v2
jmpif v0 then: b1, else: b2
b1():
v3 = load v2 -> [u32; 30]
v6 = array_set v3, index u32 0, value u32 1
store v6 at v2
jmp b2()
b2():
v7 = load v2 -> [u32; 30]
v8 = array_get v7, index u32 0 -> u32
v9 = load v2 -> [u32; 30]
v10 = array_get v9, index u32 1 -> u32
v11 = add v8, v10
v12 = eq v11, u32 1
constrain v11 == u32 1
return
}