diff --git a/src/main/fragment/pbuc1_derefidx_vwuz1=pbuc2_derefidx_vwuz2.asm b/src/main/fragment/pbuc1_derefidx_vwuz1=pbuc2_derefidx_vwuz2.asm new file mode 100644 index 000000000..2b7c64c4d --- /dev/null +++ b/src/main/fragment/pbuc1_derefidx_vwuz1=pbuc2_derefidx_vwuz2.asm @@ -0,0 +1,16 @@ +lda #<{c1} +clc +adc {z1} +sta !a1+ +1 +lda #>{c1} +adc {z1}+1 +sta !a1+ +2 +lda #<{c2} +clc +adc {z2} +sta !a2+ +1 +lda #>{c2} +adc {z2}+1 +sta !a2+ +2 +!a2: lda {c2} +!a1: sta {c1} diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 3ed4cd61b..8e6cfed54 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -44,6 +44,11 @@ public class TestPrograms { AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false); } + @Test + public void testWordsizeArrays() throws IOException, URISyntaxException { + compileAndCompare("test-word-size-arrays"); + } + @Test public void testRuntimeUnusedProcedure() throws IOException, URISyntaxException { compileAndCompare("runtime-unused-procedure"); diff --git a/src/test/kc/test-word-size-arrays.kc b/src/test/kc/test-word-size-arrays.kc new file mode 100644 index 000000000..3a3e3dd7e --- /dev/null +++ b/src/test/kc/test-word-size-arrays.kc @@ -0,0 +1,13 @@ +void main() +{ + byte* screen = $400; + word line; + for (line = 0; line < 40*24; line += 40) { + for (byte c=0; c<40; ++c) + screen[line+c] = screen[line+c+40]; + } + + // Cleare the bottom line + for (c=0; c<40; ++c) + screen[line+c] = ' '; +} diff --git a/src/test/ref/test-word-size-arrays.asm b/src/test/ref/test-word-size-arrays.asm new file mode 100644 index 000000000..ea7b119e1 --- /dev/null +++ b/src/test/ref/test-word-size-arrays.asm @@ -0,0 +1,88 @@ +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +main: { + .label screen = $400 + .label _0 = 4 + .label _2 = 6 + .label _6 = 4 + .label line = 2 + lda #<0 + sta line + sta line+1 + b1: + ldx #0 + b2: + txa + clc + adc line + sta _0 + lda #0 + adc line+1 + sta _0+1 + txa + clc + adc line + sta _2 + lda #0 + adc line+1 + sta _2+1 + lda #screen + adc _0+1 + sta !a1++2 + lda #screen+$28 + adc _2+1 + sta !a2++2 + !a2: + lda screen+$28 + !a1: + sta screen + inx + cpx #$28 + bcc b2 + clc + lda line + adc #<$28 + sta line + lda line+1 + adc #>$28 + sta line+1 + cmp #>$28*$18 + bcc b1 + bne !+ + lda line + cmp #<$28*$18 + bcc b1 + !: + ldx #0 + b3: + txa + clc + adc line + sta _6 + lda #0 + adc line+1 + sta _6+1 + lda #screen + adc _6+1 + sta !++2 + lda #' ' + !: + sta screen + inx + cpx #$28 + bcc b3 + rts +} diff --git a/src/test/ref/test-word-size-arrays.cfg b/src/test/ref/test-word-size-arrays.cfg new file mode 100644 index 000000000..5eeb556d1 --- /dev/null +++ b/src/test/ref/test-word-size-arrays.cfg @@ -0,0 +1,37 @@ +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] phi() + to:main::@1 +main::@1: scope:[main] from main main::@4 + [5] (word) main::line#5 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@4/(word) main::line#1 ) + to:main::@2 +main::@2: scope:[main] from main::@1 main::@2 + [6] (byte) main::c#4 ← phi( main::@1/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@2/(byte) main::c#1 ) + [7] (word~) main::$0 ← (word) main::line#5 + (byte) main::c#4 + [8] (word~) main::$2 ← (word) main::line#5 + (byte) main::c#4 + [9] *((const byte*) main::screen#0 + (word~) main::$0) ← *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 40 + (word~) main::$2) + [10] (byte) main::c#1 ← ++ (byte) main::c#4 + [11] if((byte) main::c#1<(byte/signed byte/word/signed word/dword/signed dword) 40) goto main::@2 + to:main::@4 +main::@4: scope:[main] from main::@2 + [12] (word) main::line#1 ← (word) main::line#5 + (byte/signed byte/word/signed word/dword/signed dword) 40 + [13] if((word) main::line#1<(byte/signed byte/word/signed word/dword/signed dword) 40*(byte/signed byte/word/signed word/dword/signed dword) 24) goto main::@1 + to:main::@3 +main::@3: scope:[main] from main::@3 main::@4 + [14] (byte) main::c#5 ← phi( main::@3/(byte) main::c#3 main::@4/(byte/signed byte/word/signed word/dword/signed dword) 0 ) + [15] (word~) main::$6 ← (word) main::line#1 + (byte) main::c#5 + [16] *((const byte*) main::screen#0 + (word~) main::$6) ← (byte) ' ' + [17] (byte) main::c#3 ← ++ (byte) main::c#5 + [18] if((byte) main::c#3<(byte/signed byte/word/signed word/dword/signed dword) 40) goto main::@3 + to:main::@return +main::@return: scope:[main] from main::@3 + [19] return + to:@return diff --git a/src/test/ref/test-word-size-arrays.log b/src/test/ref/test-word-size-arrays.log new file mode 100644 index 000000000..9952e1bc3 --- /dev/null +++ b/src/test/ref/test-word-size-arrays.log @@ -0,0 +1,801 @@ + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (byte*) main::screen#0 ← ((byte*)) (word/signed word/dword/signed dword) 1024 + (word) main::line#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 + to:main::@1 +main::@1: scope:[main] from main main::@4 + (byte*) main::screen#3 ← phi( main/(byte*) main::screen#0 main::@4/(byte*) main::screen#5 ) + (word) main::line#5 ← phi( main/(word) main::line#0 main::@4/(word) main::line#1 ) + (byte) main::c#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 + to:main::@2 +main::@2: scope:[main] from main::@1 main::@2 + (byte*) main::screen#1 ← phi( main::@1/(byte*) main::screen#3 main::@2/(byte*) main::screen#1 ) + (byte) main::c#4 ← phi( main::@1/(byte) main::c#0 main::@2/(byte) main::c#1 ) + (word) main::line#2 ← phi( main::@1/(word) main::line#5 main::@2/(word) main::line#2 ) + (word~) main::$0 ← (word) main::line#2 + (byte) main::c#4 + (word~) main::$1 ← (word) main::line#2 + (byte) main::c#4 + (word/signed dword/dword~) main::$2 ← (word~) main::$1 + (byte/signed byte/word/signed word/dword/signed dword) 40 + *((byte*) main::screen#1 + (word~) main::$0) ← *((byte*) main::screen#1 + (word/signed dword/dword~) main::$2) + (byte) main::c#1 ← ++ (byte) main::c#4 + (bool~) main::$3 ← (byte) main::c#1 < (byte/signed byte/word/signed word/dword/signed dword) 40 + if((bool~) main::$3) goto main::@2 + to:main::@4 +main::@4: scope:[main] from main::@2 + (byte*) main::screen#5 ← phi( main::@2/(byte*) main::screen#1 ) + (word) main::line#3 ← phi( main::@2/(word) main::line#2 ) + (word) main::line#1 ← (word) main::line#3 + (byte/signed byte/word/signed word/dword/signed dword) 40 + (word/signed word/dword/signed dword~) main::$4 ← (byte/signed byte/word/signed word/dword/signed dword) 40 * (byte/signed byte/word/signed word/dword/signed dword) 24 + (bool~) main::$5 ← (word) main::line#1 < (word/signed word/dword/signed dword~) main::$4 + if((bool~) main::$5) goto main::@1 + to:main::@5 +main::@5: scope:[main] from main::@4 + (byte*) main::screen#4 ← phi( main::@4/(byte*) main::screen#5 ) + (word) main::line#6 ← phi( main::@4/(word) main::line#1 ) + (byte) main::c#2 ← (byte/signed byte/word/signed word/dword/signed dword) 0 + to:main::@3 +main::@3: scope:[main] from main::@3 main::@5 + (byte*) main::screen#2 ← phi( main::@3/(byte*) main::screen#2 main::@5/(byte*) main::screen#4 ) + (byte) main::c#5 ← phi( main::@3/(byte) main::c#3 main::@5/(byte) main::c#2 ) + (word) main::line#4 ← phi( main::@3/(word) main::line#4 main::@5/(word) main::line#6 ) + (word~) main::$6 ← (word) main::line#4 + (byte) main::c#5 + *((byte*) main::screen#2 + (word~) main::$6) ← (byte) ' ' + (byte) main::c#3 ← ++ (byte) main::c#5 + (bool~) main::$7 ← (byte) main::c#3 < (byte/signed byte/word/signed word/dword/signed dword) 40 + if((bool~) main::$7) goto main::@3 + to:main::@return +main::@return: scope:[main] from main::@3 + return + to:@return +@1: scope:[] from @begin + call main + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @begin +(label) @end +(void()) main() +(word~) main::$0 +(word~) main::$1 +(word/signed dword/dword~) main::$2 +(bool~) main::$3 +(word/signed word/dword/signed dword~) main::$4 +(bool~) main::$5 +(word~) main::$6 +(bool~) main::$7 +(label) main::@1 +(label) main::@2 +(label) main::@3 +(label) main::@4 +(label) main::@5 +(label) main::@return +(byte) main::c +(byte) main::c#0 +(byte) main::c#1 +(byte) main::c#2 +(byte) main::c#3 +(byte) main::c#4 +(byte) main::c#5 +(word) main::line +(word) main::line#0 +(word) main::line#1 +(word) main::line#2 +(word) main::line#3 +(word) main::line#4 +(word) main::line#5 +(word) main::line#6 +(byte*) main::screen +(byte*) main::screen#0 +(byte*) main::screen#1 +(byte*) main::screen#2 +(byte*) main::screen#3 +(byte*) main::screen#4 +(byte*) main::screen#5 + +Culled Empty Block (label) @2 +Successful SSA optimization Pass2CullEmptyBlocks +Alias (word) main::line#2 = (word) main::line#3 +Alias (byte*) main::screen#1 = (byte*) main::screen#5 (byte*) main::screen#4 +Alias (word) main::line#1 = (word) main::line#6 +Successful SSA optimization Pass2AliasElimination +Self Phi Eliminated (word) main::line#2 +Self Phi Eliminated (byte*) main::screen#1 +Self Phi Eliminated (word) main::line#4 +Self Phi Eliminated (byte*) main::screen#2 +Successful SSA optimization Pass2SelfPhiElimination +Redundant Phi (word) main::line#2 (word) main::line#5 +Redundant Phi (byte*) main::screen#1 (byte*) main::screen#3 +Redundant Phi (word) main::line#4 (word) main::line#1 +Redundant Phi (byte*) main::screen#2 (byte*) main::screen#1 +Successful SSA optimization Pass2RedundantPhiElimination +Simple Condition (bool~) main::$3 [11] if((byte) main::c#1<(byte/signed byte/word/signed word/dword/signed dword) 40) goto main::@2 +Simple Condition (bool~) main::$5 [16] if((word) main::line#1<(word/signed word/dword/signed dword~) main::$4) goto main::@1 +Simple Condition (bool~) main::$7 [24] if((byte) main::c#3<(byte/signed byte/word/signed word/dword/signed dword) 40) goto main::@3 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant (const byte*) main::screen#0 = ((byte*))1024 +Constant (const word) main::line#0 = 0 +Constant (const byte) main::c#0 = 0 +Constant (const word/signed word/dword/signed dword) main::$4 = 40*24 +Constant (const byte) main::c#2 = 0 +Successful SSA optimization Pass2ConstantIdentification +Culled Empty Block (label) main::@5 +Successful SSA optimization Pass2CullEmptyBlocks +Self Phi Eliminated (byte*) main::screen#3 +Successful SSA optimization Pass2SelfPhiElimination +Redundant Phi (byte*) main::screen#3 (const byte*) main::screen#0 +Successful SSA optimization Pass2RedundantPhiElimination +Consolidated array index constant in assignment *(main::screen#0+40 + main::$2) +Successful SSA optimization Pass2ConstantAdditionElimination +Inferred type updated to word in [4] (word/signed dword/dword~) main::$2 ← (word~) main::$1 +Alias (word~) main::$2 = (word~) main::$1 +Successful SSA optimization Pass2AliasElimination +Inlining constant with var siblings (const word) main::line#0 +Inlining constant with var siblings (const byte) main::c#0 +Inlining constant with var siblings (const byte) main::c#2 +Constant inlined main::c#0 = (byte/signed byte/word/signed word/dword/signed dword) 0 +Constant inlined main::$4 = (byte/signed byte/word/signed word/dword/signed dword) 40*(byte/signed byte/word/signed word/dword/signed dword) 24 +Constant inlined main::line#0 = (byte/signed byte/word/signed word/dword/signed dword) 0 +Constant inlined main::c#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 +Successful SSA optimization Pass2ConstantInlining +Added new block during phi lifting main::@7(between main::@4 and main::@1) +Added new block during phi lifting main::@8(between main::@2 and main::@2) +Added new block during phi lifting main::@9(between main::@3 and main::@3) +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +CALL GRAPH +Calls in [] to main:2 + +Created 3 initial phi equivalence classes +Coalesced [20] main::c#7 ← main::c#3 +Coalesced [21] main::line#7 ← main::line#1 +Coalesced [22] main::c#6 ← main::c#1 +Coalesced down to 3 phi equivalence classes +Culled Empty Block (label) main::@9 +Culled Empty Block (label) main::@7 +Culled Empty Block (label) main::@8 +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] phi() + to:main::@1 +main::@1: scope:[main] from main main::@4 + [5] (word) main::line#5 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@4/(word) main::line#1 ) + to:main::@2 +main::@2: scope:[main] from main::@1 main::@2 + [6] (byte) main::c#4 ← phi( main::@1/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@2/(byte) main::c#1 ) + [7] (word~) main::$0 ← (word) main::line#5 + (byte) main::c#4 + [8] (word~) main::$2 ← (word) main::line#5 + (byte) main::c#4 + [9] *((const byte*) main::screen#0 + (word~) main::$0) ← *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 40 + (word~) main::$2) + [10] (byte) main::c#1 ← ++ (byte) main::c#4 + [11] if((byte) main::c#1<(byte/signed byte/word/signed word/dword/signed dword) 40) goto main::@2 + to:main::@4 +main::@4: scope:[main] from main::@2 + [12] (word) main::line#1 ← (word) main::line#5 + (byte/signed byte/word/signed word/dword/signed dword) 40 + [13] if((word) main::line#1<(byte/signed byte/word/signed word/dword/signed dword) 40*(byte/signed byte/word/signed word/dword/signed dword) 24) goto main::@1 + to:main::@3 +main::@3: scope:[main] from main::@3 main::@4 + [14] (byte) main::c#5 ← phi( main::@3/(byte) main::c#3 main::@4/(byte/signed byte/word/signed word/dword/signed dword) 0 ) + [15] (word~) main::$6 ← (word) main::line#1 + (byte) main::c#5 + [16] *((const byte*) main::screen#0 + (word~) main::$6) ← (byte) ' ' + [17] (byte) main::c#3 ← ++ (byte) main::c#5 + [18] if((byte) main::c#3<(byte/signed byte/word/signed word/dword/signed dword) 40) goto main::@3 + to:main::@return +main::@return: scope:[main] from main::@3 + [19] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(word~) main::$0 101.0 +(word~) main::$2 202.0 +(word~) main::$6 22.0 +(byte) main::c +(byte) main::c#1 151.5 +(byte) main::c#3 16.5 +(byte) main::c#4 101.0 +(byte) main::c#5 11.0 +(word) main::line +(word) main::line#1 6.285714285714286 +(word) main::line#5 32.0 +(byte*) main::screen + +Initial phi equivalence classes +[ main::line#5 main::line#1 ] +[ main::c#4 main::c#1 ] +[ main::c#5 main::c#3 ] +Added variable main::$0 to zero page equivalence class [ main::$0 ] +Added variable main::$2 to zero page equivalence class [ main::$2 ] +Added variable main::$6 to zero page equivalence class [ main::$6 ] +Complete equivalence classes +[ main::line#5 main::line#1 ] +[ main::c#4 main::c#1 ] +[ main::c#5 main::c#3 ] +[ main::$0 ] +[ main::$2 ] +[ main::$6 ] +Allocated zp ZP_WORD:2 [ main::line#5 main::line#1 ] +Allocated zp ZP_BYTE:4 [ main::c#4 main::c#1 ] +Allocated zp ZP_BYTE:5 [ main::c#5 main::c#3 ] +Allocated zp ZP_WORD:6 [ main::$0 ] +Allocated zp ZP_WORD:8 [ main::$2 ] +Allocated zp ZP_WORD:10 [ main::$6 ] + +INITIAL ASM +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG1 Global Constants & labels +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG4 @1 +b1: +//SEG5 [2] call main +//SEG6 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .label screen = $400 + .label _0 = 6 + .label _2 = 8 + .label _6 = $a + .label c = 4 + .label line = 2 + .label c_3 = 5 + .label c_5 = 5 + //SEG10 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG11 [5] phi (word) main::line#5 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vwuz1=vbuc1 + lda #<0 + sta line + lda #>0 + sta line+1 + jmp b1 + //SEG12 [5] phi from main::@4 to main::@1 [phi:main::@4->main::@1] + b1_from_b4: + //SEG13 [5] phi (word) main::line#5 = (word) main::line#1 [phi:main::@4->main::@1#0] -- register_copy + jmp b1 + //SEG14 main::@1 + b1: + //SEG15 [6] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + b2_from_b1: + //SEG16 [6] phi (byte) main::c#4 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main::@1->main::@2#0] -- vbuz1=vbuc1 + lda #0 + sta c + jmp b2 + //SEG17 [6] phi from main::@2 to main::@2 [phi:main::@2->main::@2] + b2_from_b2: + //SEG18 [6] phi (byte) main::c#4 = (byte) main::c#1 [phi:main::@2->main::@2#0] -- register_copy + jmp b2 + //SEG19 main::@2 + b2: + //SEG20 [7] (word~) main::$0 ← (word) main::line#5 + (byte) main::c#4 -- vwuz1=vwuz2_plus_vbuz3 + lda c + clc + adc line + sta _0 + lda #0 + adc line+1 + sta _0+1 + //SEG21 [8] (word~) main::$2 ← (word) main::line#5 + (byte) main::c#4 -- vwuz1=vwuz2_plus_vbuz3 + lda c + clc + adc line + sta _2 + lda #0 + adc line+1 + sta _2+1 + //SEG22 [9] *((const byte*) main::screen#0 + (word~) main::$0) ← *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 40 + (word~) main::$2) -- pbuc1_derefidx_vwuz1=pbuc2_derefidx_vwuz2 + lda #screen + adc _0+1 + sta !a1++2 + lda #screen+$28 + adc _2+1 + sta !a2++2 + !a2: + lda screen+$28 + !a1: + sta screen + //SEG23 [10] (byte) main::c#1 ← ++ (byte) main::c#4 -- vbuz1=_inc_vbuz1 + inc c + //SEG24 [11] if((byte) main::c#1<(byte/signed byte/word/signed word/dword/signed dword) 40) goto main::@2 -- vbuz1_lt_vbuc1_then_la1 + lda c + cmp #$28 + bcc b2_from_b2 + jmp b4 + //SEG25 main::@4 + b4: + //SEG26 [12] (word) main::line#1 ← (word) main::line#5 + (byte/signed byte/word/signed word/dword/signed dword) 40 -- vwuz1=vwuz1_plus_vbuc1 + clc + lda line + adc #<$28 + sta line + lda line+1 + adc #>$28 + sta line+1 + //SEG27 [13] if((word) main::line#1<(byte/signed byte/word/signed word/dword/signed dword) 40*(byte/signed byte/word/signed word/dword/signed dword) 24) goto main::@1 -- vwuz1_lt_vwuc1_then_la1 + lda line+1 + cmp #>$28*$18 + bcc b1_from_b4 + bne !+ + lda line + cmp #<$28*$18 + bcc b1_from_b4 + !: + //SEG28 [14] phi from main::@4 to main::@3 [phi:main::@4->main::@3] + b3_from_b4: + //SEG29 [14] phi (byte) main::c#5 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main::@4->main::@3#0] -- vbuz1=vbuc1 + lda #0 + sta c_5 + jmp b3 + //SEG30 [14] phi from main::@3 to main::@3 [phi:main::@3->main::@3] + b3_from_b3: + //SEG31 [14] phi (byte) main::c#5 = (byte) main::c#3 [phi:main::@3->main::@3#0] -- register_copy + jmp b3 + //SEG32 main::@3 + b3: + //SEG33 [15] (word~) main::$6 ← (word) main::line#1 + (byte) main::c#5 -- vwuz1=vwuz2_plus_vbuz3 + lda c_5 + clc + adc line + sta _6 + lda #0 + adc line+1 + sta _6+1 + //SEG34 [16] *((const byte*) main::screen#0 + (word~) main::$6) ← (byte) ' ' -- pbuc1_derefidx_vwuz1=vbuc2 + lda #screen + adc _6+1 + sta !++2 + lda #' ' + !: + sta screen + //SEG35 [17] (byte) main::c#3 ← ++ (byte) main::c#5 -- vbuz1=_inc_vbuz1 + inc c_3 + //SEG36 [18] if((byte) main::c#3<(byte/signed byte/word/signed word/dword/signed dword) 40) goto main::@3 -- vbuz1_lt_vbuc1_then_la1 + lda c_3 + cmp #$28 + bcc b3_from_b3 + jmp breturn + //SEG37 main::@return + breturn: + //SEG38 [19] return + rts +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [7] (word~) main::$0 ← (word) main::line#5 + (byte) main::c#4 [ main::line#5 main::c#4 main::$0 ] ( main:2 [ main::line#5 main::c#4 main::$0 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ main::c#4 main::c#1 ] +Statement [8] (word~) main::$2 ← (word) main::line#5 + (byte) main::c#4 [ main::line#5 main::c#4 main::$0 main::$2 ] ( main:2 [ main::line#5 main::c#4 main::$0 main::$2 ] ) always clobbers reg byte a +Statement [9] *((const byte*) main::screen#0 + (word~) main::$0) ← *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 40 + (word~) main::$2) [ main::line#5 main::c#4 ] ( main:2 [ main::line#5 main::c#4 ] ) always clobbers reg byte a +Statement [12] (word) main::line#1 ← (word) main::line#5 + (byte/signed byte/word/signed word/dword/signed dword) 40 [ main::line#1 ] ( main:2 [ main::line#1 ] ) always clobbers reg byte a +Statement [13] if((word) main::line#1<(byte/signed byte/word/signed word/dword/signed dword) 40*(byte/signed byte/word/signed word/dword/signed dword) 24) goto main::@1 [ main::line#1 ] ( main:2 [ main::line#1 ] ) always clobbers reg byte a +Statement [15] (word~) main::$6 ← (word) main::line#1 + (byte) main::c#5 [ main::line#1 main::c#5 main::$6 ] ( main:2 [ main::line#1 main::c#5 main::$6 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:5 [ main::c#5 main::c#3 ] +Statement [16] *((const byte*) main::screen#0 + (word~) main::$6) ← (byte) ' ' [ main::line#1 main::c#5 ] ( main:2 [ main::line#1 main::c#5 ] ) always clobbers reg byte a +Statement [7] (word~) main::$0 ← (word) main::line#5 + (byte) main::c#4 [ main::line#5 main::c#4 main::$0 ] ( main:2 [ main::line#5 main::c#4 main::$0 ] ) always clobbers reg byte a +Statement [8] (word~) main::$2 ← (word) main::line#5 + (byte) main::c#4 [ main::line#5 main::c#4 main::$0 main::$2 ] ( main:2 [ main::line#5 main::c#4 main::$0 main::$2 ] ) always clobbers reg byte a +Statement [9] *((const byte*) main::screen#0 + (word~) main::$0) ← *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 40 + (word~) main::$2) [ main::line#5 main::c#4 ] ( main:2 [ main::line#5 main::c#4 ] ) always clobbers reg byte a +Statement [12] (word) main::line#1 ← (word) main::line#5 + (byte/signed byte/word/signed word/dword/signed dword) 40 [ main::line#1 ] ( main:2 [ main::line#1 ] ) always clobbers reg byte a +Statement [13] if((word) main::line#1<(byte/signed byte/word/signed word/dword/signed dword) 40*(byte/signed byte/word/signed word/dword/signed dword) 24) goto main::@1 [ main::line#1 ] ( main:2 [ main::line#1 ] ) always clobbers reg byte a +Statement [15] (word~) main::$6 ← (word) main::line#1 + (byte) main::c#5 [ main::line#1 main::c#5 main::$6 ] ( main:2 [ main::line#1 main::c#5 main::$6 ] ) always clobbers reg byte a +Statement [16] *((const byte*) main::screen#0 + (word~) main::$6) ← (byte) ' ' [ main::line#1 main::c#5 ] ( main:2 [ main::line#1 main::c#5 ] ) always clobbers reg byte a +Potential registers zp ZP_WORD:2 [ main::line#5 main::line#1 ] : zp ZP_WORD:2 , +Potential registers zp ZP_BYTE:4 [ main::c#4 main::c#1 ] : zp ZP_BYTE:4 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:5 [ main::c#5 main::c#3 ] : zp ZP_BYTE:5 , reg byte x , reg byte y , +Potential registers zp ZP_WORD:6 [ main::$0 ] : zp ZP_WORD:6 , +Potential registers zp ZP_WORD:8 [ main::$2 ] : zp ZP_WORD:8 , +Potential registers zp ZP_WORD:10 [ main::$6 ] : zp ZP_WORD:10 , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 252.5: zp ZP_BYTE:4 [ main::c#4 main::c#1 ] 202: zp ZP_WORD:8 [ main::$2 ] 101: zp ZP_WORD:6 [ main::$0 ] 38.29: zp ZP_WORD:2 [ main::line#5 main::line#1 ] 27.5: zp ZP_BYTE:5 [ main::c#5 main::c#3 ] 22: zp ZP_WORD:10 [ main::$6 ] +Uplift Scope [] + +Uplifting [main] best 11298 combination reg byte x [ main::c#4 main::c#1 ] zp ZP_WORD:8 [ main::$2 ] zp ZP_WORD:6 [ main::$0 ] zp ZP_WORD:2 [ main::line#5 main::line#1 ] reg byte x [ main::c#5 main::c#3 ] zp ZP_WORD:10 [ main::$6 ] +Uplifting [] best 11298 combination +Coalescing zero page register [ zp ZP_WORD:6 [ main::$0 ] ] with [ zp ZP_WORD:10 [ main::$6 ] ] +Allocated (was zp ZP_WORD:6) zp ZP_WORD:4 [ main::$0 main::$6 ] +Allocated (was zp ZP_WORD:8) zp ZP_WORD:6 [ main::$2 ] + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG1 Global Constants & labels +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG4 @1 +b1: +//SEG5 [2] call main +//SEG6 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .label screen = $400 + .label _0 = 4 + .label _2 = 6 + .label _6 = 4 + .label line = 2 + //SEG10 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG11 [5] phi (word) main::line#5 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vwuz1=vbuc1 + lda #<0 + sta line + lda #>0 + sta line+1 + jmp b1 + //SEG12 [5] phi from main::@4 to main::@1 [phi:main::@4->main::@1] + b1_from_b4: + //SEG13 [5] phi (word) main::line#5 = (word) main::line#1 [phi:main::@4->main::@1#0] -- register_copy + jmp b1 + //SEG14 main::@1 + b1: + //SEG15 [6] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + b2_from_b1: + //SEG16 [6] phi (byte) main::c#4 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main::@1->main::@2#0] -- vbuxx=vbuc1 + ldx #0 + jmp b2 + //SEG17 [6] phi from main::@2 to main::@2 [phi:main::@2->main::@2] + b2_from_b2: + //SEG18 [6] phi (byte) main::c#4 = (byte) main::c#1 [phi:main::@2->main::@2#0] -- register_copy + jmp b2 + //SEG19 main::@2 + b2: + //SEG20 [7] (word~) main::$0 ← (word) main::line#5 + (byte) main::c#4 -- vwuz1=vwuz2_plus_vbuxx + txa + clc + adc line + sta _0 + lda #0 + adc line+1 + sta _0+1 + //SEG21 [8] (word~) main::$2 ← (word) main::line#5 + (byte) main::c#4 -- vwuz1=vwuz2_plus_vbuxx + txa + clc + adc line + sta _2 + lda #0 + adc line+1 + sta _2+1 + //SEG22 [9] *((const byte*) main::screen#0 + (word~) main::$0) ← *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 40 + (word~) main::$2) -- pbuc1_derefidx_vwuz1=pbuc2_derefidx_vwuz2 + lda #screen + adc _0+1 + sta !a1++2 + lda #screen+$28 + adc _2+1 + sta !a2++2 + !a2: + lda screen+$28 + !a1: + sta screen + //SEG23 [10] (byte) main::c#1 ← ++ (byte) main::c#4 -- vbuxx=_inc_vbuxx + inx + //SEG24 [11] if((byte) main::c#1<(byte/signed byte/word/signed word/dword/signed dword) 40) goto main::@2 -- vbuxx_lt_vbuc1_then_la1 + cpx #$28 + bcc b2_from_b2 + jmp b4 + //SEG25 main::@4 + b4: + //SEG26 [12] (word) main::line#1 ← (word) main::line#5 + (byte/signed byte/word/signed word/dword/signed dword) 40 -- vwuz1=vwuz1_plus_vbuc1 + clc + lda line + adc #<$28 + sta line + lda line+1 + adc #>$28 + sta line+1 + //SEG27 [13] if((word) main::line#1<(byte/signed byte/word/signed word/dword/signed dword) 40*(byte/signed byte/word/signed word/dword/signed dword) 24) goto main::@1 -- vwuz1_lt_vwuc1_then_la1 + lda line+1 + cmp #>$28*$18 + bcc b1_from_b4 + bne !+ + lda line + cmp #<$28*$18 + bcc b1_from_b4 + !: + //SEG28 [14] phi from main::@4 to main::@3 [phi:main::@4->main::@3] + b3_from_b4: + //SEG29 [14] phi (byte) main::c#5 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main::@4->main::@3#0] -- vbuxx=vbuc1 + ldx #0 + jmp b3 + //SEG30 [14] phi from main::@3 to main::@3 [phi:main::@3->main::@3] + b3_from_b3: + //SEG31 [14] phi (byte) main::c#5 = (byte) main::c#3 [phi:main::@3->main::@3#0] -- register_copy + jmp b3 + //SEG32 main::@3 + b3: + //SEG33 [15] (word~) main::$6 ← (word) main::line#1 + (byte) main::c#5 -- vwuz1=vwuz2_plus_vbuxx + txa + clc + adc line + sta _6 + lda #0 + adc line+1 + sta _6+1 + //SEG34 [16] *((const byte*) main::screen#0 + (word~) main::$6) ← (byte) ' ' -- pbuc1_derefidx_vwuz1=vbuc2 + lda #screen + adc _6+1 + sta !++2 + lda #' ' + !: + sta screen + //SEG35 [17] (byte) main::c#3 ← ++ (byte) main::c#5 -- vbuxx=_inc_vbuxx + inx + //SEG36 [18] if((byte) main::c#3<(byte/signed byte/word/signed word/dword/signed dword) 40) goto main::@3 -- vbuxx_lt_vbuc1_then_la1 + cpx #$28 + bcc b3_from_b3 + jmp breturn + //SEG37 main::@return + breturn: + //SEG38 [19] return + rts +} + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp b1 +Removing instruction jmp b2 +Removing instruction jmp b4 +Removing instruction jmp b3 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction lda #>0 +Removing instruction lda line+1 +Succesful ASM optimization Pass5UnnecesaryLoadElimination +Replacing label b2_from_b2 with b2 +Replacing label b1_from_b4 with b1 +Replacing label b1_from_b4 with b1 +Replacing label b3_from_b3 with b3 +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction main_from_b1: +Removing instruction bend_from_b1: +Removing instruction b1_from_b4: +Removing instruction b2_from_b1: +Removing instruction b2_from_b2: +Removing instruction b3_from_b3: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction b1_from_main: +Removing instruction b4: +Removing instruction b3_from_b4: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction jmp b1 +Removing instruction jmp b2 +Removing instruction jmp b3 +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(void()) main() +(word~) main::$0 $0 zp ZP_WORD:4 101.0 +(word~) main::$2 $2 zp ZP_WORD:6 202.0 +(word~) main::$6 $6 zp ZP_WORD:4 22.0 +(label) main::@1 +(label) main::@2 +(label) main::@3 +(label) main::@4 +(label) main::@return +(byte) main::c +(byte) main::c#1 reg byte x 151.5 +(byte) main::c#3 reg byte x 16.5 +(byte) main::c#4 reg byte x 101.0 +(byte) main::c#5 reg byte x 11.0 +(word) main::line +(word) main::line#1 line zp ZP_WORD:2 6.285714285714286 +(word) main::line#5 line zp ZP_WORD:2 32.0 +(byte*) main::screen +(const byte*) main::screen#0 screen = ((byte*))(word/signed word/dword/signed dword) 1024 + +zp ZP_WORD:2 [ main::line#5 main::line#1 ] +reg byte x [ main::c#4 main::c#1 ] +reg byte x [ main::c#5 main::c#3 ] +zp ZP_WORD:4 [ main::$0 main::$6 ] +zp ZP_WORD:6 [ main::$2 ] + + +FINAL ASSEMBLER +Score: 10186 + +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels +//SEG2 @begin +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG4 @1 +//SEG5 [2] call main +//SEG6 [4] phi from @1 to main [phi:@1->main] +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +//SEG8 @end +//SEG9 main +main: { + .label screen = $400 + .label _0 = 4 + .label _2 = 6 + .label _6 = 4 + .label line = 2 + //SEG10 [5] phi from main to main::@1 [phi:main->main::@1] + //SEG11 [5] phi (word) main::line#5 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vwuz1=vbuc1 + lda #<0 + sta line + sta line+1 + //SEG12 [5] phi from main::@4 to main::@1 [phi:main::@4->main::@1] + //SEG13 [5] phi (word) main::line#5 = (word) main::line#1 [phi:main::@4->main::@1#0] -- register_copy + //SEG14 main::@1 + b1: + //SEG15 [6] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + //SEG16 [6] phi (byte) main::c#4 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main::@1->main::@2#0] -- vbuxx=vbuc1 + ldx #0 + //SEG17 [6] phi from main::@2 to main::@2 [phi:main::@2->main::@2] + //SEG18 [6] phi (byte) main::c#4 = (byte) main::c#1 [phi:main::@2->main::@2#0] -- register_copy + //SEG19 main::@2 + b2: + //SEG20 [7] (word~) main::$0 ← (word) main::line#5 + (byte) main::c#4 -- vwuz1=vwuz2_plus_vbuxx + txa + clc + adc line + sta _0 + lda #0 + adc line+1 + sta _0+1 + //SEG21 [8] (word~) main::$2 ← (word) main::line#5 + (byte) main::c#4 -- vwuz1=vwuz2_plus_vbuxx + txa + clc + adc line + sta _2 + lda #0 + adc line+1 + sta _2+1 + //SEG22 [9] *((const byte*) main::screen#0 + (word~) main::$0) ← *((const byte*) main::screen#0+(byte/signed byte/word/signed word/dword/signed dword) 40 + (word~) main::$2) -- pbuc1_derefidx_vwuz1=pbuc2_derefidx_vwuz2 + lda #screen + adc _0+1 + sta !a1++2 + lda #screen+$28 + adc _2+1 + sta !a2++2 + !a2: + lda screen+$28 + !a1: + sta screen + //SEG23 [10] (byte) main::c#1 ← ++ (byte) main::c#4 -- vbuxx=_inc_vbuxx + inx + //SEG24 [11] if((byte) main::c#1<(byte/signed byte/word/signed word/dword/signed dword) 40) goto main::@2 -- vbuxx_lt_vbuc1_then_la1 + cpx #$28 + bcc b2 + //SEG25 main::@4 + //SEG26 [12] (word) main::line#1 ← (word) main::line#5 + (byte/signed byte/word/signed word/dword/signed dword) 40 -- vwuz1=vwuz1_plus_vbuc1 + clc + lda line + adc #<$28 + sta line + lda line+1 + adc #>$28 + sta line+1 + //SEG27 [13] if((word) main::line#1<(byte/signed byte/word/signed word/dword/signed dword) 40*(byte/signed byte/word/signed word/dword/signed dword) 24) goto main::@1 -- vwuz1_lt_vwuc1_then_la1 + cmp #>$28*$18 + bcc b1 + bne !+ + lda line + cmp #<$28*$18 + bcc b1 + !: + //SEG28 [14] phi from main::@4 to main::@3 [phi:main::@4->main::@3] + //SEG29 [14] phi (byte) main::c#5 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main::@4->main::@3#0] -- vbuxx=vbuc1 + ldx #0 + //SEG30 [14] phi from main::@3 to main::@3 [phi:main::@3->main::@3] + //SEG31 [14] phi (byte) main::c#5 = (byte) main::c#3 [phi:main::@3->main::@3#0] -- register_copy + //SEG32 main::@3 + b3: + //SEG33 [15] (word~) main::$6 ← (word) main::line#1 + (byte) main::c#5 -- vwuz1=vwuz2_plus_vbuxx + txa + clc + adc line + sta _6 + lda #0 + adc line+1 + sta _6+1 + //SEG34 [16] *((const byte*) main::screen#0 + (word~) main::$6) ← (byte) ' ' -- pbuc1_derefidx_vwuz1=vbuc2 + lda #screen + adc _6+1 + sta !++2 + lda #' ' + !: + sta screen + //SEG35 [17] (byte) main::c#3 ← ++ (byte) main::c#5 -- vbuxx=_inc_vbuxx + inx + //SEG36 [18] if((byte) main::c#3<(byte/signed byte/word/signed word/dword/signed dword) 40) goto main::@3 -- vbuxx_lt_vbuc1_then_la1 + cpx #$28 + bcc b3 + //SEG37 main::@return + //SEG38 [19] return + rts +} + diff --git a/src/test/ref/test-word-size-arrays.sym b/src/test/ref/test-word-size-arrays.sym new file mode 100644 index 000000000..0c8f2e12d --- /dev/null +++ b/src/test/ref/test-word-size-arrays.sym @@ -0,0 +1,28 @@ +(label) @1 +(label) @begin +(label) @end +(void()) main() +(word~) main::$0 $0 zp ZP_WORD:4 101.0 +(word~) main::$2 $2 zp ZP_WORD:6 202.0 +(word~) main::$6 $6 zp ZP_WORD:4 22.0 +(label) main::@1 +(label) main::@2 +(label) main::@3 +(label) main::@4 +(label) main::@return +(byte) main::c +(byte) main::c#1 reg byte x 151.5 +(byte) main::c#3 reg byte x 16.5 +(byte) main::c#4 reg byte x 101.0 +(byte) main::c#5 reg byte x 11.0 +(word) main::line +(word) main::line#1 line zp ZP_WORD:2 6.285714285714286 +(word) main::line#5 line zp ZP_WORD:2 32.0 +(byte*) main::screen +(const byte*) main::screen#0 screen = ((byte*))(word/signed word/dword/signed dword) 1024 + +zp ZP_WORD:2 [ main::line#5 main::line#1 ] +reg byte x [ main::c#4 main::c#1 ] +reg byte x [ main::c#5 main::c#3 ] +zp ZP_WORD:4 [ main::$0 main::$6 ] +zp ZP_WORD:6 [ main::$2 ]