mirror of https://gitlab.com/camelot/kickc.git
403 lines
14 KiB
Plaintext
403 lines
14 KiB
Plaintext
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 popup_selector::k#0 = 0
|
|
Constant inlined opcode#13 = 'a'
|
|
Constant inlined opcode#2 = 'b'
|
|
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
|
|
|