Warning! Adding boolean cast to non-boolean condition *((byte*) print::msg + (byte) print::i)
Culled Empty Block (label) do10::@2
Culled Empty Block (label) @1
Culled Empty Block (label) @2
Culled Empty Block (label) @3
Culled Empty Block (label) print::@2

CONTROL FLOW GRAPH SSA
@begin: scope:[]  from
  to:@4

(void()) do10((void()*) do10::fn)
do10: scope:[do10]  from main main::@1
  (void()*) do10::fn#3 ← phi( main/(void()*) do10::fn#0 main::@1/(void()*) do10::fn#1 )
  (byte) do10::i#0 ← (byte) 0
  to:do10::@1
do10::@1: scope:[do10]  from do10 do10::@1
  (byte) do10::i#2 ← phi( do10/(byte) do10::i#0 do10::@1/(byte) do10::i#1 )
  (void()*) do10::fn#2 ← phi( do10/(void()*) do10::fn#3 do10::@1/(void()*) do10::fn#2 )
  call *((void()*) do10::fn#2) 
  (byte) do10::i#1 ← (byte) do10::i#2 + rangenext(0,9)
  (bool~) do10::$1 ← (byte) do10::i#1 != rangelast(0,9)
  if((bool~) do10::$1) goto do10::@1
  to:do10::@return
do10::@return: scope:[do10]  from do10::@1
  return 
  to:@return

(void()) hello()
hello: scope:[hello]  from
  (byte*) print::msg#0 ← (const byte*) hello::msg
  call print 
  to:hello::@1
hello::@1: scope:[hello]  from hello
  to:hello::@return
hello::@return: scope:[hello]  from hello::@1
  return 
  to:@return

(void()) world()
world: scope:[world]  from
  (byte*) print::msg#1 ← (const byte*) world::msg
  call print 
  to:world::@1
world::@1: scope:[world]  from world
  to:world::@return
world::@return: scope:[world]  from world::@1
  return 
  to:@return

(void()) main()
main: scope:[main]  from @5
  (void()*) do10::fn#0 ← &(void()) hello()
  call do10 
  to:main::@1
main::@1: scope:[main]  from main
  (void()*) do10::fn#1 ← &(void()) world()
  call do10 
  to:main::@2
main::@2: scope:[main]  from main::@1
  to:main::@return
main::@return: scope:[main]  from main::@2
  return 
  to:@return
@4: scope:[]  from @begin
  (byte) idx ← (byte) 0
  to:@5

(void()) print((byte*) print::msg)
print: scope:[print]  from hello world
  (byte*) print::msg#3 ← phi( hello/(byte*) print::msg#0 world/(byte*) print::msg#1 )
  (byte) print::i#0 ← (byte) 0
  to:print::@1
print::@1: scope:[print]  from print print::@1
  (byte) print::i#2 ← phi( print/(byte) print::i#0 print::@1/(byte) print::i#1 )
  (byte*) print::msg#2 ← phi( print/(byte*) print::msg#3 print::@1/(byte*) print::msg#2 )
  *((const byte*) SCREEN + (byte) idx) ← *((byte*) print::msg#2 + (byte) print::i#2)
  (byte) idx ← ++ (byte) idx
  (byte) print::i#1 ← ++ (byte) print::i#2
  (bool~) print::$0 ← (number) 0 != *((byte*) print::msg#2 + (byte) print::i#1)
  if((bool~) print::$0) goto print::@1
  to:print::@return
print::@return: scope:[print]  from print::@1
  return 
  to:@return
@5: scope:[]  from @4
  call main 
  to:@6
@6: scope:[]  from @5
  to:@end
@end: scope:[]  from @6

SYMBOL TABLE SSA
(label) @4
(label) @5
(label) @6
(label) @begin
(label) @end
(const byte*) SCREEN = (byte*)(number) $400
(void()) do10((void()*) do10::fn)
(bool~) do10::$1
(label) do10::@1
(label) do10::@return
(void()*) do10::fn
(void()*) do10::fn#0
(void()*) do10::fn#1
(void()*) do10::fn#2
(void()*) do10::fn#3
(byte) do10::i
(byte) do10::i#0
(byte) do10::i#1
(byte) do10::i#2
(void()) hello()
(label) hello::@1
(label) hello::@return
(const byte*) hello::msg[(byte) 7]  = (byte*) "hello "
(byte) idx loadstore
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@return
(void()) print((byte*) print::msg)
(bool~) print::$0
(label) print::@1
(label) print::@return
(byte) print::i
(byte) print::i#0
(byte) print::i#1
(byte) print::i#2
(byte*) print::msg
(byte*) print::msg#0
(byte*) print::msg#1
(byte*) print::msg#2
(byte*) print::msg#3
(void()) world()
(label) world::@1
(label) world::@return
(const byte*) world::msg[(byte) 7]  = (byte*) "world "

Adding number conversion cast (unumber) 0 in (bool~) print::$0 ← (number) 0 != *((byte*) print::msg#2 + (byte) print::i#1)
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Identical Phi Values (void()*) do10::fn#2 (void()*) do10::fn#3
Identical Phi Values (byte*) print::msg#2 (byte*) print::msg#3
Successful SSA optimization Pass2IdenticalPhiElimination
Simple Condition (bool~) do10::$1 [6] if((byte) do10::i#1!=rangelast(0,9)) goto do10::@1
Simple Condition (bool~) print::$0 [27] if((byte) 0!=*((byte*) print::msg#3 + (byte) print::i#1)) goto print::@1
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const byte) do10::i#0 = 0
Constant (const byte*) print::msg#0 = hello::msg
Constant (const byte*) print::msg#1 = world::msg
Constant (const void()*) do10::fn#0 = &hello
Constant (const void()*) do10::fn#1 = &world
Constant (const byte) print::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Resolved ranged next value [4] do10::i#1 ← ++ do10::i#2 to ++
Resolved ranged comparison value [6] if(do10::i#1!=rangelast(0,9)) goto do10::@1 to (number) $a
Adding number conversion cast (unumber) $a in if((byte) do10::i#1!=(number) $a) goto do10::@1
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant integer cast $a
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) $a
Successful SSA optimization PassNFinalizeNumberTypeConversions
Inlining constant with var siblings (const byte) do10::i#0
Inlining constant with var siblings (const void()*) do10::fn#0
Inlining constant with var siblings (const void()*) do10::fn#1
Inlining constant with var siblings (const byte*) print::msg#0
Inlining constant with var siblings (const byte*) print::msg#1
Inlining constant with var siblings (const byte) print::i#0
Constant inlined do10::i#0 = (byte) 0
Constant inlined print::i#0 = (byte) 0
Constant inlined do10::fn#1 = &(void()) world()
Constant inlined do10::fn#0 = &(void()) hello()
Constant inlined print::msg#1 = (const byte*) world::msg
Constant inlined print::msg#0 = (const byte*) hello::msg
Successful SSA optimization Pass2ConstantInlining
Added new block during phi lifting do10::@3(between do10::@1 and do10::@1)
Added new block during phi lifting print::@3(between print::@1 and print::@1)
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @5
Adding NOP phi() at start of @6
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
Adding NOP phi() at start of main::@1
Adding NOP phi() at start of main::@2
Adding NOP phi() at start of world
Adding NOP phi() at start of world::@1
Adding NOP phi() at start of hello
Adding NOP phi() at start of hello::@1
CALL GRAPH
Calls in [] to main:3 
Calls in [main] to do10:7 do10:9 
Calls in [world] to print:20 
Calls in [hello] to print:32 

Created 4 initial phi equivalence classes
Coalesced [18] do10::i#3 ← do10::i#1
Coalesced [30] print::i#3 ← print::i#1
Coalesced down to 4 phi equivalence classes
Culled Empty Block (label) @6
Culled Empty Block (label) main::@2
Culled Empty Block (label) do10::@3
Culled Empty Block (label) world::@1
Culled Empty Block (label) print::@3
Culled Empty Block (label) hello::@1
Renumbering block @4 to @1
Renumbering block @5 to @2
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @2
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
Adding NOP phi() at start of main::@1
Adding NOP phi() at start of world
Adding NOP phi() at start of hello

FINAL CONTROL FLOW GRAPH
@begin: scope:[]  from
  [0] phi()
  to:@1
@1: scope:[]  from @begin
  [1] (byte) idx ← (byte) 0
  to:@2
@2: scope:[]  from @1
  [2] phi()
  [3] call main 
  to:@end
@end: scope:[]  from @2
  [4] phi()

(void()) main()
main: scope:[main]  from @2
  [5] phi()
  [6] call do10 
  to:main::@1
main::@1: scope:[main]  from main
  [7] phi()
  [8] call do10 
  to:main::@return
main::@return: scope:[main]  from main::@1
  [9] return 
  to:@return

(void()) do10((void()*) do10::fn)
do10: scope:[do10]  from main main::@1
  [10] (void()*) do10::fn#3 ← phi( main/&(void()) hello() main::@1/&(void()) world() )
  to:do10::@1
do10::@1: scope:[do10]  from do10 do10::@1
  [11] (byte) do10::i#2 ← phi( do10/(byte) 0 do10::@1/(byte) do10::i#1 )
  [12] call *((void()*) do10::fn#3) 
  [13] (byte) do10::i#1 ← ++ (byte) do10::i#2
  [14] if((byte) do10::i#1!=(byte) $a) goto do10::@1
  to:do10::@return
do10::@return: scope:[do10]  from do10::@1
  [15] return 
  to:@return

(void()) world()
world: scope:[world]  from
  [16] phi()
  [17] call print 
  to:world::@return
world::@return: scope:[world]  from world
  [18] return 
  to:@return

(void()) print((byte*) print::msg)
print: scope:[print]  from hello world
  [19] (byte*) print::msg#3 ← phi( hello/(const byte*) hello::msg world/(const byte*) world::msg )
  to:print::@1
print::@1: scope:[print]  from print print::@1
  [20] (byte) print::i#2 ← phi( print/(byte) 0 print::@1/(byte) print::i#1 )
  [21] *((const byte*) SCREEN + (byte) idx) ← *((byte*) print::msg#3 + (byte) print::i#2)
  [22] (byte) idx ← ++ (byte) idx
  [23] (byte) print::i#1 ← ++ (byte) print::i#2
  [24] if((byte) 0!=*((byte*) print::msg#3 + (byte) print::i#1)) goto print::@1
  to:print::@return
print::@return: scope:[print]  from print::@1
  [25] return 
  to:@return

(void()) hello()
hello: scope:[hello]  from
  [26] phi()
  [27] call print 
  to:hello::@return
hello::@return: scope:[hello]  from hello
  [28] return 
  to:@return


VARIABLE REGISTER WEIGHTS
(void()) do10((void()*) do10::fn)
(void()*) do10::fn
(void()*) do10::fn#3
(byte) do10::i
(byte) do10::i#1 16.5
(byte) do10::i#2 11.0
(void()) hello()
(byte) idx loadstore 4.375
(void()) main()
(void()) print((byte*) print::msg)
(byte) print::i
(byte) print::i#1 16.5
(byte) print::i#2 11.0
(byte*) print::msg
(byte*) print::msg#3 3.6666666666666665
(void()) world()

Initial phi equivalence classes
[ do10::fn#3 ]
[ do10::i#2 do10::i#1 ]
[ print::msg#3 ]
[ print::i#2 print::i#1 ]
Added variable idx to live range equivalence class [ idx ]
Complete equivalence classes
[ do10::fn#3 ]
[ do10::i#2 do10::i#1 ]
[ print::msg#3 ]
[ print::i#2 print::i#1 ]
[ idx ]
Allocated zp[2]:2 [ do10::fn#3 ]
Allocated zp[1]:4 [ do10::i#2 do10::i#1 ]
Allocated zp[2]:5 [ print::msg#3 ]
Allocated zp[1]:7 [ print::i#2 print::i#1 ]
Allocated zp[1]:8 [ idx ]

INITIAL ASM
Target platform is c64basic / MOS6502X
  // File Comments
// Tests calling into different function pointers which call a common sub-method
  // Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
  // Global Constants & labels
  .label SCREEN = $400
  .label idx = 8
  // @begin
__bbegin:
  jmp __b1
  // @1
__b1:
  // [1] (byte) idx ← (byte) 0 -- vbuz1=vbuc1 
  lda #0
  sta.z idx
  // [2] phi from @1 to @2 [phi:@1->@2]
__b2_from___b1:
  jmp __b2
  // @2
__b2:
  // [3] call main 
  // [5] phi from @2 to main [phi:@2->main]
main_from___b2:
  jsr main
  // [4] phi from @2 to @end [phi:@2->@end]
__bend_from___b2:
  jmp __bend
  // @end
__bend:
  // main
main: {
    // [6] call do10 
    // [10] phi from main to do10 [phi:main->do10]
  do10_from_main:
    // [10] phi (void()*) do10::fn#3 = &(void()) hello() [phi:main->do10#0] -- pprz1=pprc1 
    lda #<hello
    sta.z do10.fn
    lda #>hello
    sta.z do10.fn+1
    jsr do10
    // [7] phi from main to main::@1 [phi:main->main::@1]
  __b1_from_main:
    jmp __b1
    // main::@1
  __b1:
    // [8] call do10 
    // [10] phi from main::@1 to do10 [phi:main::@1->do10]
  do10_from___b1:
    // [10] phi (void()*) do10::fn#3 = &(void()) world() [phi:main::@1->do10#0] -- pprz1=pprc1 
    lda #<world
    sta.z do10.fn
    lda #>world
    sta.z do10.fn+1
    jsr do10
    jmp __breturn
    // main::@return
  __breturn:
    // [9] return 
    rts
}
  // do10
// do10(void()* zp(2) fn)
do10: {
    .label i = 4
    .label fn = 2
    // [11] phi from do10 to do10::@1 [phi:do10->do10::@1]
  __b1_from_do10:
    // [11] phi (byte) do10::i#2 = (byte) 0 [phi:do10->do10::@1#0] -- vbuz1=vbuc1 
    lda #0
    sta.z i
    jmp __b1
    // [11] phi from do10::@1 to do10::@1 [phi:do10::@1->do10::@1]
  __b1_from___b1:
    // [11] phi (byte) do10::i#2 = (byte) do10::i#1 [phi:do10::@1->do10::@1#0] -- register_copy 
    jmp __b1
    // do10::@1
  __b1:
    // [12] call *((void()*) do10::fn#3) 
    jsr bi_fn
    // [13] (byte) do10::i#1 ← ++ (byte) do10::i#2 -- vbuz1=_inc_vbuz1 
    inc.z i
    // [14] if((byte) do10::i#1!=(byte) $a) goto do10::@1 -- vbuz1_neq_vbuc1_then_la1 
    lda #$a
    cmp.z i
    bne __b1_from___b1
    jmp __breturn
    // do10::@return
  __breturn:
    // [15] return 
    rts
  bi_fn:
    jmp (fn)
}
  // world
world: {
    // [17] call print 
    // [19] phi from world to print [phi:world->print]
  print_from_world:
    // [19] phi (byte*) print::msg#3 = (const byte*) world::msg [phi:world->print#0] -- pbuz1=pbuc1 
    lda #<msg
    sta.z print.msg
    lda #>msg
    sta.z print.msg+1
    jsr print
    jmp __breturn
    // world::@return
  __breturn:
    // [18] return 
    rts
    msg: .text "world "
    .byte 0
}
  // print
// print(byte* zp(5) msg)
print: {
    .label i = 7
    .label msg = 5
    // [20] phi from print to print::@1 [phi:print->print::@1]
  __b1_from_print:
    // [20] phi (byte) print::i#2 = (byte) 0 [phi:print->print::@1#0] -- vbuz1=vbuc1 
    lda #0
    sta.z i
    jmp __b1
    // [20] phi from print::@1 to print::@1 [phi:print::@1->print::@1]
  __b1_from___b1:
    // [20] phi (byte) print::i#2 = (byte) print::i#1 [phi:print::@1->print::@1#0] -- register_copy 
    jmp __b1
    // print::@1
  __b1:
    // [21] *((const byte*) SCREEN + (byte) idx) ← *((byte*) print::msg#3 + (byte) print::i#2) -- pbuc1_derefidx_vbuz1=pbuz2_derefidx_vbuz3 
    ldx.z idx
    ldy.z i
    lda (msg),y
    sta SCREEN,x
    // [22] (byte) idx ← ++ (byte) idx -- vbuz1=_inc_vbuz1 
    inc.z idx
    // [23] (byte) print::i#1 ← ++ (byte) print::i#2 -- vbuz1=_inc_vbuz1 
    inc.z i
    // [24] if((byte) 0!=*((byte*) print::msg#3 + (byte) print::i#1)) goto print::@1 -- vbuc1_neq_pbuz1_derefidx_vbuz2_then_la1 
    ldy.z i
    lda (msg),y
    cmp #0
    bne __b1_from___b1
    jmp __breturn
    // print::@return
  __breturn:
    // [25] return 
    rts
}
  // hello
hello: {
    // [27] call print 
    // [19] phi from hello to print [phi:hello->print]
  print_from_hello:
    // [19] phi (byte*) print::msg#3 = (const byte*) hello::msg [phi:hello->print#0] -- pbuz1=pbuc1 
    lda #<msg
    sta.z print.msg
    lda #>msg
    sta.z print.msg+1
    jsr print
    jmp __breturn
    // hello::@return
  __breturn:
    // [28] return 
    rts
    msg: .text "hello "
    .byte 0
}
  // File Data

REGISTER UPLIFT POTENTIAL REGISTERS
Statement [1] (byte) idx ← (byte) 0 [ ] (  [ ] ) always clobbers reg byte a 
Statement [12] call *((void()*) do10::fn#3)  [ do10::fn#3 do10::i#2 ] ( main:3::do10:6 [ do10::fn#3 do10::i#2 ] main:3::do10:8 [ do10::fn#3 do10::i#2 ] ) always clobbers reg byte a reg byte x reg byte y 
Removing always clobbered register reg byte a as potential for zp[1]:4 [ do10::i#2 do10::i#1 ]
Removing always clobbered register reg byte x as potential for zp[1]:4 [ do10::i#2 do10::i#1 ]
Removing always clobbered register reg byte y as potential for zp[1]:4 [ do10::i#2 do10::i#1 ]
Statement [14] if((byte) do10::i#1!=(byte) $a) goto do10::@1 [ do10::fn#3 do10::i#1 ] ( main:3::do10:6 [ do10::fn#3 do10::i#1 ] main:3::do10:8 [ do10::fn#3 do10::i#1 ] ) always clobbers reg byte a 
Statement [21] *((const byte*) SCREEN + (byte) idx) ← *((byte*) print::msg#3 + (byte) print::i#2) [ idx print::msg#3 print::i#2 ] ( print:17 [ idx print::msg#3 print::i#2 ] print:27 [ idx print::msg#3 print::i#2 ] ) always clobbers reg byte a reg byte x 
Removing always clobbered register reg byte a as potential for zp[1]:7 [ print::i#2 print::i#1 ]
Removing always clobbered register reg byte x as potential for zp[1]:7 [ print::i#2 print::i#1 ]
Statement [24] if((byte) 0!=*((byte*) print::msg#3 + (byte) print::i#1)) goto print::@1 [ idx print::msg#3 print::i#1 ] ( print:17 [ idx print::msg#3 print::i#1 ] print:27 [ idx print::msg#3 print::i#1 ] ) always clobbers reg byte a 
Statement [1] (byte) idx ← (byte) 0 [ ] (  [ ] ) always clobbers reg byte a 
Statement [12] call *((void()*) do10::fn#3)  [ do10::fn#3 do10::i#2 ] ( main:3::do10:6 [ do10::fn#3 do10::i#2 ] main:3::do10:8 [ do10::fn#3 do10::i#2 ] ) always clobbers reg byte a reg byte x reg byte y 
Statement [14] if((byte) do10::i#1!=(byte) $a) goto do10::@1 [ do10::fn#3 do10::i#1 ] ( main:3::do10:6 [ do10::fn#3 do10::i#1 ] main:3::do10:8 [ do10::fn#3 do10::i#1 ] ) always clobbers reg byte a 
Statement [21] *((const byte*) SCREEN + (byte) idx) ← *((byte*) print::msg#3 + (byte) print::i#2) [ idx print::msg#3 print::i#2 ] ( print:17 [ idx print::msg#3 print::i#2 ] print:27 [ idx print::msg#3 print::i#2 ] ) always clobbers reg byte a reg byte x 
Statement [24] if((byte) 0!=*((byte*) print::msg#3 + (byte) print::i#1)) goto print::@1 [ idx print::msg#3 print::i#1 ] ( print:17 [ idx print::msg#3 print::i#1 ] print:27 [ idx print::msg#3 print::i#1 ] ) always clobbers reg byte a 
Potential registers zp[2]:2 [ do10::fn#3 ] : zp[2]:2 , 
Potential registers zp[1]:4 [ do10::i#2 do10::i#1 ] : zp[1]:4 , 
Potential registers zp[2]:5 [ print::msg#3 ] : zp[2]:5 , 
Potential registers zp[1]:7 [ print::i#2 print::i#1 ] : zp[1]:7 , reg byte y , 
Potential registers zp[1]:8 [ idx ] : zp[1]:8 , 

REGISTER UPLIFT SCOPES
Uplift Scope [print] 27.5: zp[1]:7 [ print::i#2 print::i#1 ] 3.67: zp[2]:5 [ print::msg#3 ] 
Uplift Scope [do10] 27.5: zp[1]:4 [ do10::i#2 do10::i#1 ] 0: zp[2]:2 [ do10::fn#3 ] 
Uplift Scope [] 4.38: zp[1]:8 [ idx ] 
Uplift Scope [hello] 
Uplift Scope [world] 
Uplift Scope [main] 

Uplifting [print] best 898 combination reg byte y [ print::i#2 print::i#1 ] zp[2]:5 [ print::msg#3 ] 
Uplifting [do10] best 898 combination zp[1]:4 [ do10::i#2 do10::i#1 ] zp[2]:2 [ do10::fn#3 ] 
Uplifting [] best 898 combination zp[1]:8 [ idx ] 
Uplifting [hello] best 898 combination 
Uplifting [world] best 898 combination 
Uplifting [main] best 898 combination 
Attempting to uplift remaining variables inzp[1]:4 [ do10::i#2 do10::i#1 ]
Uplifting [do10] best 898 combination zp[1]:4 [ do10::i#2 do10::i#1 ] 
Attempting to uplift remaining variables inzp[1]:8 [ idx ]
Uplifting [] best 898 combination zp[1]:8 [ idx ] 
Allocated (was zp[1]:8) zp[1]:7 [ idx ]

ASSEMBLER BEFORE OPTIMIZATION
  // File Comments
// Tests calling into different function pointers which call a common sub-method
  // Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
  // Global Constants & labels
  .label SCREEN = $400
  .label idx = 7
  // @begin
__bbegin:
  jmp __b1
  // @1
__b1:
  // [1] (byte) idx ← (byte) 0 -- vbuz1=vbuc1 
  lda #0
  sta.z idx
  // [2] phi from @1 to @2 [phi:@1->@2]
__b2_from___b1:
  jmp __b2
  // @2
__b2:
  // [3] call main 
  // [5] phi from @2 to main [phi:@2->main]
main_from___b2:
  jsr main
  // [4] phi from @2 to @end [phi:@2->@end]
__bend_from___b2:
  jmp __bend
  // @end
__bend:
  // main
main: {
    // [6] call do10 
    // [10] phi from main to do10 [phi:main->do10]
  do10_from_main:
    // [10] phi (void()*) do10::fn#3 = &(void()) hello() [phi:main->do10#0] -- pprz1=pprc1 
    lda #<hello
    sta.z do10.fn
    lda #>hello
    sta.z do10.fn+1
    jsr do10
    // [7] phi from main to main::@1 [phi:main->main::@1]
  __b1_from_main:
    jmp __b1
    // main::@1
  __b1:
    // [8] call do10 
    // [10] phi from main::@1 to do10 [phi:main::@1->do10]
  do10_from___b1:
    // [10] phi (void()*) do10::fn#3 = &(void()) world() [phi:main::@1->do10#0] -- pprz1=pprc1 
    lda #<world
    sta.z do10.fn
    lda #>world
    sta.z do10.fn+1
    jsr do10
    jmp __breturn
    // main::@return
  __breturn:
    // [9] return 
    rts
}
  // do10
// do10(void()* zp(2) fn)
do10: {
    .label i = 4
    .label fn = 2
    // [11] phi from do10 to do10::@1 [phi:do10->do10::@1]
  __b1_from_do10:
    // [11] phi (byte) do10::i#2 = (byte) 0 [phi:do10->do10::@1#0] -- vbuz1=vbuc1 
    lda #0
    sta.z i
    jmp __b1
    // [11] phi from do10::@1 to do10::@1 [phi:do10::@1->do10::@1]
  __b1_from___b1:
    // [11] phi (byte) do10::i#2 = (byte) do10::i#1 [phi:do10::@1->do10::@1#0] -- register_copy 
    jmp __b1
    // do10::@1
  __b1:
    // [12] call *((void()*) do10::fn#3) 
    jsr bi_fn
    // [13] (byte) do10::i#1 ← ++ (byte) do10::i#2 -- vbuz1=_inc_vbuz1 
    inc.z i
    // [14] if((byte) do10::i#1!=(byte) $a) goto do10::@1 -- vbuz1_neq_vbuc1_then_la1 
    lda #$a
    cmp.z i
    bne __b1_from___b1
    jmp __breturn
    // do10::@return
  __breturn:
    // [15] return 
    rts
  bi_fn:
    jmp (fn)
}
  // world
world: {
    // [17] call print 
    // [19] phi from world to print [phi:world->print]
  print_from_world:
    // [19] phi (byte*) print::msg#3 = (const byte*) world::msg [phi:world->print#0] -- pbuz1=pbuc1 
    lda #<msg
    sta.z print.msg
    lda #>msg
    sta.z print.msg+1
    jsr print
    jmp __breturn
    // world::@return
  __breturn:
    // [18] return 
    rts
    msg: .text "world "
    .byte 0
}
  // print
// print(byte* zp(5) msg)
print: {
    .label msg = 5
    // [20] phi from print to print::@1 [phi:print->print::@1]
  __b1_from_print:
    // [20] phi (byte) print::i#2 = (byte) 0 [phi:print->print::@1#0] -- vbuyy=vbuc1 
    ldy #0
    jmp __b1
    // [20] phi from print::@1 to print::@1 [phi:print::@1->print::@1]
  __b1_from___b1:
    // [20] phi (byte) print::i#2 = (byte) print::i#1 [phi:print::@1->print::@1#0] -- register_copy 
    jmp __b1
    // print::@1
  __b1:
    // [21] *((const byte*) SCREEN + (byte) idx) ← *((byte*) print::msg#3 + (byte) print::i#2) -- pbuc1_derefidx_vbuz1=pbuz2_derefidx_vbuyy 
    lda (msg),y
    ldx.z idx
    sta SCREEN,x
    // [22] (byte) idx ← ++ (byte) idx -- vbuz1=_inc_vbuz1 
    inc.z idx
    // [23] (byte) print::i#1 ← ++ (byte) print::i#2 -- vbuyy=_inc_vbuyy 
    iny
    // [24] if((byte) 0!=*((byte*) print::msg#3 + (byte) print::i#1)) goto print::@1 -- vbuc1_neq_pbuz1_derefidx_vbuyy_then_la1 
    lda (msg),y
    cmp #0
    bne __b1_from___b1
    jmp __breturn
    // print::@return
  __breturn:
    // [25] return 
    rts
}
  // hello
hello: {
    // [27] call print 
    // [19] phi from hello to print [phi:hello->print]
  print_from_hello:
    // [19] phi (byte*) print::msg#3 = (const byte*) hello::msg [phi:hello->print#0] -- pbuz1=pbuc1 
    lda #<msg
    sta.z print.msg
    lda #>msg
    sta.z print.msg+1
    jsr print
    jmp __breturn
    // hello::@return
  __breturn:
    // [28] return 
    rts
    msg: .text "hello "
    .byte 0
}
  // File Data

ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __b2
Removing instruction jmp __bend
Removing instruction jmp __b1
Removing instruction jmp __breturn
Removing instruction jmp __b1
Removing instruction jmp __breturn
Removing instruction jmp __breturn
Removing instruction jmp __b1
Removing instruction jmp __breturn
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing label __bbegin with __b1
Replacing label __b1_from___b1 with __b1
Replacing label __b1_from___b1 with __b1
Removing instruction __bbegin:
Removing instruction __b2_from___b1:
Removing instruction main_from___b2:
Removing instruction __bend_from___b2:
Removing instruction __b1_from_main:
Removing instruction do10_from___b1:
Removing instruction __b1_from___b1:
Removing instruction __b1_from___b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction __b2:
Removing instruction __bend:
Removing instruction do10_from_main:
Removing instruction __b1:
Removing instruction __breturn:
Removing instruction __b1_from_do10:
Removing instruction __breturn:
Removing instruction print_from_world:
Removing instruction __breturn:
Removing instruction __b1_from_print:
Removing instruction __breturn:
Removing instruction print_from_hello:
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Adding RTS to root block 
Succesful ASM optimization Pass5AddMainRts
Removing instruction jmp __b1
Removing instruction jmp __b1
Succesful ASM optimization Pass5NextJumpElimination

FINAL SYMBOL TABLE
(label) @1
(label) @2
(label) @begin
(label) @end
(const byte*) SCREEN = (byte*) 1024
(void()) do10((void()*) do10::fn)
(label) do10::@1
(label) do10::@return
(void()*) do10::fn
(void()*) do10::fn#3 fn zp[2]:2
(byte) do10::i
(byte) do10::i#1 i zp[1]:4 16.5
(byte) do10::i#2 i zp[1]:4 11.0
(void()) hello()
(label) hello::@return
(const byte*) hello::msg[(byte) 7]  = (byte*) "hello "
(byte) idx loadstore zp[1]:7 4.375
(void()) main()
(label) main::@1
(label) main::@return
(void()) print((byte*) print::msg)
(label) print::@1
(label) print::@return
(byte) print::i
(byte) print::i#1 reg byte y 16.5
(byte) print::i#2 reg byte y 11.0
(byte*) print::msg
(byte*) print::msg#3 msg zp[2]:5 3.6666666666666665
(void()) world()
(label) world::@return
(const byte*) world::msg[(byte) 7]  = (byte*) "world "

zp[2]:2 [ do10::fn#3 ]
zp[1]:4 [ do10::i#2 do10::i#1 ]
zp[2]:5 [ print::msg#3 ]
reg byte y [ print::i#2 print::i#1 ]
zp[1]:7 [ idx ]


FINAL ASSEMBLER
Score: 676

  // File Comments
// Tests calling into different function pointers which call a common sub-method
  // Upstart
.pc = $801 "Basic"
:BasicUpstart(__b1)
.pc = $80d "Program"
  // Global Constants & labels
  .label SCREEN = $400
  .label idx = 7
  // @begin
  // @1
__b1:
  // idx = 0
  // [1] (byte) idx ← (byte) 0 -- vbuz1=vbuc1 
  lda #0
  sta.z idx
  // [2] phi from @1 to @2 [phi:@1->@2]
  // @2
  // [3] call main 
  // [5] phi from @2 to main [phi:@2->main]
  jsr main
  rts
  // [4] phi from @2 to @end [phi:@2->@end]
  // @end
  // main
main: {
    // do10(&hello)
    // [6] call do10 
    // [10] phi from main to do10 [phi:main->do10]
    // [10] phi (void()*) do10::fn#3 = &(void()) hello() [phi:main->do10#0] -- pprz1=pprc1 
    lda #<hello
    sta.z do10.fn
    lda #>hello
    sta.z do10.fn+1
    jsr do10
    // [7] phi from main to main::@1 [phi:main->main::@1]
    // main::@1
    // do10(&world)
    // [8] call do10 
    // [10] phi from main::@1 to do10 [phi:main::@1->do10]
    // [10] phi (void()*) do10::fn#3 = &(void()) world() [phi:main::@1->do10#0] -- pprz1=pprc1 
    lda #<world
    sta.z do10.fn
    lda #>world
    sta.z do10.fn+1
    jsr do10
    // main::@return
    // }
    // [9] return 
    rts
}
  // do10
// do10(void()* zp(2) fn)
do10: {
    .label i = 4
    .label fn = 2
    // [11] phi from do10 to do10::@1 [phi:do10->do10::@1]
    // [11] phi (byte) do10::i#2 = (byte) 0 [phi:do10->do10::@1#0] -- vbuz1=vbuc1 
    lda #0
    sta.z i
    // [11] phi from do10::@1 to do10::@1 [phi:do10::@1->do10::@1]
    // [11] phi (byte) do10::i#2 = (byte) do10::i#1 [phi:do10::@1->do10::@1#0] -- register_copy 
    // do10::@1
  __b1:
    // (*fn)()
    // [12] call *((void()*) do10::fn#3) 
    jsr bi_fn
    // for( byte i: 0..9)
    // [13] (byte) do10::i#1 ← ++ (byte) do10::i#2 -- vbuz1=_inc_vbuz1 
    inc.z i
    // [14] if((byte) do10::i#1!=(byte) $a) goto do10::@1 -- vbuz1_neq_vbuc1_then_la1 
    lda #$a
    cmp.z i
    bne __b1
    // do10::@return
    // }
    // [15] return 
    rts
  bi_fn:
    jmp (fn)
}
  // world
world: {
    // print("world ")
    // [17] call print 
    // [19] phi from world to print [phi:world->print]
    // [19] phi (byte*) print::msg#3 = (const byte*) world::msg [phi:world->print#0] -- pbuz1=pbuc1 
    lda #<msg
    sta.z print.msg
    lda #>msg
    sta.z print.msg+1
    jsr print
    // world::@return
    // }
    // [18] return 
    rts
    msg: .text "world "
    .byte 0
}
  // print
// print(byte* zp(5) msg)
print: {
    .label msg = 5
    // [20] phi from print to print::@1 [phi:print->print::@1]
    // [20] phi (byte) print::i#2 = (byte) 0 [phi:print->print::@1#0] -- vbuyy=vbuc1 
    ldy #0
    // [20] phi from print::@1 to print::@1 [phi:print::@1->print::@1]
    // [20] phi (byte) print::i#2 = (byte) print::i#1 [phi:print::@1->print::@1#0] -- register_copy 
    // print::@1
  __b1:
    // SCREEN[idx++] = msg[i++]
    // [21] *((const byte*) SCREEN + (byte) idx) ← *((byte*) print::msg#3 + (byte) print::i#2) -- pbuc1_derefidx_vbuz1=pbuz2_derefidx_vbuyy 
    lda (msg),y
    ldx.z idx
    sta SCREEN,x
    // SCREEN[idx++] = msg[i++];
    // [22] (byte) idx ← ++ (byte) idx -- vbuz1=_inc_vbuz1 
    inc.z idx
    // [23] (byte) print::i#1 ← ++ (byte) print::i#2 -- vbuyy=_inc_vbuyy 
    iny
    // while(msg[i])
    // [24] if((byte) 0!=*((byte*) print::msg#3 + (byte) print::i#1)) goto print::@1 -- vbuc1_neq_pbuz1_derefidx_vbuyy_then_la1 
    lda (msg),y
    cmp #0
    bne __b1
    // print::@return
    // }
    // [25] return 
    rts
}
  // hello
hello: {
    // print("hello ")
    // [27] call print 
    // [19] phi from hello to print [phi:hello->print]
    // [19] phi (byte*) print::msg#3 = (const byte*) hello::msg [phi:hello->print#0] -- pbuz1=pbuc1 
    lda #<msg
    sta.z print.msg
    lda #>msg
    sta.z print.msg+1
    jsr print
    // hello::@return
    // }
    // [28] return 
    rts
    msg: .text "hello "
    .byte 0
}
  // File Data

