Inlined call call __init

CONTROL FLOW GRAPH SSA

void main()
main: scope:[main]  from __start::@1
  opcode#7 = phi( __start::@1/opcode#13 )
  screen[$28] = opcode#7
  call popup_selector
  to:main::@1
main::@1: scope:[main]  from main
  opcode#8 = phi( main/opcode#3 )
  opcode#0 = opcode#8
  screen[$29] = opcode#0
  to:main::@return
main::@return: scope:[main]  from main::@1
  opcode#9 = phi( main::@1/opcode#0 )
  opcode#1 = opcode#9
  return 
  to:@return

void popup_selector()
popup_selector: scope:[popup_selector]  from main
  opcode#15 = phi( main/opcode#7 )
  popup_selector::k#0 = 0
  to:popup_selector::@1
popup_selector::@1: scope:[popup_selector]  from popup_selector popup_selector::@2
  opcode#14 = phi( popup_selector/opcode#15, popup_selector::@2/opcode#2 )
  popup_selector::k#2 = phi( popup_selector/popup_selector::k#0, popup_selector::@2/popup_selector::k#1 )
  popup_selector::$0 = popup_selector::k#2 <= 2
  if(popup_selector::$0) goto popup_selector::@2
  to:popup_selector::@return
popup_selector::@2: scope:[popup_selector]  from popup_selector::@1
  popup_selector::k#3 = phi( popup_selector::@1/popup_selector::k#2 )
  opcode#2 = 'b'
  screen[popup_selector::k#3] = opcode#2
  popup_selector::k#1 = ++ popup_selector::k#3
  to:popup_selector::@1
popup_selector::@return: scope:[popup_selector]  from popup_selector::@1
  opcode#10 = phi( popup_selector::@1/opcode#14 )
  opcode#3 = opcode#10
  return 
  to:@return

void __start()
__start: scope:[__start]  from
  to:__start::__init1
__start::__init1: scope:[__start]  from __start
  opcode#4 = 'a'
  to:__start::@1
__start::@1: scope:[__start]  from __start::__init1
  opcode#13 = phi( __start::__init1/opcode#4 )
  call main
  to:__start::@2
__start::@2: scope:[__start]  from __start::@1
  opcode#11 = phi( __start::@1/opcode#1 )
  opcode#5 = opcode#11
  to:__start::@return
__start::@return: scope:[__start]  from __start::@2
  opcode#12 = phi( __start::@2/opcode#5 )
  opcode#6 = opcode#12
  return 
  to:@return

SYMBOL TABLE SSA
void __start()
void main()
char opcode
char opcode#0
char opcode#1
char opcode#10
char opcode#11
char opcode#12
char opcode#13
char opcode#14
char opcode#15
char opcode#2
char opcode#3
char opcode#4
char opcode#5
char opcode#6
char opcode#7
char opcode#8
char opcode#9
void popup_selector()
bool popup_selector::$0
char popup_selector::k
char popup_selector::k#0
char popup_selector::k#1
char popup_selector::k#2
char popup_selector::k#3
__constant char * const screen = (char *)$400

Adding number conversion cast (unumber) $28 in screen[$28] = opcode#7
Adding number conversion cast (unumber) $29 in screen[$29] = opcode#0
Adding number conversion cast (unumber) 2 in popup_selector::$0 = popup_selector::k#2 <= 2
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant pointer cast (char *) 1024
Simplifying constant integer cast $28
Simplifying constant integer cast $29
Simplifying constant integer cast 2
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (char) $28
Finalized unsigned number type (char) $29
Finalized unsigned number type (char) 2
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias opcode#0 = opcode#8 opcode#9 opcode#1 
Alias popup_selector::k#2 = popup_selector::k#3 
Alias opcode#10 = opcode#14 opcode#3 
Alias opcode#13 = opcode#4 
Alias opcode#11 = opcode#5 opcode#12 opcode#6 
Successful SSA optimization Pass2AliasElimination
Identical Phi Values opcode#7 opcode#13
Identical Phi Values opcode#0 opcode#10
Identical Phi Values opcode#15 opcode#7
Identical Phi Values opcode#11 opcode#0
Successful SSA optimization Pass2IdenticalPhiElimination
Simple Condition popup_selector::$0 [10] if(popup_selector::k#2<=2) goto popup_selector::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant popup_selector::k#0 = 0
Constant opcode#2 = 'b'
Constant opcode#13 = 'a'
Successful SSA optimization Pass2ConstantIdentification
Rewriting conditional comparison [10] if(popup_selector::k#2<=2) goto popup_selector::@2
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::__init1
Removing unused procedure block __start::@1
Removing unused procedure block __start::@2
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Adding number conversion cast (unumber) 2+1 in [5] if(popup_selector::k#2<2+1) goto popup_selector::@2
Adding number conversion cast (unumber) 1 in [5] if(popup_selector::k#2<(unumber)2+1) goto popup_selector::@2
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant integer cast 2+(unumber)1
Simplifying constant integer cast 1
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (char) 1
Successful SSA optimization PassNFinalizeNumberTypeConversions
Inlining constant with var siblings popup_selector::k#0
Inlining constant with var siblings opcode#2
Inlining constant with var siblings opcode#13
Constant inlined opcode#2 = 'b'
Constant inlined popup_selector::k#0 = 0
Constant inlined opcode#13 = 'a'
Successful SSA optimization Pass2ConstantInlining
Consolidated array index constant in *(screen+$28)
Consolidated array index constant in *(screen+$29)
Successful SSA optimization Pass2ConstantAdditionElimination
Adding NOP phi() at start of popup_selector
CALL GRAPH
Calls in [main] to popup_selector:1 

Created 2 initial phi equivalence classes
Coalesced [10] popup_selector::k#4 = popup_selector::k#1
Coalesced down to 2 phi equivalence classes
Adding NOP phi() at start of popup_selector

FINAL CONTROL FLOW GRAPH

void main()
main: scope:[main]  from
  [0] *(screen+$28) = 'a'
  [1] call popup_selector
  to:main::@1
main::@1: scope:[main]  from main
  [2] *(screen+$29) = opcode#10
  to:main::@return
main::@return: scope:[main]  from main::@1
  [3] return 
  to:@return

void popup_selector()
popup_selector: scope:[popup_selector]  from main
  [4] phi()
  to:popup_selector::@1
popup_selector::@1: scope:[popup_selector]  from popup_selector popup_selector::@2
  [5] opcode#10 = phi( popup_selector/'a', popup_selector::@2/'b' )
  [5] popup_selector::k#2 = phi( popup_selector/0, popup_selector::@2/popup_selector::k#1 )
  [6] if(popup_selector::k#2<2+1) goto popup_selector::@2
  to:popup_selector::@return
popup_selector::@return: scope:[popup_selector]  from popup_selector::@1
  [7] return 
  to:@return
popup_selector::@2: scope:[popup_selector]  from popup_selector::@1
  [8] screen[popup_selector::k#2] = 'b'
  [9] popup_selector::k#1 = ++ popup_selector::k#2
  to:popup_selector::@1


VARIABLE REGISTER WEIGHTS
void main()
char opcode
char opcode#10 // 0.5
void popup_selector()
char popup_selector::k
char popup_selector::k#1 // 202.0
char popup_selector::k#2 // 134.66666666666666

Initial phi equivalence classes
[ popup_selector::k#2 popup_selector::k#1 ]
[ opcode#10 ]
Complete equivalence classes
[ popup_selector::k#2 popup_selector::k#1 ]
[ opcode#10 ]
Allocated zp[1]:2 [ popup_selector::k#2 popup_selector::k#1 ]
Allocated zp[1]:3 [ opcode#10 ]
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] *(screen+$28) = 'a' [ ] (  [ ] { }  ) always clobbers reg byte a 
Statement [8] screen[popup_selector::k#2] = 'b' [ popup_selector::k#2 ] ( popup_selector:1 [ popup_selector::k#2 ] { }  ) always clobbers reg byte a 
Removing always clobbered register reg byte a as potential for zp[1]:2 [ popup_selector::k#2 popup_selector::k#1 ]
Statement [0] *(screen+$28) = 'a' [ ] (  [ ] { }  ) always clobbers reg byte a 
Statement [8] screen[popup_selector::k#2] = 'b' [ popup_selector::k#2 ] ( popup_selector:1 [ popup_selector::k#2 ] { }  ) always clobbers reg byte a 
Potential registers zp[1]:2 [ popup_selector::k#2 popup_selector::k#1 ] : zp[1]:2 , reg byte x , reg byte y , 
Potential registers zp[1]:3 [ opcode#10 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y , 

REGISTER UPLIFT SCOPES
Uplift Scope [popup_selector] 336.67: zp[1]:2 [ popup_selector::k#2 popup_selector::k#1 ] 
Uplift Scope [] 0.5: zp[1]:3 [ opcode#10 ] 
Uplift Scope [main] 

Uplifting [popup_selector] best 382 combination reg byte x [ popup_selector::k#2 popup_selector::k#1 ] 
Uplifting [] best 319 combination reg byte a [ opcode#10 ] 
Uplifting [main] best 319 combination 

ASSEMBLER BEFORE OPTIMIZATION
  // File Comments
// Demonstrates a problem where constant loophead unrolling results in an error
// The result is a NullPointerException
// The cause is that the Unroller does not handle the variable opcode correctly.
// The Unroller gets the verwions for opcode wrong because it misses the fact that it is modified inside call to popup_selector()
  // Upstart
  // Commodore 64 PRG executable file
.file [name="loophead-problem.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
  // Global Constants & labels
  .label screen = $400
.segment Code
  // main
// Offending unroll variable
main: {
    // [0] *(screen+$28) = 'a' -- _deref_pbuc1=vbuc2 
    lda #'a'
    sta screen+$28
    // [1] call popup_selector
    // [4] phi from main to popup_selector [phi:main->popup_selector]
  popup_selector_from_main:
    jsr popup_selector
    jmp __b1
    // main::@1
  __b1:
    // [2] *(screen+$29) = opcode#10 -- _deref_pbuc1=vbuaa 
    sta screen+$29
    jmp __breturn
    // main::@return
  __breturn:
    // [3] return 
    rts
}
  // popup_selector
popup_selector: {
    // [5] phi from popup_selector to popup_selector::@1 [phi:popup_selector->popup_selector::@1]
  __b1_from_popup_selector:
    // [5] phi opcode#10 = 'a' [phi:popup_selector->popup_selector::@1#0] -- vbuaa=vbuc1 
    lda #'a'
    // [5] phi popup_selector::k#2 = 0 [phi:popup_selector->popup_selector::@1#1] -- vbuxx=vbuc1 
    ldx #0
    jmp __b1
    // popup_selector::@1
  __b1:
    // [6] if(popup_selector::k#2<2+1) goto popup_selector::@2 -- vbuxx_lt_vbuc1_then_la1 
    cpx #2+1
    bcc __b2
    jmp __breturn
    // popup_selector::@return
  __breturn:
    // [7] return 
    rts
    // popup_selector::@2
  __b2:
    // [8] screen[popup_selector::k#2] = 'b' -- pbuc1_derefidx_vbuxx=vbuc2 
    lda #'b'
    sta screen,x
    // [9] popup_selector::k#1 = ++ popup_selector::k#2 -- vbuxx=_inc_vbuxx 
    inx
    // [5] phi from popup_selector::@2 to popup_selector::@1 [phi:popup_selector::@2->popup_selector::@1]
  __b1_from___b2:
    // [5] phi opcode#10 = 'b' [phi:popup_selector::@2->popup_selector::@1#0] -- vbuaa=vbuc1 
    lda #'b'
    // [5] phi popup_selector::k#2 = popup_selector::k#1 [phi:popup_selector::@2->popup_selector::@1#1] -- register_copy 
    jmp __b1
}
  // File Data

ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __breturn
Removing instruction jmp __b1
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction popup_selector_from_main:
Removing instruction __b1:
Removing instruction __breturn:
Removing instruction __b1_from_popup_selector:
Removing instruction __breturn:
Removing instruction __b1_from___b2:
Succesful ASM optimization Pass5UnusedLabelElimination
Removing instruction lda #'b'
Succesful ASM optimization Pass5UnnecesaryLoadElimination

FINAL SYMBOL TABLE
void main()
char opcode
char opcode#10 // reg byte a 0.5
void popup_selector()
char popup_selector::k
char popup_selector::k#1 // reg byte x 202.0
char popup_selector::k#2 // reg byte x 134.66666666666666
__constant char * const screen = (char *) 1024

reg byte x [ popup_selector::k#2 popup_selector::k#1 ]
reg byte a [ opcode#10 ]


FINAL ASSEMBLER
Score: 233

  // File Comments
// Demonstrates a problem where constant loophead unrolling results in an error
// The result is a NullPointerException
// The cause is that the Unroller does not handle the variable opcode correctly.
// The Unroller gets the verwions for opcode wrong because it misses the fact that it is modified inside call to popup_selector()
  // Upstart
  // Commodore 64 PRG executable file
.file [name="loophead-problem.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
  // Global Constants & labels
  .label screen = $400
.segment Code
  // main
// Offending unroll variable
main: {
    // screen[40] = opcode
    // [0] *(screen+$28) = 'a' -- _deref_pbuc1=vbuc2 
    lda #'a'
    sta screen+$28
    // popup_selector()
    // [1] call popup_selector
    // [4] phi from main to popup_selector [phi:main->popup_selector]
    jsr popup_selector
    // main::@1
    // screen[41] = opcode
    // [2] *(screen+$29) = opcode#10 -- _deref_pbuc1=vbuaa 
    sta screen+$29
    // main::@return
    // }
    // [3] return 
    rts
}
  // popup_selector
popup_selector: {
    // [5] phi from popup_selector to popup_selector::@1 [phi:popup_selector->popup_selector::@1]
    // [5] phi opcode#10 = 'a' [phi:popup_selector->popup_selector::@1#0] -- vbuaa=vbuc1 
    lda #'a'
    // [5] phi popup_selector::k#2 = 0 [phi:popup_selector->popup_selector::@1#1] -- vbuxx=vbuc1 
    ldx #0
    // popup_selector::@1
  __b1:
    // for (byte k = 0; k <= 2; k++)
    // [6] if(popup_selector::k#2<2+1) goto popup_selector::@2 -- vbuxx_lt_vbuc1_then_la1 
    cpx #2+1
    bcc __b2
    // popup_selector::@return
    // }
    // [7] return 
    rts
    // popup_selector::@2
  __b2:
    // screen[k] = opcode
    // [8] screen[popup_selector::k#2] = 'b' -- pbuc1_derefidx_vbuxx=vbuc2 
    lda #'b'
    sta screen,x
    // for (byte k = 0; k <= 2; k++)
    // [9] popup_selector::k#1 = ++ popup_selector::k#2 -- vbuxx=_inc_vbuxx 
    inx
    // [5] phi from popup_selector::@2 to popup_selector::@1 [phi:popup_selector::@2->popup_selector::@1]
    // [5] phi opcode#10 = 'b' [phi:popup_selector::@2->popup_selector::@1#0] -- vbuaa=vbuc1 
    // [5] phi popup_selector::k#2 = popup_selector::k#1 [phi:popup_selector::@2->popup_selector::@1#1] -- register_copy 
    jmp __b1
}
  // File Data

