From 5a83c1b357880ba97eed8965b897310235f0c4e2 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Sat, 9 Mar 2019 18:37:23 +0100 Subject: [PATCH] Fixed clobber problem that can occur during PHI transitions. Closes #10 --- .../kickc/passes/Pass4AssertNoCpuClobber.java | 6 +- .../dk/camelot64/kickc/test/TestPrograms.java | 5 + src/test/kc/scrollbig-clobber.kc | 24 + src/test/ref/examples/scrollbig/scrollbig.asm | 6 +- src/test/ref/examples/scrollbig/scrollbig.log | 52 +- src/test/ref/examples/scrollbig/scrollbig.sym | 12 +- src/test/ref/scrollbig-clobber.asm | 41 + src/test/ref/scrollbig-clobber.cfg | 42 ++ src/test/ref/scrollbig-clobber.log | 707 ++++++++++++++++++ src/test/ref/scrollbig-clobber.sym | 35 + 10 files changed, 897 insertions(+), 33 deletions(-) create mode 100644 src/test/kc/scrollbig-clobber.kc create mode 100644 src/test/ref/scrollbig-clobber.asm create mode 100644 src/test/ref/scrollbig-clobber.cfg create mode 100644 src/test/ref/scrollbig-clobber.log create mode 100644 src/test/ref/scrollbig-clobber.sym diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4AssertNoCpuClobber.java b/src/main/java/dk/camelot64/kickc/passes/Pass4AssertNoCpuClobber.java index d05125679..2e0353147 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4AssertNoCpuClobber.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4AssertNoCpuClobber.java @@ -79,14 +79,18 @@ public class Pass4AssertNoCpuClobber extends Pass2Base { PhiTransitions phiTransitions = new PhiTransitions(getProgram(), statementBlock); PhiTransitions.PhiTransition phiTransition = phiTransitions.getTransition(phiTransitionId); for(PhiTransitions.PhiTransition.PhiAssignment phiAssignment : phiTransition.getAssignments()) { - // IF the assignment is later than the current one if(phiAssignment.getAssignmentIdx() > transitionAssignmentIdx) { + // IF the assignment is later than the current one RValue rValue = phiAssignment.getrValue(); Collection alive = VariableReferenceInfos.getReferencedVars(rValue); aliveVars.addAll(alive); VariableRef assignedVar = phiAssignment.getVariable(); assignedVars.remove(assignedVar); alive.remove(assignedVar); + } else if(phiAssignment.getAssignmentIdx() < transitionAssignmentIdx) { + // IF the assignment is before the current one + VariableRef assignedVar = phiAssignment.getVariable(); + assignedVars.remove(assignedVar); } } } diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 0dd857ea9..5ff1c92e9 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 testClobberProblem() throws IOException, URISyntaxException { + compileAndCompare("scrollbig-clobber"); + } + @Test public void testComparisonsSWord() throws IOException, URISyntaxException { compileAndCompare("test-comparisons-sword"); diff --git a/src/test/kc/scrollbig-clobber.kc b/src/test/kc/scrollbig-clobber.kc new file mode 100644 index 000000000..878b61a23 --- /dev/null +++ b/src/test/kc/scrollbig-clobber.kc @@ -0,0 +1,24 @@ +// Clobber problem in next_char return value + +byte* TEXT = "cml @"; + +void main() { + byte* SCREEN = $400; + for( byte i: 0..255) { + SCREEN[i] = next_char(); + } +} + +byte* nxt = TEXT; + +// Find the next char of the text +byte next_char() { + byte c = *nxt; + if(c=='@') { + nxt = TEXT; + c = *nxt; + } + nxt++; + return c; +} + diff --git a/src/test/ref/examples/scrollbig/scrollbig.asm b/src/test/ref/examples/scrollbig/scrollbig.asm index 5d1e3326a..f98b67ccd 100644 --- a/src/test/ref/examples/scrollbig/scrollbig.asm +++ b/src/test/ref/examples/scrollbig/scrollbig.asm @@ -57,6 +57,7 @@ scroll_bit: { cmp #0 bne b1 jsr next_char + txa sta c lda #0 sta c+1 @@ -143,9 +144,10 @@ scroll_hard: { next_char: { ldy #0 lda (nxt),y - cmp #'@' + tax + cpx #'@' bne b1 - lda TEXT + ldx TEXT lda #TEXT diff --git a/src/test/ref/examples/scrollbig/scrollbig.log b/src/test/ref/examples/scrollbig/scrollbig.log index ea0cc8dcb..f258c9217 100644 --- a/src/test/ref/examples/scrollbig/scrollbig.log +++ b/src/test/ref/examples/scrollbig/scrollbig.log @@ -2104,13 +2104,13 @@ Limited combination testing to 100 combinations of 512 possible. Uplifting [scroll_hard] best 24938 combination reg byte x [ scroll_hard::i#2 scroll_hard::i#1 ] Uplifting [] best 24626 combination zp ZP_WORD:4 [ current_chargen#27 current_chargen#11 current_chargen#19 current_chargen#5 ] zp ZP_BYTE:3 [ current_bit#29 current_bit#12 current_bit#21 current_bit#5 ] zp ZP_WORD:11 [ nxt#18 nxt#31 nxt#14 nxt#36 nxt#19 ] reg byte x [ scroll#18 scroll#10 scroll#3 ] Uplifting [fillscreen] best 24626 combination zp ZP_WORD:14 [ fillscreen::cursor#2 fillscreen::cursor#1 ] -Uplifting [next_char] best 24608 combination reg byte a [ next_char::return#1 next_char::c#0 next_char::c#1 ] reg byte a [ next_char::return#0 ] -Uplifting [main] best 24608 combination -Uplifting [scroll_soft] best 24608 combination +Uplifting [next_char] best 24610 combination reg byte x [ next_char::return#1 next_char::c#0 next_char::c#1 ] reg byte x [ next_char::return#0 ] +Uplifting [main] best 24610 combination +Uplifting [scroll_soft] best 24610 combination Attempting to uplift remaining variables inzp ZP_BYTE:3 [ current_bit#29 current_bit#12 current_bit#21 current_bit#5 ] -Uplifting [] best 24608 combination zp ZP_BYTE:3 [ current_bit#29 current_bit#12 current_bit#21 current_bit#5 ] +Uplifting [] best 24610 combination zp ZP_BYTE:3 [ current_bit#29 current_bit#12 current_bit#21 current_bit#5 ] Attempting to uplift remaining variables inzp ZP_BYTE:17 [ scroll_bit::$3 ] -Uplifting [scroll_bit] best 24602 combination reg byte a [ scroll_bit::$3 ] +Uplifting [scroll_bit] best 24606 combination reg byte a [ scroll_bit::$3 ] Coalescing zero page register with common assignment [ zp ZP_WORD:4 [ current_chargen#27 current_chargen#11 current_chargen#19 current_chargen#5 ] ] with [ zp ZP_WORD:20 [ scroll_bit::$4 ] ] - score: 1 Coalescing zero page register with common assignment [ zp ZP_WORD:4 [ current_chargen#27 current_chargen#11 current_chargen#19 current_chargen#5 scroll_bit::$4 ] ] with [ zp ZP_WORD:18 [ scroll_bit::c#0 ] ] - score: 1 Coalescing zero page register [ zp ZP_WORD:4 [ current_chargen#27 current_chargen#11 current_chargen#19 current_chargen#5 scroll_bit::$4 scroll_bit::c#0 ] ] with [ zp ZP_WORD:14 [ fillscreen::cursor#2 fillscreen::cursor#1 ] ] @@ -2274,7 +2274,8 @@ scroll_bit: { jmp b8 //SEG60 scroll_bit::@8 b8: - //SEG61 [24] (byte~) scroll_bit::$3 ← (byte) next_char::return#0 + //SEG61 [24] (byte~) scroll_bit::$3 ← (byte) next_char::return#0 -- vbuaa=vbuxx + txa //SEG62 [25] (word) scroll_bit::c#0 ← ((word)) (byte~) scroll_bit::$3 -- vwuz1=_word_vbuaa sta c lda #0 @@ -2447,17 +2448,18 @@ scroll_hard: { //SEG123 next_char // Find the next char of the scroll text next_char: { - //SEG124 [58] (byte) next_char::c#0 ← *((byte*) nxt#31) -- vbuaa=_deref_pbuz1 + //SEG124 [58] (byte) next_char::c#0 ← *((byte*) nxt#31) -- vbuxx=_deref_pbuz1 ldy #0 lda (nxt),y - //SEG125 [59] if((byte) next_char::c#0!=(byte) '@') goto next_char::@1 -- vbuaa_neq_vbuc1_then_la1 - cmp #'@' + tax + //SEG125 [59] if((byte) next_char::c#0!=(byte) '@') goto next_char::@1 -- vbuxx_neq_vbuc1_then_la1 + cpx #'@' bne b1_from_next_char jmp b2 //SEG126 next_char::@2 b2: - //SEG127 [60] (byte) next_char::c#1 ← *((const byte*) TEXT#0) -- vbuaa=_deref_pbuc1 - lda TEXT + //SEG127 [60] (byte) next_char::c#1 ← *((const byte*) TEXT#0) -- vbuxx=_deref_pbuc1 + ldx TEXT //SEG128 [61] phi from next_char::@2 to next_char::@1 [phi:next_char::@2->next_char::@1] b1_from_b2: //SEG129 [61] phi (byte) next_char::return#1 = (byte) next_char::c#1 [phi:next_char::@2->next_char::@1#0] -- register_copy @@ -2670,11 +2672,11 @@ FINAL SYMBOL TABLE (label) next_char::@2 (label) next_char::@return (byte) next_char::c -(byte) next_char::c#0 reg byte a 3.0 -(byte) next_char::c#1 reg byte a 4.0 +(byte) next_char::c#0 reg byte x 3.0 +(byte) next_char::c#1 reg byte x 4.0 (byte) next_char::return -(byte) next_char::return#0 reg byte a 4.0 -(byte) next_char::return#1 reg byte a 1.5 +(byte) next_char::return#0 reg byte x 4.0 +(byte) next_char::return#1 reg byte x 1.5 (byte*) nxt (byte*) nxt#14 nxt zp ZP_WORD:7 3.0 (byte*) nxt#18 nxt zp ZP_WORD:7 4.0 @@ -2729,15 +2731,15 @@ zp ZP_WORD:5 [ scroll_bit::sc#2 scroll_bit::sc#1 ] reg byte a [ scroll_bit::b#2 ] reg byte x [ scroll_hard::i#2 scroll_hard::i#1 ] zp ZP_WORD:7 [ nxt#18 nxt#31 nxt#14 nxt#36 nxt#19 ] -reg byte a [ next_char::return#1 next_char::c#0 next_char::c#1 ] -reg byte a [ next_char::return#0 ] +reg byte x [ next_char::return#1 next_char::c#0 next_char::c#1 ] +reg byte x [ next_char::return#0 ] reg byte a [ scroll_bit::$3 ] reg byte a [ scroll_bit::bits#0 ] reg byte a [ scroll_bit::$9 ] FINAL ASSEMBLER -Score: 20822 +Score: 20826 //SEG0 File Comments // An 8x8 char letter scroller @@ -2859,7 +2861,8 @@ scroll_bit: { jsr next_char //SEG59 [23] (byte) next_char::return#0 ← (byte) next_char::return#1 //SEG60 scroll_bit::@8 - //SEG61 [24] (byte~) scroll_bit::$3 ← (byte) next_char::return#0 + //SEG61 [24] (byte~) scroll_bit::$3 ← (byte) next_char::return#0 -- vbuaa=vbuxx + txa //SEG62 [25] (word) scroll_bit::c#0 ← ((word)) (byte~) scroll_bit::$3 -- vwuz1=_word_vbuaa sta c lda #0 @@ -3006,15 +3009,16 @@ scroll_hard: { //SEG123 next_char // Find the next char of the scroll text next_char: { - //SEG124 [58] (byte) next_char::c#0 ← *((byte*) nxt#31) -- vbuaa=_deref_pbuz1 + //SEG124 [58] (byte) next_char::c#0 ← *((byte*) nxt#31) -- vbuxx=_deref_pbuz1 ldy #0 lda (nxt),y - //SEG125 [59] if((byte) next_char::c#0!=(byte) '@') goto next_char::@1 -- vbuaa_neq_vbuc1_then_la1 - cmp #'@' + tax + //SEG125 [59] if((byte) next_char::c#0!=(byte) '@') goto next_char::@1 -- vbuxx_neq_vbuc1_then_la1 + cpx #'@' bne b1 //SEG126 next_char::@2 - //SEG127 [60] (byte) next_char::c#1 ← *((const byte*) TEXT#0) -- vbuaa=_deref_pbuc1 - lda TEXT + //SEG127 [60] (byte) next_char::c#1 ← *((const byte*) TEXT#0) -- vbuxx=_deref_pbuc1 + ldx TEXT //SEG128 [61] phi from next_char::@2 to next_char::@1 [phi:next_char::@2->next_char::@1] //SEG129 [61] phi (byte) next_char::return#1 = (byte) next_char::c#1 [phi:next_char::@2->next_char::@1#0] -- register_copy //SEG130 [61] phi (byte*) nxt#18 = (const byte*) TEXT#0 [phi:next_char::@2->next_char::@1#1] -- pbuz1=pbuc1 diff --git a/src/test/ref/examples/scrollbig/scrollbig.sym b/src/test/ref/examples/scrollbig/scrollbig.sym index 0f106de57..501c86b1f 100644 --- a/src/test/ref/examples/scrollbig/scrollbig.sym +++ b/src/test/ref/examples/scrollbig/scrollbig.sym @@ -44,11 +44,11 @@ (label) next_char::@2 (label) next_char::@return (byte) next_char::c -(byte) next_char::c#0 reg byte a 3.0 -(byte) next_char::c#1 reg byte a 4.0 +(byte) next_char::c#0 reg byte x 3.0 +(byte) next_char::c#1 reg byte x 4.0 (byte) next_char::return -(byte) next_char::return#0 reg byte a 4.0 -(byte) next_char::return#1 reg byte a 1.5 +(byte) next_char::return#0 reg byte x 4.0 +(byte) next_char::return#1 reg byte x 1.5 (byte*) nxt (byte*) nxt#14 nxt zp ZP_WORD:7 3.0 (byte*) nxt#18 nxt zp ZP_WORD:7 4.0 @@ -103,8 +103,8 @@ zp ZP_WORD:5 [ scroll_bit::sc#2 scroll_bit::sc#1 ] reg byte a [ scroll_bit::b#2 ] reg byte x [ scroll_hard::i#2 scroll_hard::i#1 ] zp ZP_WORD:7 [ nxt#18 nxt#31 nxt#14 nxt#36 nxt#19 ] -reg byte a [ next_char::return#1 next_char::c#0 next_char::c#1 ] -reg byte a [ next_char::return#0 ] +reg byte x [ next_char::return#1 next_char::c#0 next_char::c#1 ] +reg byte x [ next_char::return#0 ] reg byte a [ scroll_bit::$3 ] reg byte a [ scroll_bit::bits#0 ] reg byte a [ scroll_bit::$9 ] diff --git a/src/test/ref/scrollbig-clobber.asm b/src/test/ref/scrollbig-clobber.asm new file mode 100644 index 000000000..30d29f41e --- /dev/null +++ b/src/test/ref/scrollbig-clobber.asm @@ -0,0 +1,41 @@ +// Clobber problem in next_char return value +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .label nxt = 2 +main: { + .label SCREEN = $400 + ldx #0 + lda #TEXT + sta nxt+1 + b1: + jsr next_char + tya + sta SCREEN,x + inx + cpx #0 + bne b1 + rts +} +// Find the next char of the text +next_char: { + ldy #0 + lda (nxt),y + tay + cpy #'@' + bne b1 + ldy TEXT + lda #TEXT + sta nxt+1 + b1: + inc nxt + bne !+ + inc nxt+1 + !: + rts +} + TEXT: .text "cml @" diff --git a/src/test/ref/scrollbig-clobber.cfg b/src/test/ref/scrollbig-clobber.cfg new file mode 100644 index 000000000..481723782 --- /dev/null +++ b/src/test/ref/scrollbig-clobber.cfg @@ -0,0 +1,42 @@ +@begin: scope:[] from + [0] phi() + to:@2 +@2: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @2 + [3] phi() +main: scope:[main] from @2 + [4] phi() + to:main::@1 +main::@1: scope:[main] from main main::@3 + [5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@3/(byte) main::i#1 ) + [5] (byte*) nxt#13 ← phi( main/(const byte*) TEXT#0 main::@3/(byte*) nxt#11 ) + [6] call next_char + [7] (byte) next_char::return#0 ← (byte) next_char::return#1 + to:main::@3 +main::@3: scope:[main] from main::@1 + [8] (byte~) main::$0 ← (byte) next_char::return#0 + [9] *((const byte*) main::SCREEN#0 + (byte) main::i#2) ← (byte~) main::$0 + [10] (byte) main::i#1 ← ++ (byte) main::i#2 + [11] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@3 + [12] return + to:@return +next_char: scope:[next_char] from main::@1 + [13] (byte) next_char::c#0 ← *((byte*) nxt#13) + [14] if((byte) next_char::c#0!=(byte) '@') goto next_char::@1 + to:next_char::@2 +next_char::@2: scope:[next_char] from next_char + [15] (byte) next_char::c#1 ← *((const byte*) TEXT#0) + to:next_char::@1 +next_char::@1: scope:[next_char] from next_char next_char::@2 + [16] (byte) next_char::return#1 ← phi( next_char/(byte) next_char::c#0 next_char::@2/(byte) next_char::c#1 ) + [16] (byte*) nxt#10 ← phi( next_char/(byte*) nxt#13 next_char::@2/(const byte*) TEXT#0 ) + [17] (byte*) nxt#11 ← ++ (byte*) nxt#10 + to:next_char::@return +next_char::@return: scope:[next_char] from next_char::@1 + [18] return + to:@return diff --git a/src/test/ref/scrollbig-clobber.log b/src/test/ref/scrollbig-clobber.log new file mode 100644 index 000000000..5fcd9f9a7 --- /dev/null +++ b/src/test/ref/scrollbig-clobber.log @@ -0,0 +1,707 @@ + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (byte*) TEXT#0 ← (const string) $0 + to:@1 +main: scope:[main] from @2 + (byte*) TEXT#5 ← phi( @2/(byte*) TEXT#7 ) + (byte*) nxt#15 ← phi( @2/(byte*) nxt#14 ) + (byte*) main::SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $400 + (byte) main::i#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 + to:main::@1 +main::@1: scope:[main] from main main::@3 + (byte*) TEXT#4 ← phi( main/(byte*) TEXT#5 main::@3/(byte*) TEXT#6 ) + (byte) main::i#3 ← phi( main/(byte) main::i#0 main::@3/(byte) main::i#1 ) + (byte*) main::SCREEN#2 ← phi( main/(byte*) main::SCREEN#0 main::@3/(byte*) main::SCREEN#1 ) + (byte*) nxt#13 ← phi( main/(byte*) nxt#15 main::@3/(byte*) nxt#0 ) + call next_char + (byte) next_char::return#0 ← (byte) next_char::return#2 + to:main::@3 +main::@3: scope:[main] from main::@1 + (byte*) TEXT#6 ← phi( main::@1/(byte*) TEXT#4 ) + (byte) main::i#2 ← phi( main::@1/(byte) main::i#3 ) + (byte*) main::SCREEN#1 ← phi( main::@1/(byte*) main::SCREEN#2 ) + (byte*) nxt#7 ← phi( main::@1/(byte*) nxt#5 ) + (byte) next_char::return#3 ← phi( main::@1/(byte) next_char::return#0 ) + (byte~) main::$0 ← (byte) next_char::return#3 + (byte*) nxt#0 ← (byte*) nxt#7 + *((byte*) main::SCREEN#1 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::i#1 ← (byte) main::i#2 + rangenext(0,$ff) + (bool~) main::$1 ← (byte) main::i#1 != rangelast(0,$ff) + if((bool~) main::$1) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@3 + (byte*) nxt#8 ← phi( main::@3/(byte*) nxt#0 ) + (byte*) nxt#1 ← (byte*) nxt#8 + return + to:@return +@1: scope:[] from @begin + (byte*) TEXT#1 ← phi( @begin/(byte*) TEXT#0 ) + (byte*) nxt#2 ← (byte*) TEXT#1 + to:@2 +next_char: scope:[next_char] from main::@1 + (byte*) TEXT#3 ← phi( main::@1/(byte*) TEXT#4 ) + (byte*) nxt#9 ← phi( main::@1/(byte*) nxt#13 ) + (byte) next_char::c#0 ← *((byte*) nxt#9) + (bool~) next_char::$0 ← (byte) next_char::c#0 == (byte) '@' + (bool~) next_char::$1 ← ! (bool~) next_char::$0 + if((bool~) next_char::$1) goto next_char::@1 + to:next_char::@2 +next_char::@1: scope:[next_char] from next_char next_char::@2 + (byte) next_char::c#2 ← phi( next_char/(byte) next_char::c#0 next_char::@2/(byte) next_char::c#1 ) + (byte*) nxt#10 ← phi( next_char/(byte*) nxt#9 next_char::@2/(byte*) nxt#4 ) + (byte*) nxt#3 ← ++ (byte*) nxt#10 + (byte) next_char::return#1 ← (byte) next_char::c#2 + to:next_char::@return +next_char::@2: scope:[next_char] from next_char + (byte*) TEXT#2 ← phi( next_char/(byte*) TEXT#3 ) + (byte*) nxt#4 ← (byte*) TEXT#2 + (byte) next_char::c#1 ← *((byte*) nxt#4) + to:next_char::@1 +next_char::@return: scope:[next_char] from next_char::@1 + (byte*) nxt#11 ← phi( next_char::@1/(byte*) nxt#3 ) + (byte) next_char::return#4 ← phi( next_char::@1/(byte) next_char::return#1 ) + (byte) next_char::return#2 ← (byte) next_char::return#4 + (byte*) nxt#5 ← (byte*) nxt#11 + return + to:@return +@2: scope:[] from @1 + (byte*) TEXT#7 ← phi( @1/(byte*) TEXT#1 ) + (byte*) nxt#14 ← phi( @1/(byte*) nxt#2 ) + call main + to:@3 +@3: scope:[] from @2 + (byte*) nxt#12 ← phi( @2/(byte*) nxt#1 ) + (byte*) nxt#6 ← (byte*) nxt#12 + to:@end +@end: scope:[] from @3 + +SYMBOL TABLE SSA +(const string) $0 = (string) "cml @" +(label) @1 +(label) @2 +(label) @3 +(label) @begin +(label) @end +(byte*) TEXT +(byte*) TEXT#0 +(byte*) TEXT#1 +(byte*) TEXT#2 +(byte*) TEXT#3 +(byte*) TEXT#4 +(byte*) TEXT#5 +(byte*) TEXT#6 +(byte*) TEXT#7 +(void()) main() +(byte~) main::$0 +(bool~) main::$1 +(label) main::@1 +(label) main::@3 +(label) main::@return +(byte*) main::SCREEN +(byte*) main::SCREEN#0 +(byte*) main::SCREEN#1 +(byte*) main::SCREEN#2 +(byte) main::i +(byte) main::i#0 +(byte) main::i#1 +(byte) main::i#2 +(byte) main::i#3 +(byte()) next_char() +(bool~) next_char::$0 +(bool~) next_char::$1 +(label) next_char::@1 +(label) next_char::@2 +(label) next_char::@return +(byte) next_char::c +(byte) next_char::c#0 +(byte) next_char::c#1 +(byte) next_char::c#2 +(byte) next_char::return +(byte) next_char::return#0 +(byte) next_char::return#1 +(byte) next_char::return#2 +(byte) next_char::return#3 +(byte) next_char::return#4 +(byte*) nxt +(byte*) nxt#0 +(byte*) nxt#1 +(byte*) nxt#10 +(byte*) nxt#11 +(byte*) nxt#12 +(byte*) nxt#13 +(byte*) nxt#14 +(byte*) nxt#15 +(byte*) nxt#2 +(byte*) nxt#3 +(byte*) nxt#4 +(byte*) nxt#5 +(byte*) nxt#6 +(byte*) nxt#7 +(byte*) nxt#8 +(byte*) nxt#9 + +Inversing boolean not [22] (bool~) next_char::$1 ← (byte) next_char::c#0 != (byte) '@' from [21] (bool~) next_char::$0 ← (byte) next_char::c#0 == (byte) '@' +Successful SSA optimization Pass2UnaryNotSimplification +Alias (byte) next_char::return#0 = (byte) next_char::return#3 +Alias (byte*) main::SCREEN#1 = (byte*) main::SCREEN#2 +Alias (byte) main::i#2 = (byte) main::i#3 +Alias (byte*) TEXT#4 = (byte*) TEXT#6 +Alias (byte*) nxt#0 = (byte*) nxt#7 (byte*) nxt#8 (byte*) nxt#1 +Alias (byte*) TEXT#0 = (byte*) TEXT#1 (byte*) nxt#2 (byte*) nxt#14 (byte*) TEXT#7 +Alias (byte) next_char::return#1 = (byte) next_char::c#2 (byte) next_char::return#4 (byte) next_char::return#2 +Alias (byte*) TEXT#2 = (byte*) TEXT#3 (byte*) nxt#4 +Alias (byte*) nxt#11 = (byte*) nxt#3 (byte*) nxt#5 +Alias (byte*) nxt#12 = (byte*) nxt#6 +Successful SSA optimization Pass2AliasElimination +Self Phi Eliminated (byte*) main::SCREEN#1 +Self Phi Eliminated (byte*) TEXT#4 +Successful SSA optimization Pass2SelfPhiElimination +Redundant Phi (byte*) nxt#15 (byte*) TEXT#0 +Redundant Phi (byte*) TEXT#5 (byte*) TEXT#0 +Redundant Phi (byte*) main::SCREEN#1 (byte*) main::SCREEN#0 +Redundant Phi (byte*) TEXT#4 (byte*) TEXT#5 +Redundant Phi (byte*) nxt#0 (byte*) nxt#11 +Redundant Phi (byte*) nxt#9 (byte*) nxt#13 +Redundant Phi (byte*) TEXT#2 (byte*) TEXT#4 +Redundant Phi (byte*) nxt#12 (byte*) nxt#0 +Successful SSA optimization Pass2RedundantPhiElimination +Simple Condition (bool~) main::$1 [13] if((byte) main::i#1!=rangelast(0,$ff)) goto main::@1 +Simple Condition (bool~) next_char::$1 [23] if((byte) next_char::c#0!=(byte) '@') goto next_char::@1 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant (const byte*) TEXT#0 = $0 +Constant (const byte*) main::SCREEN#0 = ((byte*))$400 +Constant (const byte) main::i#0 = 0 +Successful SSA optimization Pass2ConstantIdentification +Resolved ranged next value main::i#1 ← ++ main::i#2 to ++ +Resolved ranged comparison value if(main::i#1!=rangelast(0,$ff)) goto main::@1 to (byte/signed byte/word/signed word/dword/signed dword) 0 +Culled Empty Block (label) @1 +Culled Empty Block (label) @3 +Successful SSA optimization Pass2CullEmptyBlocks +Inlining constant with var siblings (const byte) main::i#0 +Constant inlined $0 = (const byte*) TEXT#0 +Constant inlined main::i#0 = (byte/signed byte/word/signed word/dword/signed dword) 0 +Successful SSA optimization Pass2ConstantInlining +Added new block during phi lifting main::@4(between main::@3 and main::@1) +Added new block during phi lifting next_char::@4(between next_char and next_char::@1) +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 +CALL GRAPH +Calls in [] to main:2 +Calls in [main] to next_char:6 + +Created 4 initial phi equivalence classes +Coalesced [13] nxt#16 ← nxt#11 +Coalesced [14] main::i#4 ← main::i#1 +Coalesced [18] next_char::return#6 ← next_char::c#1 +Coalesced [22] nxt#17 ← nxt#13 +Coalesced [23] next_char::return#5 ← next_char::c#0 +Coalesced down to 3 phi equivalence classes +Culled Empty Block (label) main::@4 +Culled Empty Block (label) next_char::@4 +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 + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() + to:@2 +@2: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @2 + [3] phi() +main: scope:[main] from @2 + [4] phi() + to:main::@1 +main::@1: scope:[main] from main main::@3 + [5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@3/(byte) main::i#1 ) + [5] (byte*) nxt#13 ← phi( main/(const byte*) TEXT#0 main::@3/(byte*) nxt#11 ) + [6] call next_char + [7] (byte) next_char::return#0 ← (byte) next_char::return#1 + to:main::@3 +main::@3: scope:[main] from main::@1 + [8] (byte~) main::$0 ← (byte) next_char::return#0 + [9] *((const byte*) main::SCREEN#0 + (byte) main::i#2) ← (byte~) main::$0 + [10] (byte) main::i#1 ← ++ (byte) main::i#2 + [11] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@3 + [12] return + to:@return +next_char: scope:[next_char] from main::@1 + [13] (byte) next_char::c#0 ← *((byte*) nxt#13) + [14] if((byte) next_char::c#0!=(byte) '@') goto next_char::@1 + to:next_char::@2 +next_char::@2: scope:[next_char] from next_char + [15] (byte) next_char::c#1 ← *((const byte*) TEXT#0) + to:next_char::@1 +next_char::@1: scope:[next_char] from next_char next_char::@2 + [16] (byte) next_char::return#1 ← phi( next_char/(byte) next_char::c#0 next_char::@2/(byte) next_char::c#1 ) + [16] (byte*) nxt#10 ← phi( next_char/(byte*) nxt#13 next_char::@2/(const byte*) TEXT#0 ) + [17] (byte*) nxt#11 ← ++ (byte*) nxt#10 + to:next_char::@return +next_char::@return: scope:[next_char] from next_char::@1 + [18] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(byte*) TEXT +(void()) main() +(byte~) main::$0 22.0 +(byte*) main::SCREEN +(byte) main::i +(byte) main::i#1 16.5 +(byte) main::i#2 6.6000000000000005 +(byte()) next_char() +(byte) next_char::c +(byte) next_char::c#0 3.0 +(byte) next_char::c#1 4.0 +(byte) next_char::return +(byte) next_char::return#0 22.0 +(byte) next_char::return#1 3.75 +(byte*) nxt +(byte*) nxt#10 4.0 +(byte*) nxt#11 1.625 +(byte*) nxt#13 5.0 + +Initial phi equivalence classes +[ main::i#2 main::i#1 ] +[ nxt#10 nxt#13 nxt#11 ] +[ next_char::return#1 next_char::c#0 next_char::c#1 ] +Added variable next_char::return#0 to zero page equivalence class [ next_char::return#0 ] +Added variable main::$0 to zero page equivalence class [ main::$0 ] +Complete equivalence classes +[ main::i#2 main::i#1 ] +[ nxt#10 nxt#13 nxt#11 ] +[ next_char::return#1 next_char::c#0 next_char::c#1 ] +[ next_char::return#0 ] +[ main::$0 ] +Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ] +Allocated zp ZP_WORD:3 [ nxt#10 nxt#13 nxt#11 ] +Allocated zp ZP_BYTE:5 [ next_char::return#1 next_char::c#0 next_char::c#1 ] +Allocated zp ZP_BYTE:6 [ next_char::return#0 ] +Allocated zp ZP_BYTE:7 [ main::$0 ] + +INITIAL ASM +//SEG0 File Comments +// Clobber problem in next_char return value +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .label nxt = 3 +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @2 [phi:@begin->@2] +b2_from_bbegin: + jmp b2 +//SEG5 @2 +b2: +//SEG6 [2] call main +//SEG7 [4] phi from @2 to main [phi:@2->main] +main_from_b2: + jsr main +//SEG8 [3] phi from @2 to @end [phi:@2->@end] +bend_from_b2: + jmp bend +//SEG9 @end +bend: +//SEG10 main +main: { + .label SCREEN = $400 + .label _0 = 7 + .label i = 2 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 + lda #0 + sta i + //SEG13 [5] phi (byte*) nxt#13 = (const byte*) TEXT#0 [phi:main->main::@1#1] -- pbuz1=pbuc1 + lda #TEXT + sta nxt+1 + jmp b1 + //SEG14 [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1] + b1_from_b3: + //SEG15 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@3->main::@1#0] -- register_copy + //SEG16 [5] phi (byte*) nxt#13 = (byte*) nxt#11 [phi:main::@3->main::@1#1] -- register_copy + jmp b1 + //SEG17 main::@1 + b1: + //SEG18 [6] call next_char + jsr next_char + //SEG19 [7] (byte) next_char::return#0 ← (byte) next_char::return#1 -- vbuz1=vbuz2 + lda next_char.return_1 + sta next_char.return + jmp b3 + //SEG20 main::@3 + b3: + //SEG21 [8] (byte~) main::$0 ← (byte) next_char::return#0 -- vbuz1=vbuz2 + lda next_char.return + sta _0 + //SEG22 [9] *((const byte*) main::SCREEN#0 + (byte) main::i#2) ← (byte~) main::$0 -- pbuc1_derefidx_vbuz1=vbuz2 + lda _0 + ldy i + sta SCREEN,y + //SEG23 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 + inc i + //SEG24 [11] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@1 -- vbuz1_neq_0_then_la1 + lda i + cmp #0 + bne b1_from_b3 + jmp breturn + //SEG25 main::@return + breturn: + //SEG26 [12] return + rts +} +//SEG27 next_char +// Find the next char of the text +next_char: { + .label return = 6 + .label c = 5 + .label return_1 = 5 + //SEG28 [13] (byte) next_char::c#0 ← *((byte*) nxt#13) -- vbuz1=_deref_pbuz2 + ldy #0 + lda (nxt),y + sta c + //SEG29 [14] if((byte) next_char::c#0!=(byte) '@') goto next_char::@1 -- vbuz1_neq_vbuc1_then_la1 + lda c + cmp #'@' + bne b1_from_next_char + jmp b2 + //SEG30 next_char::@2 + b2: + //SEG31 [15] (byte) next_char::c#1 ← *((const byte*) TEXT#0) -- vbuz1=_deref_pbuc1 + lda TEXT + sta c + //SEG32 [16] phi from next_char::@2 to next_char::@1 [phi:next_char::@2->next_char::@1] + b1_from_b2: + //SEG33 [16] phi (byte) next_char::return#1 = (byte) next_char::c#1 [phi:next_char::@2->next_char::@1#0] -- register_copy + //SEG34 [16] phi (byte*) nxt#10 = (const byte*) TEXT#0 [phi:next_char::@2->next_char::@1#1] -- pbuz1=pbuc1 + lda #TEXT + sta nxt+1 + jmp b1 + //SEG35 [16] phi from next_char to next_char::@1 [phi:next_char->next_char::@1] + b1_from_next_char: + //SEG36 [16] phi (byte) next_char::return#1 = (byte) next_char::c#0 [phi:next_char->next_char::@1#0] -- register_copy + //SEG37 [16] phi (byte*) nxt#10 = (byte*) nxt#13 [phi:next_char->next_char::@1#1] -- register_copy + jmp b1 + //SEG38 next_char::@1 + b1: + //SEG39 [17] (byte*) nxt#11 ← ++ (byte*) nxt#10 -- pbuz1=_inc_pbuz1 + inc nxt + bne !+ + inc nxt+1 + !: + jmp breturn + //SEG40 next_char::@return + breturn: + //SEG41 [18] return + rts +} + TEXT: .text "cml @" + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [13] (byte) next_char::c#0 ← *((byte*) nxt#13) [ nxt#13 next_char::c#0 ] ( main:2::next_char:6 [ main::i#2 nxt#13 next_char::c#0 ] ) always clobbers reg byte a reg byte y +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ] +Removing always clobbered register reg byte y as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ] +Statement [13] (byte) next_char::c#0 ← *((byte*) nxt#13) [ nxt#13 next_char::c#0 ] ( main:2::next_char:6 [ main::i#2 nxt#13 next_char::c#0 ] ) always clobbers reg byte a reg byte y +Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte x , +Potential registers zp ZP_WORD:3 [ nxt#10 nxt#13 nxt#11 ] : zp ZP_WORD:3 , +Potential registers zp ZP_BYTE:5 [ next_char::return#1 next_char::c#0 next_char::c#1 ] : zp ZP_BYTE:5 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:6 [ next_char::return#0 ] : zp ZP_BYTE:6 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:7 [ main::$0 ] : zp ZP_BYTE:7 , reg byte a , reg byte x , reg byte y , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 23.1: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 22: zp ZP_BYTE:7 [ main::$0 ] +Uplift Scope [next_char] 22: zp ZP_BYTE:6 [ next_char::return#0 ] 10.75: zp ZP_BYTE:5 [ next_char::return#1 next_char::c#0 next_char::c#1 ] +Uplift Scope [] 10.62: zp ZP_WORD:3 [ nxt#10 nxt#13 nxt#11 ] + +Uplifting [main] best 587 combination reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::$0 ] +Uplifting [next_char] best 510 combination reg byte a [ next_char::return#0 ] reg byte y [ next_char::return#1 next_char::c#0 next_char::c#1 ] +Uplifting [] best 510 combination zp ZP_WORD:3 [ nxt#10 nxt#13 nxt#11 ] +Allocated (was zp ZP_WORD:3) zp ZP_WORD:2 [ nxt#10 nxt#13 nxt#11 ] + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +// Clobber problem in next_char return value +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .label nxt = 2 +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @2 [phi:@begin->@2] +b2_from_bbegin: + jmp b2 +//SEG5 @2 +b2: +//SEG6 [2] call main +//SEG7 [4] phi from @2 to main [phi:@2->main] +main_from_b2: + jsr main +//SEG8 [3] phi from @2 to @end [phi:@2->@end] +bend_from_b2: + jmp bend +//SEG9 @end +bend: +//SEG10 main +main: { + .label SCREEN = $400 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + ldx #0 + //SEG13 [5] phi (byte*) nxt#13 = (const byte*) TEXT#0 [phi:main->main::@1#1] -- pbuz1=pbuc1 + lda #TEXT + sta nxt+1 + jmp b1 + //SEG14 [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1] + b1_from_b3: + //SEG15 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@3->main::@1#0] -- register_copy + //SEG16 [5] phi (byte*) nxt#13 = (byte*) nxt#11 [phi:main::@3->main::@1#1] -- register_copy + jmp b1 + //SEG17 main::@1 + b1: + //SEG18 [6] call next_char + jsr next_char + //SEG19 [7] (byte) next_char::return#0 ← (byte) next_char::return#1 -- vbuaa=vbuyy + tya + jmp b3 + //SEG20 main::@3 + b3: + //SEG21 [8] (byte~) main::$0 ← (byte) next_char::return#0 + //SEG22 [9] *((const byte*) main::SCREEN#0 + (byte) main::i#2) ← (byte~) main::$0 -- pbuc1_derefidx_vbuxx=vbuaa + sta SCREEN,x + //SEG23 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx + inx + //SEG24 [11] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@1 -- vbuxx_neq_0_then_la1 + cpx #0 + bne b1_from_b3 + jmp breturn + //SEG25 main::@return + breturn: + //SEG26 [12] return + rts +} +//SEG27 next_char +// Find the next char of the text +next_char: { + //SEG28 [13] (byte) next_char::c#0 ← *((byte*) nxt#13) -- vbuyy=_deref_pbuz1 + ldy #0 + lda (nxt),y + tay + //SEG29 [14] if((byte) next_char::c#0!=(byte) '@') goto next_char::@1 -- vbuyy_neq_vbuc1_then_la1 + cpy #'@' + bne b1_from_next_char + jmp b2 + //SEG30 next_char::@2 + b2: + //SEG31 [15] (byte) next_char::c#1 ← *((const byte*) TEXT#0) -- vbuyy=_deref_pbuc1 + ldy TEXT + //SEG32 [16] phi from next_char::@2 to next_char::@1 [phi:next_char::@2->next_char::@1] + b1_from_b2: + //SEG33 [16] phi (byte) next_char::return#1 = (byte) next_char::c#1 [phi:next_char::@2->next_char::@1#0] -- register_copy + //SEG34 [16] phi (byte*) nxt#10 = (const byte*) TEXT#0 [phi:next_char::@2->next_char::@1#1] -- pbuz1=pbuc1 + lda #TEXT + sta nxt+1 + jmp b1 + //SEG35 [16] phi from next_char to next_char::@1 [phi:next_char->next_char::@1] + b1_from_next_char: + //SEG36 [16] phi (byte) next_char::return#1 = (byte) next_char::c#0 [phi:next_char->next_char::@1#0] -- register_copy + //SEG37 [16] phi (byte*) nxt#10 = (byte*) nxt#13 [phi:next_char->next_char::@1#1] -- register_copy + jmp b1 + //SEG38 next_char::@1 + b1: + //SEG39 [17] (byte*) nxt#11 ← ++ (byte*) nxt#10 -- pbuz1=_inc_pbuz1 + inc nxt + bne !+ + inc nxt+1 + !: + jmp breturn + //SEG40 next_char::@return + breturn: + //SEG41 [18] return + rts +} + TEXT: .text "cml @" + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b2 +Removing instruction jmp bend +Removing instruction jmp b1 +Removing instruction jmp b3 +Removing instruction jmp breturn +Removing instruction jmp b2 +Removing instruction jmp b1 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Replacing label b1_from_b3 with b1 +Replacing label b1_from_next_char with b1 +Removing instruction b2_from_bbegin: +Removing instruction b2: +Removing instruction main_from_b2: +Removing instruction bend_from_b2: +Removing instruction b1_from_b3: +Removing instruction b1_from_next_char: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction b1_from_main: +Removing instruction b3: +Removing instruction breturn: +Removing instruction b2: +Removing instruction b1_from_b2: +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 b1 +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @2 +(label) @begin +(label) @end +(byte*) TEXT +(const byte*) TEXT#0 TEXT = (string) "cml @" +(void()) main() +(byte~) main::$0 reg byte a 22.0 +(label) main::@1 +(label) main::@3 +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400 +(byte) main::i +(byte) main::i#1 reg byte x 16.5 +(byte) main::i#2 reg byte x 6.6000000000000005 +(byte()) next_char() +(label) next_char::@1 +(label) next_char::@2 +(label) next_char::@return +(byte) next_char::c +(byte) next_char::c#0 reg byte y 3.0 +(byte) next_char::c#1 reg byte y 4.0 +(byte) next_char::return +(byte) next_char::return#0 reg byte a 22.0 +(byte) next_char::return#1 reg byte y 3.75 +(byte*) nxt +(byte*) nxt#10 nxt zp ZP_WORD:2 4.0 +(byte*) nxt#11 nxt zp ZP_WORD:2 1.625 +(byte*) nxt#13 nxt zp ZP_WORD:2 5.0 + +reg byte x [ main::i#2 main::i#1 ] +zp ZP_WORD:2 [ nxt#10 nxt#13 nxt#11 ] +reg byte y [ next_char::return#1 next_char::c#0 next_char::c#1 ] +reg byte a [ next_char::return#0 ] +reg byte a [ main::$0 ] + + +FINAL ASSEMBLER +Score: 366 + +//SEG0 File Comments +// Clobber problem in next_char return value +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .label nxt = 2 +//SEG3 @begin +//SEG4 [1] phi from @begin to @2 [phi:@begin->@2] +//SEG5 @2 +//SEG6 [2] call main +//SEG7 [4] phi from @2 to main [phi:@2->main] +//SEG8 [3] phi from @2 to @end [phi:@2->@end] +//SEG9 @end +//SEG10 main +main: { + .label SCREEN = $400 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + //SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + ldx #0 + //SEG13 [5] phi (byte*) nxt#13 = (const byte*) TEXT#0 [phi:main->main::@1#1] -- pbuz1=pbuc1 + lda #TEXT + sta nxt+1 + //SEG14 [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1] + //SEG15 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@3->main::@1#0] -- register_copy + //SEG16 [5] phi (byte*) nxt#13 = (byte*) nxt#11 [phi:main::@3->main::@1#1] -- register_copy + //SEG17 main::@1 + b1: + //SEG18 [6] call next_char + jsr next_char + //SEG19 [7] (byte) next_char::return#0 ← (byte) next_char::return#1 -- vbuaa=vbuyy + tya + //SEG20 main::@3 + //SEG21 [8] (byte~) main::$0 ← (byte) next_char::return#0 + //SEG22 [9] *((const byte*) main::SCREEN#0 + (byte) main::i#2) ← (byte~) main::$0 -- pbuc1_derefidx_vbuxx=vbuaa + sta SCREEN,x + //SEG23 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx + inx + //SEG24 [11] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@1 -- vbuxx_neq_0_then_la1 + cpx #0 + bne b1 + //SEG25 main::@return + //SEG26 [12] return + rts +} +//SEG27 next_char +// Find the next char of the text +next_char: { + //SEG28 [13] (byte) next_char::c#0 ← *((byte*) nxt#13) -- vbuyy=_deref_pbuz1 + ldy #0 + lda (nxt),y + tay + //SEG29 [14] if((byte) next_char::c#0!=(byte) '@') goto next_char::@1 -- vbuyy_neq_vbuc1_then_la1 + cpy #'@' + bne b1 + //SEG30 next_char::@2 + //SEG31 [15] (byte) next_char::c#1 ← *((const byte*) TEXT#0) -- vbuyy=_deref_pbuc1 + ldy TEXT + //SEG32 [16] phi from next_char::@2 to next_char::@1 [phi:next_char::@2->next_char::@1] + //SEG33 [16] phi (byte) next_char::return#1 = (byte) next_char::c#1 [phi:next_char::@2->next_char::@1#0] -- register_copy + //SEG34 [16] phi (byte*) nxt#10 = (const byte*) TEXT#0 [phi:next_char::@2->next_char::@1#1] -- pbuz1=pbuc1 + lda #TEXT + sta nxt+1 + //SEG35 [16] phi from next_char to next_char::@1 [phi:next_char->next_char::@1] + //SEG36 [16] phi (byte) next_char::return#1 = (byte) next_char::c#0 [phi:next_char->next_char::@1#0] -- register_copy + //SEG37 [16] phi (byte*) nxt#10 = (byte*) nxt#13 [phi:next_char->next_char::@1#1] -- register_copy + //SEG38 next_char::@1 + b1: + //SEG39 [17] (byte*) nxt#11 ← ++ (byte*) nxt#10 -- pbuz1=_inc_pbuz1 + inc nxt + bne !+ + inc nxt+1 + !: + //SEG40 next_char::@return + //SEG41 [18] return + rts +} + TEXT: .text "cml @" + diff --git a/src/test/ref/scrollbig-clobber.sym b/src/test/ref/scrollbig-clobber.sym new file mode 100644 index 000000000..23569856c --- /dev/null +++ b/src/test/ref/scrollbig-clobber.sym @@ -0,0 +1,35 @@ +(label) @2 +(label) @begin +(label) @end +(byte*) TEXT +(const byte*) TEXT#0 TEXT = (string) "cml @" +(void()) main() +(byte~) main::$0 reg byte a 22.0 +(label) main::@1 +(label) main::@3 +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400 +(byte) main::i +(byte) main::i#1 reg byte x 16.5 +(byte) main::i#2 reg byte x 6.6000000000000005 +(byte()) next_char() +(label) next_char::@1 +(label) next_char::@2 +(label) next_char::@return +(byte) next_char::c +(byte) next_char::c#0 reg byte y 3.0 +(byte) next_char::c#1 reg byte y 4.0 +(byte) next_char::return +(byte) next_char::return#0 reg byte a 22.0 +(byte) next_char::return#1 reg byte y 3.75 +(byte*) nxt +(byte*) nxt#10 nxt zp ZP_WORD:2 4.0 +(byte*) nxt#11 nxt zp ZP_WORD:2 1.625 +(byte*) nxt#13 nxt zp ZP_WORD:2 5.0 + +reg byte x [ main::i#2 main::i#1 ] +zp ZP_WORD:2 [ nxt#10 nxt#13 nxt#11 ] +reg byte y [ next_char::return#1 next_char::c#0 next_char::c#1 ] +reg byte a [ next_char::return#0 ] +reg byte a [ main::$0 ]