diff --git a/src/main/fragment/vwuz1_gt_vwuc1_then_la1.asm b/src/main/fragment/vwuz1_gt_vwuc1_then_la1.asm new file mode 100644 index 000000000..66322a3c9 --- /dev/null +++ b/src/main/fragment/vwuz1_gt_vwuc1_then_la1.asm @@ -0,0 +1,8 @@ +lda #>{c1} +cmp {z1}+1 +bcc {la1} +bne !+ +lda #<{c1} +cmp {z1} +bcc {la1} +!: diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2ComparisonOptimization.java b/src/main/java/dk/camelot64/kickc/passes/Pass2ComparisonOptimization.java index 984901929..3c9658e9c 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2ComparisonOptimization.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2ComparisonOptimization.java @@ -46,13 +46,12 @@ public class Pass2ComparisonOptimization extends Pass2SsaOptimization { try { constantLiteral = constantValue.calculateLiteral(getScope()); } catch(ConstantNotLiteral e) { - System.out.println(e); // Ignore } if(Operators.GT.equals(operator) && valueType instanceof SymbolTypeInteger && constantLiteral instanceof ConstantInteger) { // Found > C - rewrite to >= C+1 if possible Long longValue = (Long) constantLiteral.getValue(); - if(longValue < ((SymbolTypeInteger) valueType).getMaxValue() && longValue != 0L) { + if(longValue > 0x00L && longValue < 0xffL) { // Rewrite is possible - do it getLog().append("Rewriting conditional comparison " + statement.toString(getProgram(), false)); conditionalJump.setOperator(Operators.GE); @@ -62,7 +61,7 @@ public class Pass2ComparisonOptimization extends Pass2SsaOptimization { if(Operators.LE.equals(operator) && valueType instanceof SymbolTypeInteger && constantLiteral instanceof ConstantInteger) { // Found <= C - rewrite to < C+1 if possible Long longValue = (Long) constantLiteral.getValue(); - if(longValue < ((SymbolTypeInteger) valueType).getMaxValue() && longValue != 0L) { + if(longValue > 0x00L && longValue < 0xffL) { // Rewrite is possible - do it getLog().append("Rewriting conditional comparison " + statement.toString(getProgram(), false)); conditionalJump.setOperator(Operators.LT); diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 054886017..5204a26a7 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -192,6 +192,11 @@ public class TestPrograms { compileAndCompare("comparison-rewriting"); } + @Test + public void testComparisonRewritingPointer() throws IOException, URISyntaxException { + compileAndCompare("comparison-rewriting-pointer", log()); + } + @Test public void testLoopBreakContinue() throws IOException, URISyntaxException { compileAndCompare("loop-break-continue"); diff --git a/src/test/kc/comparison-rewriting-pointer.kc b/src/test/kc/comparison-rewriting-pointer.kc new file mode 100644 index 000000000..3dd54a970 --- /dev/null +++ b/src/test/kc/comparison-rewriting-pointer.kc @@ -0,0 +1,10 @@ +// Test rewriting of constant comparisons for pointers + +void main() { + const byte* screen = $0400; + for(byte* sc =screen;sc<=screen+999;sc++) *sc='a'; + + const byte* cols = $d800; + for(byte* cc =cols+999;cc>cols-1;cc--) *cc=2; + +} \ No newline at end of file diff --git a/src/test/ref/comparison-rewriting-pointer.asm b/src/test/ref/comparison-rewriting-pointer.asm new file mode 100644 index 000000000..bcf05a272 --- /dev/null +++ b/src/test/ref/comparison-rewriting-pointer.asm @@ -0,0 +1,52 @@ +// Test rewriting of constant comparisons for pointers +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +main: { + .label screen = $400 + .label cols = $d800 + .label sc = 2 + .label cc = 2 + lda #screen + sta sc+1 + b1: + lda #'a' + ldy #0 + sta (sc),y + inc sc + bne !+ + inc sc+1 + !: + lda sc+1 + cmp #>screen+$3e7 + bne !+ + lda sc + cmp #cols+$3e7 + sta cc+1 + b2: + lda #2 + ldy #0 + sta (cc),y + lda cc + bne !+ + dec cc+1 + !: + dec cc + lda #>cols-1 + cmp cc+1 + bcc b2 + bne !+ + lda #(const byte*) main::cols#0-(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@2 + [13] return + to:@return diff --git a/src/test/ref/comparison-rewriting-pointer.log b/src/test/ref/comparison-rewriting-pointer.log new file mode 100644 index 000000000..da7550c7d --- /dev/null +++ b/src/test/ref/comparison-rewriting-pointer.log @@ -0,0 +1,520 @@ + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (byte*) main::screen#0 ← ((byte*)) (word/signed word/dword/signed dword) $400 + (byte*) main::sc#0 ← (byte*) main::screen#0 + to:main::@1 +main::@1: scope:[main] from main main::@1 + (byte*) main::sc#2 ← phi( main/(byte*) main::sc#0 main::@1/(byte*) main::sc#1 ) + *((byte*) main::sc#2) ← (byte) 'a' + (byte*) main::sc#1 ← ++ (byte*) main::sc#2 + (byte*~) main::$0 ← (byte*) main::screen#0 + (word/signed word/dword/signed dword) $3e7 + (bool~) main::$1 ← (byte*) main::sc#1 <= (byte*~) main::$0 + if((bool~) main::$1) goto main::@1 + to:main::@2 +main::@2: scope:[main] from main::@1 + (byte*) main::cols#0 ← ((byte*)) (word/dword/signed dword) $d800 + (byte*~) main::$2 ← (byte*) main::cols#0 + (word/signed word/dword/signed dword) $3e7 + (byte*) main::cc#0 ← (byte*~) main::$2 + to:main::@3 +main::@3: scope:[main] from main::@2 main::@3 + (byte*) main::cc#2 ← phi( main::@2/(byte*) main::cc#0 main::@3/(byte*) main::cc#1 ) + *((byte*) main::cc#2) ← (byte/signed byte/word/signed word/dword/signed dword) 2 + (byte*) main::cc#1 ← -- (byte*) main::cc#2 + (byte*~) main::$3 ← (byte*) main::cols#0 - (byte/signed byte/word/signed word/dword/signed dword) 1 + (bool~) main::$4 ← (byte*) main::cc#1 > (byte*~) main::$3 + if((bool~) main::$4) goto main::@3 + to:main::@return +main::@return: scope:[main] from main::@3 + return + to:@return +@1: scope:[] from @begin + call main + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @begin +(label) @end +(void()) main() +(byte*~) main::$0 +(bool~) main::$1 +(byte*~) main::$2 +(byte*~) main::$3 +(bool~) main::$4 +(label) main::@1 +(label) main::@2 +(label) main::@3 +(label) main::@return +(byte*) main::cc +(byte*) main::cc#0 +(byte*) main::cc#1 +(byte*) main::cc#2 +(byte*) main::cols +(byte*) main::cols#0 +(byte*) main::sc +(byte*) main::sc#0 +(byte*) main::sc#1 +(byte*) main::sc#2 +(byte*) main::screen +(byte*) main::screen#0 + +Culled Empty Block (label) @2 +Successful SSA optimization Pass2CullEmptyBlocks +Alias (byte*) main::screen#0 = (byte*) main::sc#0 +Alias (byte*) main::cc#0 = (byte*~) main::$2 +Successful SSA optimization Pass2AliasElimination +Simple Condition (bool~) main::$1 [7] if((byte*) main::sc#1<=(byte*~) main::$0) goto main::@1 +Simple Condition (bool~) main::$4 [16] if((byte*) main::cc#1>(byte*~) main::$3) goto main::@3 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant (const byte*) main::screen#0 = ((byte*))$400 +Constant (const byte*) main::cols#0 = ((byte*))$d800 +Successful SSA optimization Pass2ConstantIdentification +Constant (const byte*) main::$0 = main::screen#0+$3e7 +Constant (const byte*) main::cc#0 = main::cols#0+$3e7 +Constant (const byte*) main::$3 = main::cols#0-1 +Successful SSA optimization Pass2ConstantIdentification +Culled Empty Block (label) main::@2 +Successful SSA optimization Pass2CullEmptyBlocks +Inlining constant with var siblings (const byte*) main::cc#0 +Constant inlined main::$3 = (const byte*) main::cols#0-(byte/signed byte/word/signed word/dword/signed dword) 1 +Constant inlined main::cc#0 = (const byte*) main::cols#0+(word/signed word/dword/signed dword) $3e7 +Constant inlined main::$0 = (const byte*) main::screen#0+(word/signed word/dword/signed dword) $3e7 +Successful SSA optimization Pass2ConstantInlining +Added new block during phi lifting main::@5(between main::@1 and main::@1) +Added new block during phi lifting main::@6(between main::@3 and main::@3) +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +CALL GRAPH +Calls in [] to main:2 + +Created 2 initial phi equivalence classes +Coalesced [14] main::cc#3 ← main::cc#1 +Coalesced [15] main::sc#3 ← main::sc#1 +Coalesced down to 2 phi equivalence classes +Culled Empty Block (label) main::@6 +Culled Empty Block (label) main::@5 +Renumbering block main::@3 to main::@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() +main: scope:[main] from @1 + [4] phi() + to:main::@1 +main::@1: scope:[main] from main main::@1 + [5] (byte*) main::sc#2 ← phi( main/(const byte*) main::screen#0 main::@1/(byte*) main::sc#1 ) + [6] *((byte*) main::sc#2) ← (byte) 'a' + [7] (byte*) main::sc#1 ← ++ (byte*) main::sc#2 + [8] if((byte*) main::sc#1<=(const byte*) main::screen#0+(word/signed word/dword/signed dword) $3e7) goto main::@1 + to:main::@2 +main::@2: scope:[main] from main::@1 main::@2 + [9] (byte*) main::cc#2 ← phi( main::@1/(const byte*) main::cols#0+(word/signed word/dword/signed dword) $3e7 main::@2/(byte*) main::cc#1 ) + [10] *((byte*) main::cc#2) ← (byte/signed byte/word/signed word/dword/signed dword) 2 + [11] (byte*) main::cc#1 ← -- (byte*) main::cc#2 + [12] if((byte*) main::cc#1>(const byte*) main::cols#0-(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@2 + [13] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(byte*) main::cc +(byte*) main::cc#1 16.5 +(byte*) main::cc#2 16.5 +(byte*) main::cols +(byte*) main::sc +(byte*) main::sc#1 16.5 +(byte*) main::sc#2 16.5 +(byte*) main::screen + +Initial phi equivalence classes +[ main::sc#2 main::sc#1 ] +[ main::cc#2 main::cc#1 ] +Complete equivalence classes +[ main::sc#2 main::sc#1 ] +[ main::cc#2 main::cc#1 ] +Allocated zp ZP_WORD:2 [ main::sc#2 main::sc#1 ] +Allocated zp ZP_WORD:4 [ main::cc#2 main::cc#1 ] + +INITIAL ASM +//SEG0 File Comments +// Test rewriting of constant comparisons for pointers +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main +//SEG7 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG9 @end +bend: +//SEG10 main +main: { + .label screen = $400 + .label cols = $d800 + .label sc = 2 + .label cc = 4 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG12 [5] phi (byte*) main::sc#2 = (const byte*) main::screen#0 [phi:main->main::@1#0] -- pbuz1=pbuc1 + lda #screen + sta sc+1 + jmp b1 + //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + b1_from_b1: + //SEG14 [5] phi (byte*) main::sc#2 = (byte*) main::sc#1 [phi:main::@1->main::@1#0] -- register_copy + jmp b1 + //SEG15 main::@1 + b1: + //SEG16 [6] *((byte*) main::sc#2) ← (byte) 'a' -- _deref_pbuz1=vbuc1 + lda #'a' + ldy #0 + sta (sc),y + //SEG17 [7] (byte*) main::sc#1 ← ++ (byte*) main::sc#2 -- pbuz1=_inc_pbuz1 + inc sc + bne !+ + inc sc+1 + !: + //SEG18 [8] if((byte*) main::sc#1<=(const byte*) main::screen#0+(word/signed word/dword/signed dword) $3e7) goto main::@1 -- pbuz1_le_pbuc1_then_la1 + lda sc+1 + cmp #>screen+$3e7 + bne !+ + lda sc + cmp #main::@2] + b2_from_b1: + //SEG20 [9] phi (byte*) main::cc#2 = (const byte*) main::cols#0+(word/signed word/dword/signed dword) $3e7 [phi:main::@1->main::@2#0] -- pbuz1=pbuc1 + lda #cols+$3e7 + sta cc+1 + jmp b2 + //SEG21 [9] phi from main::@2 to main::@2 [phi:main::@2->main::@2] + b2_from_b2: + //SEG22 [9] phi (byte*) main::cc#2 = (byte*) main::cc#1 [phi:main::@2->main::@2#0] -- register_copy + jmp b2 + //SEG23 main::@2 + b2: + //SEG24 [10] *((byte*) main::cc#2) ← (byte/signed byte/word/signed word/dword/signed dword) 2 -- _deref_pbuz1=vbuc1 + lda #2 + ldy #0 + sta (cc),y + //SEG25 [11] (byte*) main::cc#1 ← -- (byte*) main::cc#2 -- pbuz1=_dec_pbuz1 + lda cc + bne !+ + dec cc+1 + !: + dec cc + //SEG26 [12] if((byte*) main::cc#1>(const byte*) main::cols#0-(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@2 -- pbuz1_gt_pbuc1_then_la1 + lda #>cols-1 + cmp cc+1 + bcc b2_from_b2 + bne !+ + lda #(const byte*) main::cols#0-(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@2 [ main::cc#1 ] ( main:2 [ main::cc#1 ] ) always clobbers reg byte a +Potential registers zp ZP_WORD:2 [ main::sc#2 main::sc#1 ] : zp ZP_WORD:2 , +Potential registers zp ZP_WORD:4 [ main::cc#2 main::cc#1 ] : zp ZP_WORD:4 , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 33: zp ZP_WORD:2 [ main::sc#2 main::sc#1 ] 33: zp ZP_WORD:4 [ main::cc#2 main::cc#1 ] +Uplift Scope [] + +Uplifting [main] best 1198 combination zp ZP_WORD:2 [ main::sc#2 main::sc#1 ] zp ZP_WORD:4 [ main::cc#2 main::cc#1 ] +Uplifting [] best 1198 combination +Coalescing zero page register [ zp ZP_WORD:2 [ main::sc#2 main::sc#1 ] ] with [ zp ZP_WORD:4 [ main::cc#2 main::cc#1 ] ] + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +// Test rewriting of constant comparisons for pointers +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main +//SEG7 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG9 @end +bend: +//SEG10 main +main: { + .label screen = $400 + .label cols = $d800 + .label sc = 2 + .label cc = 2 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG12 [5] phi (byte*) main::sc#2 = (const byte*) main::screen#0 [phi:main->main::@1#0] -- pbuz1=pbuc1 + lda #screen + sta sc+1 + jmp b1 + //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + b1_from_b1: + //SEG14 [5] phi (byte*) main::sc#2 = (byte*) main::sc#1 [phi:main::@1->main::@1#0] -- register_copy + jmp b1 + //SEG15 main::@1 + b1: + //SEG16 [6] *((byte*) main::sc#2) ← (byte) 'a' -- _deref_pbuz1=vbuc1 + lda #'a' + ldy #0 + sta (sc),y + //SEG17 [7] (byte*) main::sc#1 ← ++ (byte*) main::sc#2 -- pbuz1=_inc_pbuz1 + inc sc + bne !+ + inc sc+1 + !: + //SEG18 [8] if((byte*) main::sc#1<=(const byte*) main::screen#0+(word/signed word/dword/signed dword) $3e7) goto main::@1 -- pbuz1_le_pbuc1_then_la1 + lda sc+1 + cmp #>screen+$3e7 + bne !+ + lda sc + cmp #main::@2] + b2_from_b1: + //SEG20 [9] phi (byte*) main::cc#2 = (const byte*) main::cols#0+(word/signed word/dword/signed dword) $3e7 [phi:main::@1->main::@2#0] -- pbuz1=pbuc1 + lda #cols+$3e7 + sta cc+1 + jmp b2 + //SEG21 [9] phi from main::@2 to main::@2 [phi:main::@2->main::@2] + b2_from_b2: + //SEG22 [9] phi (byte*) main::cc#2 = (byte*) main::cc#1 [phi:main::@2->main::@2#0] -- register_copy + jmp b2 + //SEG23 main::@2 + b2: + //SEG24 [10] *((byte*) main::cc#2) ← (byte/signed byte/word/signed word/dword/signed dword) 2 -- _deref_pbuz1=vbuc1 + lda #2 + ldy #0 + sta (cc),y + //SEG25 [11] (byte*) main::cc#1 ← -- (byte*) main::cc#2 -- pbuz1=_dec_pbuz1 + lda cc + bne !+ + dec cc+1 + !: + dec cc + //SEG26 [12] if((byte*) main::cc#1>(const byte*) main::cols#0-(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@2 -- pbuz1_gt_pbuc1_then_la1 + lda #>cols-1 + cmp cc+1 + bcc b2_from_b2 + bne !+ + lda #@1] +//SEG5 @1 +//SEG6 [2] call main +//SEG7 [4] phi from @1 to main [phi:@1->main] +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +//SEG9 @end +//SEG10 main +main: { + .label screen = $400 + .label cols = $d800 + .label sc = 2 + .label cc = 2 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + //SEG12 [5] phi (byte*) main::sc#2 = (const byte*) main::screen#0 [phi:main->main::@1#0] -- pbuz1=pbuc1 + lda #screen + sta sc+1 + //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + //SEG14 [5] phi (byte*) main::sc#2 = (byte*) main::sc#1 [phi:main::@1->main::@1#0] -- register_copy + //SEG15 main::@1 + b1: + //SEG16 [6] *((byte*) main::sc#2) ← (byte) 'a' -- _deref_pbuz1=vbuc1 + lda #'a' + ldy #0 + sta (sc),y + //SEG17 [7] (byte*) main::sc#1 ← ++ (byte*) main::sc#2 -- pbuz1=_inc_pbuz1 + inc sc + bne !+ + inc sc+1 + !: + //SEG18 [8] if((byte*) main::sc#1<=(const byte*) main::screen#0+(word/signed word/dword/signed dword) $3e7) goto main::@1 -- pbuz1_le_pbuc1_then_la1 + lda sc+1 + cmp #>screen+$3e7 + bne !+ + lda sc + cmp #main::@2] + //SEG20 [9] phi (byte*) main::cc#2 = (const byte*) main::cols#0+(word/signed word/dword/signed dword) $3e7 [phi:main::@1->main::@2#0] -- pbuz1=pbuc1 + lda #cols+$3e7 + sta cc+1 + //SEG21 [9] phi from main::@2 to main::@2 [phi:main::@2->main::@2] + //SEG22 [9] phi (byte*) main::cc#2 = (byte*) main::cc#1 [phi:main::@2->main::@2#0] -- register_copy + //SEG23 main::@2 + b2: + //SEG24 [10] *((byte*) main::cc#2) ← (byte/signed byte/word/signed word/dword/signed dword) 2 -- _deref_pbuz1=vbuc1 + lda #2 + ldy #0 + sta (cc),y + //SEG25 [11] (byte*) main::cc#1 ← -- (byte*) main::cc#2 -- pbuz1=_dec_pbuz1 + lda cc + bne !+ + dec cc+1 + !: + dec cc + //SEG26 [12] if((byte*) main::cc#1>(const byte*) main::cols#0-(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@2 -- pbuz1_gt_pbuc1_then_la1 + lda #>cols-1 + cmp cc+1 + bcc b2 + bne !+ + lda #$ff+1 - bcc !+ bne b1 lda x - cmp #<$ff+1 + cmp #$ff + beq !+ bcs b1 !: lda #1 diff --git a/src/test/ref/roll-sprite-msb.cfg b/src/test/ref/roll-sprite-msb.cfg index bb1524341..5e2d263fe 100644 --- a/src/test/ref/roll-sprite-msb.cfg +++ b/src/test/ref/roll-sprite-msb.cfg @@ -31,7 +31,7 @@ position_sprite: scope:[position_sprite] from main::@1 [15] (byte~) position_sprite::$1 ← (byte) position_sprite::spriteno#0 << (byte/signed byte/word/signed word/dword/signed dword) 1 [16] (byte~) position_sprite::$2 ← < (word) position_sprite::x#0 [17] *((const byte*) SPRITES_XPOS#0 + (byte~) position_sprite::$1) ← (byte~) position_sprite::$2 - [18] if((word) position_sprite::x#0>=(byte/word/signed word/dword/signed dword) $ff+(byte/signed byte/word/signed word/dword/signed dword) 1) goto position_sprite::@1 + [18] if((word) position_sprite::x#0>(byte/word/signed word/dword/signed dword) $ff) goto position_sprite::@1 to:position_sprite::@2 position_sprite::@2: scope:[position_sprite] from position_sprite [19] (byte/signed byte/word/signed word/dword/signed dword~) position_sprite::$4 ← (byte/signed byte/word/signed word/dword/signed dword) 1 << (byte) position_sprite::spriteno#0 diff --git a/src/test/ref/roll-sprite-msb.log b/src/test/ref/roll-sprite-msb.log index 3e6ecf52d..758573637 100644 --- a/src/test/ref/roll-sprite-msb.log +++ b/src/test/ref/roll-sprite-msb.log @@ -438,7 +438,6 @@ Successful SSA optimization Pass2ConstantIdentification Successful SSA optimization PassNEliminateUnusedVars Resolved ranged next value main::s#1 ← ++ main::s#2 to ++ Resolved ranged comparison value if(main::s#1!=rangelast(0,7)) goto main::@1 to (byte/signed byte/word/signed word/dword/signed dword) 8 -Rewriting conditional comparison if((word) position_sprite::x#0>(byte/word/signed word/dword/signed dword) $ff) goto position_sprite::@1 Inlining constant with var siblings (const word) main::xpos#0 Inlining constant with var siblings (const byte) main::s#0 Constant inlined main::xpos#0 = (byte/word/signed word/dword/signed dword) $c8 @@ -500,7 +499,7 @@ position_sprite: scope:[position_sprite] from main::@1 [15] (byte~) position_sprite::$1 ← (byte) position_sprite::spriteno#0 << (byte/signed byte/word/signed word/dword/signed dword) 1 [16] (byte~) position_sprite::$2 ← < (word) position_sprite::x#0 [17] *((const byte*) SPRITES_XPOS#0 + (byte~) position_sprite::$1) ← (byte~) position_sprite::$2 - [18] if((word) position_sprite::x#0>=(byte/word/signed word/dword/signed dword) $ff+(byte/signed byte/word/signed word/dword/signed dword) 1) goto position_sprite::@1 + [18] if((word) position_sprite::x#0>(byte/word/signed word/dword/signed dword) $ff) goto position_sprite::@1 to:position_sprite::@2 position_sprite::@2: scope:[position_sprite] from position_sprite [19] (byte/signed byte/word/signed word/dword/signed dword~) position_sprite::$4 ← (byte/signed byte/word/signed word/dword/signed dword) 1 << (byte) position_sprite::spriteno#0 @@ -762,13 +761,12 @@ position_sprite: { lda _2 ldy _1 sta SPRITES_XPOS,y - //SEG33 [18] if((word) position_sprite::x#0>=(byte/word/signed word/dword/signed dword) $ff+(byte/signed byte/word/signed word/dword/signed dword) 1) goto position_sprite::@1 -- vwuz1_ge_vwuc1_then_la1 + //SEG33 [18] if((word) position_sprite::x#0>(byte/word/signed word/dword/signed dword) $ff) goto position_sprite::@1 -- vwuz1_gt_vbuc1_then_la1 lda x+1 - cmp #>$ff+1 - bcc !+ bne b1 lda x - cmp #<$ff+1 + cmp #$ff + beq !+ bcs b1 !: jmp b2 @@ -828,7 +826,7 @@ Statement [14] *((const byte*) SPRITES_YPOS#0 + (byte~) position_sprite::$0) ← Statement [15] (byte~) position_sprite::$1 ← (byte) position_sprite::spriteno#0 << (byte/signed byte/word/signed word/dword/signed dword) 1 [ position_sprite::spriteno#0 position_sprite::x#0 position_sprite::$1 ] ( main:2::position_sprite:8 [ main::s#2 main::xpos#2 position_sprite::spriteno#0 position_sprite::x#0 position_sprite::$1 ] ) always clobbers reg byte a Statement [16] (byte~) position_sprite::$2 ← < (word) position_sprite::x#0 [ position_sprite::spriteno#0 position_sprite::x#0 position_sprite::$1 position_sprite::$2 ] ( main:2::position_sprite:8 [ main::s#2 main::xpos#2 position_sprite::spriteno#0 position_sprite::x#0 position_sprite::$1 position_sprite::$2 ] ) always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp ZP_BYTE:9 [ position_sprite::$1 ] -Statement [18] if((word) position_sprite::x#0>=(byte/word/signed word/dword/signed dword) $ff+(byte/signed byte/word/signed word/dword/signed dword) 1) goto position_sprite::@1 [ position_sprite::spriteno#0 ] ( main:2::position_sprite:8 [ main::s#2 main::xpos#2 position_sprite::spriteno#0 ] ) always clobbers reg byte a +Statement [18] if((word) position_sprite::x#0>(byte/word/signed word/dword/signed dword) $ff) goto position_sprite::@1 [ position_sprite::spriteno#0 ] ( main:2::position_sprite:8 [ main::s#2 main::xpos#2 position_sprite::spriteno#0 ] ) always clobbers reg byte a Statement [19] (byte/signed byte/word/signed word/dword/signed dword~) position_sprite::$4 ← (byte/signed byte/word/signed word/dword/signed dword) 1 << (byte) position_sprite::spriteno#0 [ position_sprite::$4 ] ( main:2::position_sprite:8 [ main::s#2 main::xpos#2 position_sprite::$4 ] ) always clobbers reg byte a Statement [20] (byte/word/dword~) position_sprite::$5 ← (byte/signed byte/word/signed word/dword/signed dword~) position_sprite::$4 ^ (byte/word/signed word/dword/signed dword) $ff [ position_sprite::$5 ] ( main:2::position_sprite:8 [ main::s#2 main::xpos#2 position_sprite::$5 ] ) always clobbers reg byte a Statement [21] *((const byte*) SPRITES_XMSB#0) ← *((const byte*) SPRITES_XMSB#0) & (byte/word/dword~) position_sprite::$5 [ ] ( main:2::position_sprite:8 [ main::s#2 main::xpos#2 ] ) always clobbers reg byte a @@ -840,7 +838,7 @@ Statement [13] (byte~) position_sprite::$0 ← (byte) position_sprite::spriteno# Statement [14] *((const byte*) SPRITES_YPOS#0 + (byte~) position_sprite::$0) ← (const byte) position_sprite::y#0 [ position_sprite::spriteno#0 position_sprite::x#0 ] ( main:2::position_sprite:8 [ main::s#2 main::xpos#2 position_sprite::spriteno#0 position_sprite::x#0 ] ) always clobbers reg byte a Statement [15] (byte~) position_sprite::$1 ← (byte) position_sprite::spriteno#0 << (byte/signed byte/word/signed word/dword/signed dword) 1 [ position_sprite::spriteno#0 position_sprite::x#0 position_sprite::$1 ] ( main:2::position_sprite:8 [ main::s#2 main::xpos#2 position_sprite::spriteno#0 position_sprite::x#0 position_sprite::$1 ] ) always clobbers reg byte a Statement [16] (byte~) position_sprite::$2 ← < (word) position_sprite::x#0 [ position_sprite::spriteno#0 position_sprite::x#0 position_sprite::$1 position_sprite::$2 ] ( main:2::position_sprite:8 [ main::s#2 main::xpos#2 position_sprite::spriteno#0 position_sprite::x#0 position_sprite::$1 position_sprite::$2 ] ) always clobbers reg byte a -Statement [18] if((word) position_sprite::x#0>=(byte/word/signed word/dword/signed dword) $ff+(byte/signed byte/word/signed word/dword/signed dword) 1) goto position_sprite::@1 [ position_sprite::spriteno#0 ] ( main:2::position_sprite:8 [ main::s#2 main::xpos#2 position_sprite::spriteno#0 ] ) always clobbers reg byte a +Statement [18] if((word) position_sprite::x#0>(byte/word/signed word/dword/signed dword) $ff) goto position_sprite::@1 [ position_sprite::spriteno#0 ] ( main:2::position_sprite:8 [ main::s#2 main::xpos#2 position_sprite::spriteno#0 ] ) always clobbers reg byte a Statement [19] (byte/signed byte/word/signed word/dword/signed dword~) position_sprite::$4 ← (byte/signed byte/word/signed word/dword/signed dword) 1 << (byte) position_sprite::spriteno#0 [ position_sprite::$4 ] ( main:2::position_sprite:8 [ main::s#2 main::xpos#2 position_sprite::$4 ] ) always clobbers reg byte a Statement [20] (byte/word/dword~) position_sprite::$5 ← (byte/signed byte/word/signed word/dword/signed dword~) position_sprite::$4 ^ (byte/word/signed word/dword/signed dword) $ff [ position_sprite::$5 ] ( main:2::position_sprite:8 [ main::s#2 main::xpos#2 position_sprite::$5 ] ) always clobbers reg byte a Statement [21] *((const byte*) SPRITES_XMSB#0) ← *((const byte*) SPRITES_XMSB#0) & (byte/word/dword~) position_sprite::$5 [ ] ( main:2::position_sprite:8 [ main::s#2 main::xpos#2 ] ) always clobbers reg byte a @@ -862,16 +860,16 @@ Uplift Scope [main] 23.1: zp ZP_BYTE:2 [ main::s#2 main::s#1 ] 15.58: zp ZP_WORD Uplift Scope [position_sprite] 4: zp ZP_BYTE:8 [ position_sprite::$0 ] 4: zp ZP_BYTE:10 [ position_sprite::$2 ] 4: zp ZP_BYTE:11 [ position_sprite::$4 ] 4: zp ZP_BYTE:12 [ position_sprite::$5 ] 4: zp ZP_BYTE:13 [ position_sprite::$6 ] 2.5: zp ZP_WORD:6 [ position_sprite::x#0 ] 2.38: zp ZP_BYTE:5 [ position_sprite::spriteno#0 ] 2: zp ZP_BYTE:9 [ position_sprite::$1 ] Uplift Scope [] -Uplifting [main] best 851 combination reg byte x [ main::s#2 main::s#1 ] zp ZP_WORD:3 [ main::xpos#2 main::xpos#1 ] -Uplifting [position_sprite] best 829 combination reg byte a [ position_sprite::$0 ] reg byte a [ position_sprite::$2 ] reg byte a [ position_sprite::$4 ] reg byte a [ position_sprite::$5 ] zp ZP_BYTE:13 [ position_sprite::$6 ] zp ZP_WORD:6 [ position_sprite::x#0 ] zp ZP_BYTE:5 [ position_sprite::spriteno#0 ] zp ZP_BYTE:9 [ position_sprite::$1 ] +Uplifting [main] best 849 combination reg byte x [ main::s#2 main::s#1 ] zp ZP_WORD:3 [ main::xpos#2 main::xpos#1 ] +Uplifting [position_sprite] best 827 combination reg byte a [ position_sprite::$0 ] reg byte a [ position_sprite::$2 ] reg byte a [ position_sprite::$4 ] reg byte a [ position_sprite::$5 ] zp ZP_BYTE:13 [ position_sprite::$6 ] zp ZP_WORD:6 [ position_sprite::x#0 ] zp ZP_BYTE:5 [ position_sprite::spriteno#0 ] zp ZP_BYTE:9 [ position_sprite::$1 ] Limited combination testing to 100 combinations of 9216 possible. -Uplifting [] best 829 combination +Uplifting [] best 827 combination Attempting to uplift remaining variables inzp ZP_BYTE:13 [ position_sprite::$6 ] -Uplifting [position_sprite] best 823 combination reg byte a [ position_sprite::$6 ] +Uplifting [position_sprite] best 821 combination reg byte a [ position_sprite::$6 ] Attempting to uplift remaining variables inzp ZP_BYTE:5 [ position_sprite::spriteno#0 ] -Uplifting [position_sprite] best 823 combination zp ZP_BYTE:5 [ position_sprite::spriteno#0 ] +Uplifting [position_sprite] best 821 combination zp ZP_BYTE:5 [ position_sprite::spriteno#0 ] Attempting to uplift remaining variables inzp ZP_BYTE:9 [ position_sprite::$1 ] -Uplifting [position_sprite] best 819 combination reg byte y [ position_sprite::$1 ] +Uplifting [position_sprite] best 817 combination reg byte y [ position_sprite::$1 ] Coalescing zero page register with common assignment [ zp ZP_WORD:3 [ main::xpos#2 main::xpos#1 ] ] with [ zp ZP_WORD:6 [ position_sprite::x#0 ] ] - score: 1 Allocated (was zp ZP_WORD:3) zp ZP_WORD:2 [ main::xpos#2 main::xpos#1 position_sprite::x#0 ] Allocated (was zp ZP_BYTE:5) zp ZP_BYTE:4 [ position_sprite::spriteno#0 ] @@ -971,13 +969,12 @@ position_sprite: { lda x //SEG32 [17] *((const byte*) SPRITES_XPOS#0 + (byte~) position_sprite::$1) ← (byte~) position_sprite::$2 -- pbuc1_derefidx_vbuyy=vbuaa sta SPRITES_XPOS,y - //SEG33 [18] if((word) position_sprite::x#0>=(byte/word/signed word/dword/signed dword) $ff+(byte/signed byte/word/signed word/dword/signed dword) 1) goto position_sprite::@1 -- vwuz1_ge_vwuc1_then_la1 + //SEG33 [18] if((word) position_sprite::x#0>(byte/word/signed word/dword/signed dword) $ff) goto position_sprite::@1 -- vwuz1_gt_vbuc1_then_la1 lda x+1 - cmp #>$ff+1 - bcc !+ bne b1 lda x - cmp #<$ff+1 + cmp #$ff + beq !+ bcs b1 !: jmp b2 @@ -1180,7 +1177,7 @@ reg byte a [ position_sprite::$6 ] FINAL ASSEMBLER -Score: 564 +Score: 562 //SEG0 File Comments // Tests rolling sprite MSB by variable amount @@ -1259,13 +1256,12 @@ position_sprite: { lda x //SEG32 [17] *((const byte*) SPRITES_XPOS#0 + (byte~) position_sprite::$1) ← (byte~) position_sprite::$2 -- pbuc1_derefidx_vbuyy=vbuaa sta SPRITES_XPOS,y - //SEG33 [18] if((word) position_sprite::x#0>=(byte/word/signed word/dword/signed dword) $ff+(byte/signed byte/word/signed word/dword/signed dword) 1) goto position_sprite::@1 -- vwuz1_ge_vwuc1_then_la1 + //SEG33 [18] if((word) position_sprite::x#0>(byte/word/signed word/dword/signed dword) $ff) goto position_sprite::@1 -- vwuz1_gt_vbuc1_then_la1 lda x+1 - cmp #>$ff+1 - bcc !+ bne b1 lda x - cmp #<$ff+1 + cmp #$ff + beq !+ bcs b1 !: //SEG34 position_sprite::@2