diff --git a/src/main/java/dk/camelot64/kickc/asm/AsmProgramStaticRegisterValues.java b/src/main/java/dk/camelot64/kickc/asm/AsmProgramStaticRegisterValues.java index c48d37a13..bb28a445e 100644 --- a/src/main/java/dk/camelot64/kickc/asm/AsmProgramStaticRegisterValues.java +++ b/src/main/java/dk/camelot64/kickc/asm/AsmProgramStaticRegisterValues.java @@ -31,7 +31,7 @@ public class AsmProgramStaticRegisterValues { } else if(parameter.startsWith(">")) { try { int parValue = Integer.parseInt(parameter.substring(1)); - return 0xff & (parValue / 0x100); + return 0xff & ((parValue & 0xffff) / 0x100); } catch(NumberFormatException e) { // ignore } diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 4143ad38c..3e6806665 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -37,6 +37,11 @@ public class TestPrograms { public TestPrograms() { } + @Test + public void testStaticRegisterOptimizationProblem() throws IOException, URISyntaxException { + compileAndCompare("static-register-optimization-problem"); + } + @Test public void testDeclaredNotConstVar1() throws IOException, URISyntaxException { compileAndCompare("declared-notconst-var-1"); diff --git a/src/test/kc/static-register-optimization-problem.kc b/src/test/kc/static-register-optimization-problem.kc new file mode 100644 index 000000000..811ece515 --- /dev/null +++ b/src/test/kc/static-register-optimization-problem.kc @@ -0,0 +1,11 @@ +// https://gitlab.com/camelot/kickc/issues/336 +// ASM Static Register Value analysis erronously believes >-1 == 0 + +void main() { + char* screen = 0x0400; + int lasti = -1; + for(int i=0;i<10;i++) { + screen[i] = -1 == 0 +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +main: { + .label screen = $400 + .label lasti = 4 + .label i = 2 + .label __2 = 6 + lda #<-1 + sta.z lasti + sta.z lasti+1 + lda #<0 + sta.z i + sta.z i+1 + __b1: + lda.z i+1 + bmi __b2 + cmp #>$a + bcc __b2 + bne !+ + lda.z i + cmp #<$a + bcc __b2 + !: + rts + __b2: + lda.z lasti + tax + lda #screen + adc.z i+1 + sta.z __2+1 + txa + ldy #0 + sta (__2),y + lda.z i + sta.z lasti + lda.z i+1 + sta.z lasti+1 + inc.z i + bne !+ + inc.z i+1 + !: + jmp __b1 +} diff --git a/src/test/ref/static-register-optimization-problem.cfg b/src/test/ref/static-register-optimization-problem.cfg new file mode 100644 index 000000000..06c137ff1 --- /dev/null +++ b/src/test/ref/static-register-optimization-problem.cfg @@ -0,0 +1,29 @@ +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() + +(void()) main() +main: scope:[main] from @1 + [4] phi() + to:main::@1 +main::@1: scope:[main] from main main::@2 + [5] (signed word) main::lasti#2 ← phi( main/(signed byte) -1 main::@2/(signed word) main::lasti#1 ) + [5] (signed word) main::i#2 ← phi( main/(signed byte) 0 main::@2/(signed word) main::i#1 ) + [6] if((signed word) main::i#2<(signed byte) $a) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@1 + [7] return + to:@return +main::@2: scope:[main] from main::@1 + [8] (byte~) main::$1 ← < (signed word) main::lasti#2 + [9] (byte*~) main::$2 ← (const byte*) main::screen + (signed word) main::i#2 + [10] *((byte*~) main::$2) ← (byte~) main::$1 + [11] (signed word) main::lasti#1 ← (signed word) main::i#2 + [12] (signed word) main::i#1 ← ++ (signed word) main::i#2 + to:main::@1 diff --git a/src/test/ref/static-register-optimization-problem.log b/src/test/ref/static-register-optimization-problem.log new file mode 100644 index 000000000..bc7cadce9 --- /dev/null +++ b/src/test/ref/static-register-optimization-problem.log @@ -0,0 +1,535 @@ +Identified constant variable (byte*) main::screen +Culled Empty Block (label) main::@4 +Culled Empty Block (label) main::@3 +Culled Empty Block (label) main::@5 +Culled Empty Block (label) main::@6 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 + +(void()) main() +main: scope:[main] from @1 + (byte*) main::screen ← ((byte*)) (number) $400 + (signed word) main::lasti#0 ← (number) -1 + (signed word) main::i#0 ← (number) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (signed word) main::lasti#3 ← phi( main/(signed word) main::lasti#0 main::@2/(signed word) main::lasti#1 ) + (signed word) main::i#2 ← phi( main/(signed word) main::i#0 main::@2/(signed word) main::i#1 ) + (bool~) main::$0 ← (signed word) main::i#2 < (number) $a + if((bool~) main::$0) goto main::@2 + to:main::@return +main::@2: scope:[main] from main::@1 + (signed word) main::i#3 ← phi( main::@1/(signed word) main::i#2 ) + (signed word) main::lasti#2 ← phi( main::@1/(signed word) main::lasti#3 ) + (byte~) main::$1 ← < (signed word) main::lasti#2 + *((byte*) main::screen + (signed word) main::i#3) ← (byte~) main::$1 + (signed word) main::lasti#1 ← (signed word) main::i#3 + (signed word) main::i#1 ← ++ (signed word) main::i#3 + to:main::@1 +main::@return: scope:[main] from main::@1 + 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() +(bool~) main::$0 +(byte~) main::$1 +(label) main::@1 +(label) main::@2 +(label) main::@return +(signed word) main::i +(signed word) main::i#0 +(signed word) main::i#1 +(signed word) main::i#2 +(signed word) main::i#3 +(signed word) main::lasti +(signed word) main::lasti#0 +(signed word) main::lasti#1 +(signed word) main::lasti#2 +(signed word) main::lasti#3 +(byte*) main::screen + +Adding number conversion cast (snumber) -1 in (signed word) main::lasti#0 ← (number) -1 +Adding number conversion cast (snumber) 0 in (signed word) main::i#0 ← (number) 0 +Adding number conversion cast (snumber) $a in (bool~) main::$0 ← (signed word) main::i#2 < (number) $a +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (byte*) main::screen ← (byte*)(number) $400 +Inlining cast (signed word) main::lasti#0 ← (snumber)(number) -1 +Inlining cast (signed word) main::i#0 ← (snumber)(number) 0 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast -1 +Simplifying constant integer cast 0 +Simplifying constant integer cast $a +Successful SSA optimization PassNCastSimplification +Finalized signed number type (signed byte) -1 +Finalized signed number type (signed byte) 0 +Finalized signed number type (signed byte) $a +Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias candidate removed (phi-usage) (signed word) main::i#2 = (signed word) main::i#3 (signed word) main::lasti#1 +Alias (signed word) main::lasti#2 = (signed word) main::lasti#3 +Successful SSA optimization Pass2AliasElimination +Alias candidate removed (phi-usage) (signed word) main::i#2 = (signed word) main::i#3 (signed word) main::lasti#1 +Identical Phi Values (signed word) main::i#3 (signed word) main::i#2 +Successful SSA optimization Pass2IdenticalPhiElimination +Simple Condition (bool~) main::$0 [5] if((signed word) main::i#2<(signed byte) $a) goto main::@2 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant (const byte*) main::screen = (byte*) 1024 +Constant (const signed word) main::lasti#0 = -1 +Constant (const signed word) main::i#0 = 0 +Successful SSA optimization Pass2ConstantIdentification +De-inlining pointer[w] to *(pointer+w) [8] *((const byte*) main::screen + (signed word) main::i#2) ← (byte~) main::$1 +Successful SSA optimization Pass2DeInlineWordDerefIdx +Alias candidate removed (phi-usage) (signed word) main::lasti#1 = (signed word) main::i#2 +Inlining constant with var siblings (const signed word) main::lasti#0 +Inlining constant with var siblings (const signed word) main::i#0 +Constant inlined main::i#0 = (signed byte) 0 +Constant inlined main::lasti#0 = (signed byte) -1 +Successful SSA optimization Pass2ConstantInlining +Alias candidate removed (phi-usage) (signed word) main::lasti#1 = (signed word) main::i#2 +Alias candidate removed (phi-usage) (signed word) main::lasti#1 = (signed word) main::i#2 +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +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 + +Created 2 initial phi equivalence classes +Coalesced [14] main::i#4 ← main::i#1 +Coalesced [15] main::lasti#4 ← main::lasti#1 +Coalesced down to 2 phi equivalence classes +Culled Empty Block (label) @2 +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() + +(void()) main() +main: scope:[main] from @1 + [4] phi() + to:main::@1 +main::@1: scope:[main] from main main::@2 + [5] (signed word) main::lasti#2 ← phi( main/(signed byte) -1 main::@2/(signed word) main::lasti#1 ) + [5] (signed word) main::i#2 ← phi( main/(signed byte) 0 main::@2/(signed word) main::i#1 ) + [6] if((signed word) main::i#2<(signed byte) $a) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@1 + [7] return + to:@return +main::@2: scope:[main] from main::@1 + [8] (byte~) main::$1 ← < (signed word) main::lasti#2 + [9] (byte*~) main::$2 ← (const byte*) main::screen + (signed word) main::i#2 + [10] *((byte*~) main::$2) ← (byte~) main::$1 + [11] (signed word) main::lasti#1 ← (signed word) main::i#2 + [12] (signed word) main::i#1 ← ++ (signed word) main::i#2 + to:main::@1 + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(byte~) main::$1 11.0 +(byte*~) main::$2 22.0 +(signed word) main::i +(signed word) main::i#1 22.0 +(signed word) main::i#2 9.166666666666666 +(signed word) main::lasti +(signed word) main::lasti#1 11.0 +(signed word) main::lasti#2 11.0 + +Initial phi equivalence classes +[ main::i#2 main::i#1 ] +[ main::lasti#2 main::lasti#1 ] +Added variable main::$1 to zero page equivalence class [ main::$1 ] +Added variable main::$2 to zero page equivalence class [ main::$2 ] +Complete equivalence classes +[ main::i#2 main::i#1 ] +[ main::lasti#2 main::lasti#1 ] +[ main::$1 ] +[ main::$2 ] +Allocated zp[2]:2 [ main::i#2 main::i#1 ] +Allocated zp[2]:4 [ main::lasti#2 main::lasti#1 ] +Allocated zp[1]:6 [ main::$1 ] +Allocated zp[2]:7 [ main::$2 ] + +INITIAL ASM +Target platform is c64basic / MOS6502X + // File Comments +// https://gitlab.com/camelot/kickc/issues/336 +// ASM Static Register Value analysis erronously believes >-1 == 0 + // Upstart +.pc = $801 "Basic" +:BasicUpstart(__bbegin) +.pc = $80d "Program" + // Global Constants & labels + // @begin +__bbegin: + // [1] phi from @begin to @1 [phi:@begin->@1] +__b1_from___bbegin: + jmp __b1 + // @1 +__b1: + // [2] call main + // [4] phi from @1 to main [phi:@1->main] +main_from___b1: + jsr main + // [3] phi from @1 to @end [phi:@1->@end] +__bend_from___b1: + jmp __bend + // @end +__bend: + // main +main: { + .label screen = $400 + .label __1 = 6 + .label lasti = 4 + .label i = 2 + .label __2 = 7 + // [5] phi from main to main::@1 [phi:main->main::@1] + __b1_from_main: + // [5] phi (signed word) main::lasti#2 = (signed byte) -1 [phi:main->main::@1#0] -- vwsz1=vbsc1 + lda #<-1 + sta.z lasti + lda #>-1 + sta.z lasti+1 + // [5] phi (signed word) main::i#2 = (signed byte) 0 [phi:main->main::@1#1] -- vwsz1=vbsc1 + lda #<0 + sta.z i + lda #>0 + sta.z i+1 + jmp __b1 + // main::@1 + __b1: + // [6] if((signed word) main::i#2<(signed byte) $a) goto main::@2 -- vwsz1_lt_vwuc1_then_la1 + lda.z i+1 + bmi __b2 + cmp #>$a + bcc __b2 + bne !+ + lda.z i + cmp #<$a + bcc __b2 + !: + jmp __breturn + // main::@return + __breturn: + // [7] return + rts + // main::@2 + __b2: + // [8] (byte~) main::$1 ← < (signed word) main::lasti#2 -- vbuz1=_lo_vwsz2 + lda.z lasti + sta.z __1 + // [9] (byte*~) main::$2 ← (const byte*) main::screen + (signed word) main::i#2 -- pbuz1=pbuc1_plus_vwsz2 + lda #screen + adc.z i+1 + sta.z __2+1 + // [10] *((byte*~) main::$2) ← (byte~) main::$1 -- _deref_pbuz1=vbuz2 + lda.z __1 + ldy #0 + sta (__2),y + // [11] (signed word) main::lasti#1 ← (signed word) main::i#2 -- vwsz1=vwsz2 + lda.z i + sta.z lasti + lda.z i+1 + sta.z lasti+1 + // [12] (signed word) main::i#1 ← ++ (signed word) main::i#2 -- vwsz1=_inc_vwsz1 + inc.z i + bne !+ + inc.z i+1 + !: + // [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + __b1_from___b2: + // [5] phi (signed word) main::lasti#2 = (signed word) main::lasti#1 [phi:main::@2->main::@1#0] -- register_copy + // [5] phi (signed word) main::i#2 = (signed word) main::i#1 [phi:main::@2->main::@1#1] -- register_copy + jmp __b1 +} + // File Data + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [6] if((signed word) main::i#2<(signed byte) $a) goto main::@2 [ main::i#2 main::lasti#2 ] ( main:2 [ main::i#2 main::lasti#2 ] ) always clobbers reg byte a +Statement [8] (byte~) main::$1 ← < (signed word) main::lasti#2 [ main::i#2 main::$1 ] ( main:2 [ main::i#2 main::$1 ] ) always clobbers reg byte a +Statement [9] (byte*~) main::$2 ← (const byte*) main::screen + (signed word) main::i#2 [ main::i#2 main::$1 main::$2 ] ( main:2 [ main::i#2 main::$1 main::$2 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp[1]:6 [ main::$1 ] +Statement [10] *((byte*~) main::$2) ← (byte~) main::$1 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a reg byte y +Statement [11] (signed word) main::lasti#1 ← (signed word) main::i#2 [ main::i#2 main::lasti#1 ] ( main:2 [ main::i#2 main::lasti#1 ] ) always clobbers reg byte a +Statement [6] if((signed word) main::i#2<(signed byte) $a) goto main::@2 [ main::i#2 main::lasti#2 ] ( main:2 [ main::i#2 main::lasti#2 ] ) always clobbers reg byte a +Statement [8] (byte~) main::$1 ← < (signed word) main::lasti#2 [ main::i#2 main::$1 ] ( main:2 [ main::i#2 main::$1 ] ) always clobbers reg byte a +Statement [9] (byte*~) main::$2 ← (const byte*) main::screen + (signed word) main::i#2 [ main::i#2 main::$1 main::$2 ] ( main:2 [ main::i#2 main::$1 main::$2 ] ) always clobbers reg byte a +Statement [10] *((byte*~) main::$2) ← (byte~) main::$1 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a reg byte y +Statement [11] (signed word) main::lasti#1 ← (signed word) main::i#2 [ main::i#2 main::lasti#1 ] ( main:2 [ main::i#2 main::lasti#1 ] ) always clobbers reg byte a +Potential registers zp[2]:2 [ main::i#2 main::i#1 ] : zp[2]:2 , +Potential registers zp[2]:4 [ main::lasti#2 main::lasti#1 ] : zp[2]:4 , +Potential registers zp[1]:6 [ main::$1 ] : zp[1]:6 , reg byte x , reg byte y , +Potential registers zp[2]:7 [ main::$2 ] : zp[2]:7 , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 31.17: zp[2]:2 [ main::i#2 main::i#1 ] 22: zp[2]:4 [ main::lasti#2 main::lasti#1 ] 22: zp[2]:7 [ main::$2 ] 11: zp[1]:6 [ main::$1 ] +Uplift Scope [] + +Uplifting [main] best 1083 combination zp[2]:2 [ main::i#2 main::i#1 ] zp[2]:4 [ main::lasti#2 main::lasti#1 ] zp[2]:7 [ main::$2 ] reg byte x [ main::$1 ] +Uplifting [] best 1083 combination +Allocated (was zp[2]:7) zp[2]:6 [ main::$2 ] + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// https://gitlab.com/camelot/kickc/issues/336 +// ASM Static Register Value analysis erronously believes >-1 == 0 + // Upstart +.pc = $801 "Basic" +:BasicUpstart(__bbegin) +.pc = $80d "Program" + // Global Constants & labels + // @begin +__bbegin: + // [1] phi from @begin to @1 [phi:@begin->@1] +__b1_from___bbegin: + jmp __b1 + // @1 +__b1: + // [2] call main + // [4] phi from @1 to main [phi:@1->main] +main_from___b1: + jsr main + // [3] phi from @1 to @end [phi:@1->@end] +__bend_from___b1: + jmp __bend + // @end +__bend: + // main +main: { + .label screen = $400 + .label lasti = 4 + .label i = 2 + .label __2 = 6 + // [5] phi from main to main::@1 [phi:main->main::@1] + __b1_from_main: + // [5] phi (signed word) main::lasti#2 = (signed byte) -1 [phi:main->main::@1#0] -- vwsz1=vbsc1 + lda #<-1 + sta.z lasti + lda #>-1 + sta.z lasti+1 + // [5] phi (signed word) main::i#2 = (signed byte) 0 [phi:main->main::@1#1] -- vwsz1=vbsc1 + lda #<0 + sta.z i + lda #>0 + sta.z i+1 + jmp __b1 + // main::@1 + __b1: + // [6] if((signed word) main::i#2<(signed byte) $a) goto main::@2 -- vwsz1_lt_vwuc1_then_la1 + lda.z i+1 + bmi __b2 + cmp #>$a + bcc __b2 + bne !+ + lda.z i + cmp #<$a + bcc __b2 + !: + jmp __breturn + // main::@return + __breturn: + // [7] return + rts + // main::@2 + __b2: + // [8] (byte~) main::$1 ← < (signed word) main::lasti#2 -- vbuxx=_lo_vwsz1 + lda.z lasti + tax + // [9] (byte*~) main::$2 ← (const byte*) main::screen + (signed word) main::i#2 -- pbuz1=pbuc1_plus_vwsz2 + lda #screen + adc.z i+1 + sta.z __2+1 + // [10] *((byte*~) main::$2) ← (byte~) main::$1 -- _deref_pbuz1=vbuxx + txa + ldy #0 + sta (__2),y + // [11] (signed word) main::lasti#1 ← (signed word) main::i#2 -- vwsz1=vwsz2 + lda.z i + sta.z lasti + lda.z i+1 + sta.z lasti+1 + // [12] (signed word) main::i#1 ← ++ (signed word) main::i#2 -- vwsz1=_inc_vwsz1 + inc.z i + bne !+ + inc.z i+1 + !: + // [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + __b1_from___b2: + // [5] phi (signed word) main::lasti#2 = (signed word) main::lasti#1 [phi:main::@2->main::@1#0] -- register_copy + // [5] phi (signed word) main::i#2 = (signed word) main::i#1 [phi:main::@2->main::@1#1] -- register_copy + jmp __b1 +} + // File Data + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp __b1 +Removing instruction jmp __bend +Removing instruction jmp __b1 +Removing instruction jmp __breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction lda #>-1 +Removing instruction lda #>0 +Succesful ASM optimization Pass5UnnecesaryLoadElimination +Replacing label __bbegin with __b1 +Removing instruction __bbegin: +Removing instruction __b1_from___bbegin: +Removing instruction main_from___b1: +Removing instruction __bend_from___b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction __bend: +Removing instruction __b1_from_main: +Removing instruction __breturn: +Removing instruction __b1_from___b2: +Succesful ASM optimization Pass5UnusedLabelElimination +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction __b1: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(void()) main() +(byte~) main::$1 reg byte x 11.0 +(byte*~) main::$2 zp[2]:6 22.0 +(label) main::@1 +(label) main::@2 +(label) main::@return +(signed word) main::i +(signed word) main::i#1 i zp[2]:2 22.0 +(signed word) main::i#2 i zp[2]:2 9.166666666666666 +(signed word) main::lasti +(signed word) main::lasti#1 lasti zp[2]:4 11.0 +(signed word) main::lasti#2 lasti zp[2]:4 11.0 +(const byte*) main::screen = (byte*) 1024 + +zp[2]:2 [ main::i#2 main::i#1 ] +zp[2]:4 [ main::lasti#2 main::lasti#1 ] +reg byte x [ main::$1 ] +zp[2]:6 [ main::$2 ] + + +FINAL ASSEMBLER +Score: 971 + + // File Comments +// https://gitlab.com/camelot/kickc/issues/336 +// ASM Static Register Value analysis erronously believes >-1 == 0 + // Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + // Global Constants & labels + // @begin + // [1] phi from @begin to @1 [phi:@begin->@1] + // @1 + // [2] call main + // [4] phi from @1 to main [phi:@1->main] + // [3] phi from @1 to @end [phi:@1->@end] + // @end + // main +main: { + .label screen = $400 + .label lasti = 4 + .label i = 2 + .label __2 = 6 + // [5] phi from main to main::@1 [phi:main->main::@1] + // [5] phi (signed word) main::lasti#2 = (signed byte) -1 [phi:main->main::@1#0] -- vwsz1=vbsc1 + lda #<-1 + sta.z lasti + sta.z lasti+1 + // [5] phi (signed word) main::i#2 = (signed byte) 0 [phi:main->main::@1#1] -- vwsz1=vbsc1 + lda #<0 + sta.z i + sta.z i+1 + // main::@1 + __b1: + // for(int i=0;i<10;i++) + // [6] if((signed word) main::i#2<(signed byte) $a) goto main::@2 -- vwsz1_lt_vwuc1_then_la1 + lda.z i+1 + bmi __b2 + cmp #>$a + bcc __b2 + bne !+ + lda.z i + cmp #<$a + bcc __b2 + !: + // main::@return + // } + // [7] return + rts + // main::@2 + __b2: + // screen + adc.z i+1 + sta.z __2+1 + // [10] *((byte*~) main::$2) ← (byte~) main::$1 -- _deref_pbuz1=vbuxx + txa + ldy #0 + sta (__2),y + // lasti = i + // [11] (signed word) main::lasti#1 ← (signed word) main::i#2 -- vwsz1=vwsz2 + lda.z i + sta.z lasti + lda.z i+1 + sta.z lasti+1 + // for(int i=0;i<10;i++) + // [12] (signed word) main::i#1 ← ++ (signed word) main::i#2 -- vwsz1=_inc_vwsz1 + inc.z i + bne !+ + inc.z i+1 + !: + // [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + // [5] phi (signed word) main::lasti#2 = (signed word) main::lasti#1 [phi:main::@2->main::@1#0] -- register_copy + // [5] phi (signed word) main::i#2 = (signed word) main::i#1 [phi:main::@2->main::@1#1] -- register_copy + jmp __b1 +} + // File Data + diff --git a/src/test/ref/static-register-optimization-problem.sym b/src/test/ref/static-register-optimization-problem.sym new file mode 100644 index 000000000..728e32ca0 --- /dev/null +++ b/src/test/ref/static-register-optimization-problem.sym @@ -0,0 +1,21 @@ +(label) @1 +(label) @begin +(label) @end +(void()) main() +(byte~) main::$1 reg byte x 11.0 +(byte*~) main::$2 zp[2]:6 22.0 +(label) main::@1 +(label) main::@2 +(label) main::@return +(signed word) main::i +(signed word) main::i#1 i zp[2]:2 22.0 +(signed word) main::i#2 i zp[2]:2 9.166666666666666 +(signed word) main::lasti +(signed word) main::lasti#1 lasti zp[2]:4 11.0 +(signed word) main::lasti#2 lasti zp[2]:4 11.0 +(const byte*) main::screen = (byte*) 1024 + +zp[2]:2 [ main::i#2 main::i#1 ] +zp[2]:4 [ main::lasti#2 main::lasti#1 ] +reg byte x [ main::$1 ] +zp[2]:6 [ main::$2 ]