mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-27 19:50:10 +00:00
Fixed clobber problem that can occur during PHI transitions. Closes #10
This commit is contained in:
parent
4d8e083a21
commit
5a83c1b357
@ -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<VariableRef> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
|
24
src/test/kc/scrollbig-clobber.kc
Normal file
24
src/test/kc/scrollbig-clobber.kc
Normal file
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
sta nxt
|
||||
lda #>TEXT
|
||||
|
@ -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
|
||||
|
@ -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 ]
|
||||
|
41
src/test/ref/scrollbig-clobber.asm
Normal file
41
src/test/ref/scrollbig-clobber.asm
Normal file
@ -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
|
||||
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
|
||||
lda #>TEXT
|
||||
sta nxt+1
|
||||
b1:
|
||||
inc nxt
|
||||
bne !+
|
||||
inc nxt+1
|
||||
!:
|
||||
rts
|
||||
}
|
||||
TEXT: .text "cml @"
|
42
src/test/ref/scrollbig-clobber.cfg
Normal file
42
src/test/ref/scrollbig-clobber.cfg
Normal file
@ -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
|
707
src/test/ref/scrollbig-clobber.log
Normal file
707
src/test/ref/scrollbig-clobber.log
Normal file
@ -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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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 @"
|
||||
|
35
src/test/ref/scrollbig-clobber.sym
Normal file
35
src/test/ref/scrollbig-clobber.sym
Normal file
@ -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 ]
|
Loading…
Reference in New Issue
Block a user