diff --git a/src/test/ref/struct-with-huge-array.asm b/src/test/ref/struct-with-huge-array.asm new file mode 100644 index 000000000..02be66107 --- /dev/null +++ b/src/test/ref/struct-with-huge-array.asm @@ -0,0 +1,78 @@ + // Commodore 64 PRG executable file +.file [name="struct-with-huge-array.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) + .const SIZEOF_STRUCT___0 = $11a + .label SCREEN = $400 +.segment Code +main: { + .label i = 2 + .label __2 = 4 + .label __3 = 6 + // bug b + lda #<b + sta.z $fe + lda #>b + sta.z $ff + lda #0 + tay + tax + !n: + sta ($fe),y + iny + cpy #$ff + bne !+ + inc.z $ff + inx + !: + cpy #<$11a + bne !n- + cpx #>$11a + bne !n- + lda #<0 + sta.z i + sta.z i+1 + __b1: + // for(unsigned int i=0;i<sizeof b;i++) + lda.z i+1 + cmp #>$11a + bcc __b2 + bne !+ + lda.z i + cmp #<$11a + bcc __b2 + !: + // } + rts + __b2: + // SCREEN[i] = b.header[i] + lda.z i + clc + adc #<b + sta.z __2 + lda.z i+1 + adc #>b + sta.z __2+1 + lda.z i + clc + adc #<SCREEN + sta.z __3 + lda.z i+1 + adc #>SCREEN + sta.z __3+1 + ldy #0 + lda (__2),y + sta (__3),y + // for(unsigned int i=0;i<sizeof b;i++) + inc.z i + bne !+ + inc.z i+1 + !: + jmp __b1 + .segment Data + b: .fill SIZEOF_STRUCT___0, 0 +} diff --git a/src/test/ref/struct-with-huge-array.cfg b/src/test/ref/struct-with-huge-array.cfg new file mode 100644 index 000000000..94220019b --- /dev/null +++ b/src/test/ref/struct-with-huge-array.cfg @@ -0,0 +1,18 @@ + +void main() +main: scope:[main] from + [0] *(&main::b) = memset(struct $0, $11a) + to:main::@1 +main::@1: scope:[main] from main main::@2 + [1] main::i#2 = phi( main/0, main::@2/main::i#1 ) + [2] if(main::i#2<$11a) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@1 + [3] return + to:@return +main::@2: scope:[main] from main::@1 + [4] main::$2 = (char *)&main::b + main::i#2 + [5] main::$3 = SCREEN + main::i#2 + [6] *main::$3 = *main::$2 + [7] main::i#1 = ++ main::i#2 + to:main::@1 diff --git a/src/test/ref/struct-with-huge-array.log b/src/test/ref/struct-with-huge-array.log new file mode 100644 index 000000000..683660525 --- /dev/null +++ b/src/test/ref/struct-with-huge-array.log @@ -0,0 +1,392 @@ +Fixing struct type size struct $0 to 282 +Fixing struct type size struct $0 to 282 +Fixing struct type SIZE_OF struct $0 to 282 +Fixing struct type SIZE_OF struct $0 to 282 +Resolving sizeof() main::$0 = sizeof main::b +Inlined call call __init +Removing C-classic struct-unwound assignment main::b = struct-unwound {*(&main::b)} + +CONTROL FLOW GRAPH SSA + +void main() +main: scope:[main] from __start::@1 + *(&main::b) = memset(struct $0, SIZEOF_STRUCT_$0) + main::i#0 = 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + main::i#2 = phi( main/main::i#0, main::@2/main::i#1 ) + main::$0 = SIZEOF_STRUCT_$0 + main::$1 = main::i#2 < main::$0 + if(main::$1) goto main::@2 + to:main::@return +main::@2: scope:[main] from main::@1 + main::i#3 = phi( main::@1/main::i#2 ) + SCREEN[main::i#3] = ((char *)&main::b+OFFSET_STRUCT_$0_HEADER)[main::i#3] + main::i#1 = ++ main::i#3 + to:main::@1 +main::@return: scope:[main] from main::@1 + return + to:@return + +void __start() +__start: scope:[__start] from + to:__start::__init1 +__start::__init1: scope:[__start] from __start + to:__start::@1 +__start::@1: scope:[__start] from __start::__init1 + call main + to:__start::@2 +__start::@2: scope:[__start] from __start::@1 + to:__start::@return +__start::@return: scope:[__start] from __start::@2 + return + to:@return + +SYMBOL TABLE SSA +__constant char OFFSET_STRUCT_$0_HEADER = 0 +__constant char *SCREEN = (char *)$400 +__constant unsigned int SIZEOF_STRUCT_$0 = $11a +void __start() +void main() +unsigned int main::$0 +bool main::$1 +__loadstore struct $0 main::b +unsigned int main::i +unsigned int main::i#0 +unsigned int main::i#1 +unsigned int main::i#2 +unsigned int main::i#3 + +Simplifying constant pointer cast (char *) 1024 +Successful SSA optimization PassNCastSimplification +Alias main::i#2 = main::i#3 +Successful SSA optimization Pass2AliasElimination +Simple Condition main::$1 [5] if(main::i#2<main::$0) goto main::@2 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant main::i#0 = 0 +Constant main::$0 = SIZEOF_STRUCT_$0 +Successful SSA optimization Pass2ConstantIdentification +De-inlining pointer[w] to *(pointer+w) [6] SCREEN[main::i#2] = ((char *)&main::b+OFFSET_STRUCT_$0_HEADER)[main::i#2] +De-inlining pointer[w] to *(pointer+w) [6] SCREEN[main::i#2] = *main::$2 +Successful SSA optimization Pass2DeInlineWordDerefIdx +Simplifying expression containing zero (char *)&main::b in main::$2 = (char *)&main::b+OFFSET_STRUCT_$0_HEADER + main::i#2 +Successful SSA optimization PassNSimplifyExpressionWithZero +Eliminating unused constant OFFSET_STRUCT_$0_HEADER +Successful SSA optimization PassNEliminateUnusedVars +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 +Inlining constant with var siblings main::i#0 +Constant inlined SIZEOF_STRUCT_$0 = $11a +Constant inlined main::i#0 = 0 +Constant inlined main::$0 = $11a +Successful SSA optimization Pass2ConstantInlining +Finalized unsigned number type (unsigned int) $11a +Finalized unsigned number type (unsigned int) $11a +Successful SSA optimization PassNFinalizeNumberTypeConversions +CALL GRAPH + +Created 1 initial phi equivalence classes +Coalesced [8] main::i#4 = main::i#1 +Coalesced down to 1 phi equivalence classes + +FINAL CONTROL FLOW GRAPH + +void main() +main: scope:[main] from + [0] *(&main::b) = memset(struct $0, $11a) + to:main::@1 +main::@1: scope:[main] from main main::@2 + [1] main::i#2 = phi( main/0, main::@2/main::i#1 ) + [2] if(main::i#2<$11a) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@1 + [3] return + to:@return +main::@2: scope:[main] from main::@1 + [4] main::$2 = (char *)&main::b + main::i#2 + [5] main::$3 = SCREEN + main::i#2 + [6] *main::$3 = *main::$2 + [7] main::i#1 = ++ main::i#2 + to:main::@1 + + +VARIABLE REGISTER WEIGHTS +void main() +char *main::$2 // 11.0 +char *main::$3 // 22.0 +__loadstore struct $0 main::b +unsigned int main::i +unsigned int main::i#1 // 22.0 +unsigned int main::i#2 // 11.0 + +Initial phi equivalence classes +[ main::i#2 main::i#1 ] +Added variable main::$2 to live range equivalence class [ main::$2 ] +Added variable main::$3 to live range equivalence class [ main::$3 ] +Added variable main::b to live range equivalence class [ main::b ] +Complete equivalence classes +[ main::i#2 main::i#1 ] +[ main::$2 ] +[ main::$3 ] +[ main::b ] +Allocated zp[2]:2 [ main::i#2 main::i#1 ] +Allocated zp[2]:4 [ main::$2 ] +Allocated zp[2]:6 [ main::$3 ] +Zero-page exhausted. Moving allocation to main memory main::b +Allocated mem[282] [ main::b ] +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [0] *(&main::b) = memset(struct $0, $11a) [ main::b ] ( [ main::b ] { } ) always clobbers reg byte a reg byte x reg byte y +Statement [2] if(main::i#2<$11a) goto main::@2 [ main::i#2 main::b ] ( [ main::i#2 main::b ] { } ) always clobbers reg byte a +Statement [4] main::$2 = (char *)&main::b + main::i#2 [ main::i#2 main::$2 main::b ] ( [ main::i#2 main::$2 main::b ] { } ) always clobbers reg byte a +Statement [5] main::$3 = SCREEN + main::i#2 [ main::i#2 main::$2 main::b main::$3 ] ( [ main::i#2 main::$2 main::b main::$3 ] { } ) always clobbers reg byte a +Statement [6] *main::$3 = *main::$2 [ main::i#2 main::b ] ( [ main::i#2 main::b ] { } ) always clobbers reg byte a reg byte y +Potential registers zp[2]:2 [ main::i#2 main::i#1 ] : zp[2]:2 , +Potential registers zp[2]:4 [ main::$2 ] : zp[2]:4 , +Potential registers zp[2]:6 [ main::$3 ] : zp[2]:6 , +Potential registers mem[282] [ main::b ] : mem[282] , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 33: zp[2]:2 [ main::i#2 main::i#1 ] 22: zp[2]:6 [ main::$3 ] 11: zp[2]:4 [ main::$2 ] 0: mem[282] [ main::b ] +Uplift Scope [$0] +Uplift Scope [] + +Uplifting [main] best 1055 combination zp[2]:2 [ main::i#2 main::i#1 ] zp[2]:6 [ main::$3 ] zp[2]:4 [ main::$2 ] mem[282] [ main::b ] +Uplifting [$0] best 1055 combination +Uplifting [] best 1055 combination + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments + // Upstart + // Commodore 64 PRG executable file +.file [name="struct-with-huge-array.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 + .const SIZEOF_STRUCT___0 = $11a + .label SCREEN = $400 +.segment Code + // main +main: { + .label i = 2 + .label __2 = 4 + .label __3 = 6 + // [0] *(&main::b) = memset(struct $0, $11a) -- _deref_pssc1=_memset_vwuc2 + lda #<b + sta.z $fe + lda #>b + sta.z $ff + lda #0 + tay + tax + !n: + sta ($fe),y + iny + cpy #$ff + bne !+ + inc.z $ff + inx + !: + cpy #<$11a + bne !n- + cpx #>$11a + bne !n- + // [1] phi from main to main::@1 [phi:main->main::@1] + __b1_from_main: + // [1] phi main::i#2 = 0 [phi:main->main::@1#0] -- vwuz1=vwuc1 + lda #<0 + sta.z i + lda #>0 + sta.z i+1 + jmp __b1 + // main::@1 + __b1: + // [2] if(main::i#2<$11a) goto main::@2 -- vwuz1_lt_vwuc1_then_la1 + lda.z i+1 + cmp #>$11a + bcc __b2 + bne !+ + lda.z i + cmp #<$11a + bcc __b2 + !: + jmp __breturn + // main::@return + __breturn: + // [3] return + rts + // main::@2 + __b2: + // [4] main::$2 = (char *)&main::b + main::i#2 -- pbuz1=pbuc1_plus_vwuz2 + lda.z i + clc + adc #<b + sta.z __2 + lda.z i+1 + adc #>b + sta.z __2+1 + // [5] main::$3 = SCREEN + main::i#2 -- pbuz1=pbuc1_plus_vwuz2 + lda.z i + clc + adc #<SCREEN + sta.z __3 + lda.z i+1 + adc #>SCREEN + sta.z __3+1 + // [6] *main::$3 = *main::$2 -- _deref_pbuz1=_deref_pbuz2 + ldy #0 + lda (__2),y + ldy #0 + sta (__3),y + // [7] main::i#1 = ++ main::i#2 -- vwuz1=_inc_vwuz1 + inc.z i + bne !+ + inc.z i+1 + !: + // [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + __b1_from___b2: + // [1] phi main::i#2 = main::i#1 [phi:main::@2->main::@1#0] -- register_copy + jmp __b1 + .segment Data + b: .fill SIZEOF_STRUCT___0, 0 +} + // File Data + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp __b1 +Removing instruction jmp __breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction lda #>0 +Removing instruction ldy #0 +Succesful ASM optimization Pass5UnnecesaryLoadElimination +Removing instruction __b1_from_main: +Removing instruction __breturn: +Removing instruction __b1_from___b2: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +__constant char *SCREEN = (char *) 1024 +__constant unsigned int SIZEOF_STRUCT_$0 = $11a +void main() +char *main::$2 // zp[2]:4 11.0 +char *main::$3 // zp[2]:6 22.0 +__loadstore struct $0 main::b // mem[282] +unsigned int main::i +unsigned int main::i#1 // i zp[2]:2 22.0 +unsigned int main::i#2 // i zp[2]:2 11.0 + +zp[2]:2 [ main::i#2 main::i#1 ] +zp[2]:4 [ main::$2 ] +zp[2]:6 [ main::$3 ] +mem[282] [ main::b ] + + +FINAL ASSEMBLER +Score: 955 + + // File Comments + // Upstart + // Commodore 64 PRG executable file +.file [name="struct-with-huge-array.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 + .const SIZEOF_STRUCT___0 = $11a + .label SCREEN = $400 +.segment Code + // main +main: { + .label i = 2 + .label __2 = 4 + .label __3 = 6 + // bug b + // [0] *(&main::b) = memset(struct $0, $11a) -- _deref_pssc1=_memset_vwuc2 + lda #<b + sta.z $fe + lda #>b + sta.z $ff + lda #0 + tay + tax + !n: + sta ($fe),y + iny + cpy #$ff + bne !+ + inc.z $ff + inx + !: + cpy #<$11a + bne !n- + cpx #>$11a + bne !n- + // [1] phi from main to main::@1 [phi:main->main::@1] + // [1] phi main::i#2 = 0 [phi:main->main::@1#0] -- vwuz1=vwuc1 + lda #<0 + sta.z i + sta.z i+1 + // main::@1 + __b1: + // for(unsigned int i=0;i<sizeof b;i++) + // [2] if(main::i#2<$11a) goto main::@2 -- vwuz1_lt_vwuc1_then_la1 + lda.z i+1 + cmp #>$11a + bcc __b2 + bne !+ + lda.z i + cmp #<$11a + bcc __b2 + !: + // main::@return + // } + // [3] return + rts + // main::@2 + __b2: + // SCREEN[i] = b.header[i] + // [4] main::$2 = (char *)&main::b + main::i#2 -- pbuz1=pbuc1_plus_vwuz2 + lda.z i + clc + adc #<b + sta.z __2 + lda.z i+1 + adc #>b + sta.z __2+1 + // [5] main::$3 = SCREEN + main::i#2 -- pbuz1=pbuc1_plus_vwuz2 + lda.z i + clc + adc #<SCREEN + sta.z __3 + lda.z i+1 + adc #>SCREEN + sta.z __3+1 + // [6] *main::$3 = *main::$2 -- _deref_pbuz1=_deref_pbuz2 + ldy #0 + lda (__2),y + sta (__3),y + // for(unsigned int i=0;i<sizeof b;i++) + // [7] main::i#1 = ++ main::i#2 -- vwuz1=_inc_vwuz1 + inc.z i + bne !+ + inc.z i+1 + !: + // [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + // [1] phi main::i#2 = main::i#1 [phi:main::@2->main::@1#0] -- register_copy + jmp __b1 + .segment Data + b: .fill SIZEOF_STRUCT___0, 0 +} + // File Data + diff --git a/src/test/ref/struct-with-huge-array.sym b/src/test/ref/struct-with-huge-array.sym new file mode 100644 index 000000000..96e0424e1 --- /dev/null +++ b/src/test/ref/struct-with-huge-array.sym @@ -0,0 +1,14 @@ +__constant char *SCREEN = (char *) 1024 +__constant unsigned int SIZEOF_STRUCT_$0 = $11a +void main() +char *main::$2 // zp[2]:4 11.0 +char *main::$3 // zp[2]:6 22.0 +__loadstore struct $0 main::b // mem[282] +unsigned int main::i +unsigned int main::i#1 // i zp[2]:2 22.0 +unsigned int main::i#2 // i zp[2]:2 11.0 + +zp[2]:2 [ main::i#2 main::i#1 ] +zp[2]:4 [ main::$2 ] +zp[2]:6 [ main::$3 ] +mem[282] [ main::b ]