From 5642c8d22889cb5e9bc9999b9662ce9f0bf2cb40 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Sat, 24 Aug 2019 12:18:56 +0200 Subject: [PATCH] Added pointer ANDing test case. --- src/main/fragment/vbuaa=_hi__deref_pwsc1.asm | 1 + .../vwsz1=_deref_pwsc1_band_vwsc2.asm | 6 + .../dk/camelot64/kickc/test/TestPrograms.java | 5 + src/test/kc/pointer-anding.kc | 12 + src/test/ref/pointer-anding.kc.asm | 61 ++ src/test/ref/pointer-anding.kc.cfg | 31 + src/test/ref/pointer-anding.kc.log | 644 ++++++++++++++++++ src/test/ref/pointer-anding.kc.sym | 27 + 8 files changed, 787 insertions(+) create mode 100644 src/main/fragment/vbuaa=_hi__deref_pwsc1.asm create mode 100644 src/main/fragment/vwsz1=_deref_pwsc1_band_vwsc2.asm create mode 100644 src/test/kc/pointer-anding.kc create mode 100644 src/test/ref/pointer-anding.kc.asm create mode 100644 src/test/ref/pointer-anding.kc.cfg create mode 100644 src/test/ref/pointer-anding.kc.log create mode 100644 src/test/ref/pointer-anding.kc.sym diff --git a/src/main/fragment/vbuaa=_hi__deref_pwsc1.asm b/src/main/fragment/vbuaa=_hi__deref_pwsc1.asm new file mode 100644 index 000000000..a836deba0 --- /dev/null +++ b/src/main/fragment/vbuaa=_hi__deref_pwsc1.asm @@ -0,0 +1 @@ +lda {c1}+1 \ No newline at end of file diff --git a/src/main/fragment/vwsz1=_deref_pwsc1_band_vwsc2.asm b/src/main/fragment/vwsz1=_deref_pwsc1_band_vwsc2.asm new file mode 100644 index 000000000..b1cbe99ae --- /dev/null +++ b/src/main/fragment/vwsz1=_deref_pwsc1_band_vwsc2.asm @@ -0,0 +1,6 @@ +lda {c1} +and #<{c2} +sta {z1} +lda {c1}+1 +and #>{c2} +sta {z1}+1 diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index a6e064b5f..0de71ce2b 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -47,6 +47,11 @@ public class TestPrograms { @Test public void testLongPointer0() throws IOException, URISyntaxException { + compileAndCompare("pointer-anding.kc"); + } + + @Test + public void testPointerAnding() throws IOException, URISyntaxException { compileAndCompare("long-pointer-0"); } diff --git a/src/test/kc/pointer-anding.kc b/src/test/kc/pointer-anding.kc new file mode 100644 index 000000000..ee92daac9 --- /dev/null +++ b/src/test/kc/pointer-anding.kc @@ -0,0 +1,12 @@ +// Test binary ANDing pointers by Clay Cowgill + +void main() { + int* pos_ptr = 0x0400; + byte* vram_ptr = 0x0428; + for( char i:0..2) { + *pos_ptr=(int)0x55AA; + *vram_ptr++=<(*pos_ptr&(int)0xAA55); // stores 0x00 + *vram_ptr++=>*pos_ptr; // stores 0x55 + pos_ptr++; + } +} \ No newline at end of file diff --git a/src/test/ref/pointer-anding.kc.asm b/src/test/ref/pointer-anding.kc.asm new file mode 100644 index 000000000..59b36de9e --- /dev/null +++ b/src/test/ref/pointer-anding.kc.asm @@ -0,0 +1,61 @@ +// Test binary ANDing pointers by Clay Cowgill +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .const SIZEOF_SIGNED_WORD = 2 +main: { + .label _2 = 6 + .label vram_ptr = 4 + .label pos_ptr = 2 + ldx #0 + lda #<$428 + sta.z vram_ptr + lda #>$428 + sta.z vram_ptr+1 + lda #<$400 + sta.z pos_ptr + lda #>$400 + sta.z pos_ptr+1 + b1: + ldy #0 + lda #<$55aa + sta (pos_ptr),y + iny + lda #>$55aa + sta (pos_ptr),y + ldy #0 + lda (pos_ptr),y + and #<$aa55 + sta.z _2 + iny + lda (pos_ptr),y + and #>$aa55 + sta.z _2+1 + lda.z _2 + ldy #0 + sta (vram_ptr),y + inc.z vram_ptr + bne !+ + inc.z vram_ptr+1 + !: + ldy #1 + lda (pos_ptr),y + // stores 0x00 + ldy #0 + sta (vram_ptr),y + inc.z vram_ptr + bne !+ + inc.z vram_ptr+1 + !: + lda #SIZEOF_SIGNED_WORD + clc + adc.z pos_ptr + sta.z pos_ptr + bcc !+ + inc.z pos_ptr+1 + !: + inx + cpx #3 + bne b1 + rts +} diff --git a/src/test/ref/pointer-anding.kc.cfg b/src/test/ref/pointer-anding.kc.cfg new file mode 100644 index 000000000..3d09cdcad --- /dev/null +++ b/src/test/ref/pointer-anding.kc.cfg @@ -0,0 +1,31 @@ +@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::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 ) + [5] (byte*) main::vram_ptr#3 ← phi( main/(byte*) 1064 main::@1/(byte*) main::vram_ptr#2 ) + [5] (signed word*) main::pos_ptr#2 ← phi( main/(signed word*) 1024 main::@1/(signed word*) main::pos_ptr#1 ) + [6] *((signed word*) main::pos_ptr#2) ← (signed word) $55aa + [7] (signed word~) main::$2 ← *((signed word*) main::pos_ptr#2) & (signed word) $aa55 + [8] (byte~) main::$3 ← < (signed word~) main::$2 + [9] *((byte*) main::vram_ptr#3) ← (byte~) main::$3 + [10] (byte*) main::vram_ptr#1 ← ++ (byte*) main::vram_ptr#3 + [11] (byte~) main::$4 ← > *((signed word*) main::pos_ptr#2) + [12] *((byte*) main::vram_ptr#1) ← (byte~) main::$4 + [13] (byte*) main::vram_ptr#2 ← ++ (byte*) main::vram_ptr#1 + [14] (signed word*) main::pos_ptr#1 ← (signed word*) main::pos_ptr#2 + (const byte) SIZEOF_SIGNED_WORD + [15] (byte) main::i#1 ← ++ (byte) main::i#2 + [16] if((byte) main::i#1!=(byte) 3) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@1 + [17] return + to:@return diff --git a/src/test/ref/pointer-anding.kc.log b/src/test/ref/pointer-anding.kc.log new file mode 100644 index 000000000..86c7294fd --- /dev/null +++ b/src/test/ref/pointer-anding.kc.log @@ -0,0 +1,644 @@ +Fixing pointer increment (signed word*) main::pos_ptr ← ++ (signed word*) main::pos_ptr +Culled Empty Block (label) main::@2 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (signed word*) main::pos_ptr#0 ← ((signed word*)) (number) $400 + (byte*) main::vram_ptr#0 ← ((byte*)) (number) $428 + (byte) main::i#0 ← (byte) 0 + to:main::@1 +main::@1: scope:[main] from main main::@1 + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 ) + (byte*) main::vram_ptr#3 ← phi( main/(byte*) main::vram_ptr#0 main::@1/(byte*) main::vram_ptr#2 ) + (signed word*) main::pos_ptr#2 ← phi( main/(signed word*) main::pos_ptr#0 main::@1/(signed word*) main::pos_ptr#1 ) + (signed word~) main::$0 ← ((signed word)) (number) $55aa + *((signed word*) main::pos_ptr#2) ← (signed word~) main::$0 + (signed word~) main::$1 ← ((signed word)) (number) $aa55 + (signed word~) main::$2 ← *((signed word*) main::pos_ptr#2) & (signed word~) main::$1 + (byte~) main::$3 ← < (signed word~) main::$2 + *((byte*) main::vram_ptr#3) ← (byte~) main::$3 + (byte*) main::vram_ptr#1 ← ++ (byte*) main::vram_ptr#3 + (byte~) main::$4 ← > *((signed word*) main::pos_ptr#2) + *((byte*) main::vram_ptr#1) ← (byte~) main::$4 + (byte*) main::vram_ptr#2 ← ++ (byte*) main::vram_ptr#1 + (signed word*) main::pos_ptr#1 ← (signed word*) main::pos_ptr#2 + (const byte) SIZEOF_SIGNED_WORD + (byte) main::i#1 ← (byte) main::i#2 + rangenext(0,2) + (bool~) main::$5 ← (byte) main::i#1 != rangelast(0,2) + if((bool~) main::$5) goto main::@1 + to:main::@return +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 +(const byte) SIZEOF_SIGNED_WORD = (byte) 2 +(void()) main() +(signed word~) main::$0 +(signed word~) main::$1 +(signed word~) main::$2 +(byte~) main::$3 +(byte~) main::$4 +(bool~) main::$5 +(label) main::@1 +(label) main::@return +(byte) main::i +(byte) main::i#0 +(byte) main::i#1 +(byte) main::i#2 +(signed word*) main::pos_ptr +(signed word*) main::pos_ptr#0 +(signed word*) main::pos_ptr#1 +(signed word*) main::pos_ptr#2 +(byte*) main::vram_ptr +(byte*) main::vram_ptr#0 +(byte*) main::vram_ptr#1 +(byte*) main::vram_ptr#2 +(byte*) main::vram_ptr#3 + +Inlining cast (signed word*) main::pos_ptr#0 ← (signed word*)(number) $400 +Inlining cast (byte*) main::vram_ptr#0 ← (byte*)(number) $428 +Inlining cast (signed word~) main::$0 ← (signed word)(number) $55aa +Inlining cast (signed word~) main::$1 ← (signed word)(number) $aa55 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (signed word*) 1024 +Simplifying constant pointer cast (byte*) 1064 +Simplifying constant integer cast $55aa +Simplifying constant integer cast $aa55 +Successful SSA optimization PassNCastSimplification +Simple Condition (bool~) main::$5 [17] if((byte) main::i#1!=rangelast(0,2)) goto main::@1 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant (const signed word*) main::pos_ptr#0 = (signed word*) 1024 +Constant (const byte*) main::vram_ptr#0 = (byte*) 1064 +Constant (const byte) main::i#0 = 0 +Constant (const signed word) main::$0 = $55aa +Constant (const signed word) main::$1 = $aa55 +Successful SSA optimization Pass2ConstantIdentification +Resolved ranged next value [15] main::i#1 ← ++ main::i#2 to ++ +Resolved ranged comparison value [17] if(main::i#1!=rangelast(0,2)) goto main::@1 to (number) 3 +Adding number conversion cast (unumber) 3 in if((byte) main::i#1!=(number) 3) goto main::@1 +Successful SSA optimization PassNAddNumberTypeConversions +Simplifying constant integer cast 3 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 3 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Inlining constant with var siblings (const signed word*) main::pos_ptr#0 +Inlining constant with var siblings (const byte*) main::vram_ptr#0 +Inlining constant with var siblings (const byte) main::i#0 +Constant inlined main::vram_ptr#0 = (byte*) 1064 +Constant inlined main::i#0 = (byte) 0 +Constant inlined main::$1 = (signed word) $aa55 +Constant inlined main::pos_ptr#0 = (signed word*) 1024 +Constant inlined main::$0 = (signed word) $55aa +Successful SSA optimization Pass2ConstantInlining +Added new block during phi lifting main::@3(between main::@1 and main::@1) +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 3 initial phi equivalence classes +Coalesced [19] main::pos_ptr#3 ← main::pos_ptr#1 +Coalesced [20] main::vram_ptr#4 ← main::vram_ptr#2 +Coalesced [21] main::i#3 ← main::i#1 +Coalesced down to 3 phi equivalence classes +Culled Empty Block (label) @2 +Culled Empty Block (label) 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 + +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::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 ) + [5] (byte*) main::vram_ptr#3 ← phi( main/(byte*) 1064 main::@1/(byte*) main::vram_ptr#2 ) + [5] (signed word*) main::pos_ptr#2 ← phi( main/(signed word*) 1024 main::@1/(signed word*) main::pos_ptr#1 ) + [6] *((signed word*) main::pos_ptr#2) ← (signed word) $55aa + [7] (signed word~) main::$2 ← *((signed word*) main::pos_ptr#2) & (signed word) $aa55 + [8] (byte~) main::$3 ← < (signed word~) main::$2 + [9] *((byte*) main::vram_ptr#3) ← (byte~) main::$3 + [10] (byte*) main::vram_ptr#1 ← ++ (byte*) main::vram_ptr#3 + [11] (byte~) main::$4 ← > *((signed word*) main::pos_ptr#2) + [12] *((byte*) main::vram_ptr#1) ← (byte~) main::$4 + [13] (byte*) main::vram_ptr#2 ← ++ (byte*) main::vram_ptr#1 + [14] (signed word*) main::pos_ptr#1 ← (signed word*) main::pos_ptr#2 + (const byte) SIZEOF_SIGNED_WORD + [15] (byte) main::i#1 ← ++ (byte) main::i#2 + [16] if((byte) main::i#1!=(byte) 3) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@1 + [17] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(signed word~) main::$2 22.0 +(byte~) main::$3 22.0 +(byte~) main::$4 22.0 +(byte) main::i +(byte) main::i#1 16.5 +(byte) main::i#2 2.2 +(signed word*) main::pos_ptr +(signed word*) main::pos_ptr#1 7.333333333333333 +(signed word*) main::pos_ptr#2 6.111111111111112 +(byte*) main::vram_ptr +(byte*) main::vram_ptr#1 11.0 +(byte*) main::vram_ptr#2 5.5 +(byte*) main::vram_ptr#3 6.6000000000000005 + +Initial phi equivalence classes +[ main::pos_ptr#2 main::pos_ptr#1 ] +[ main::vram_ptr#3 main::vram_ptr#2 ] +[ main::i#2 main::i#1 ] +Added variable main::$2 to zero page equivalence class [ main::$2 ] +Added variable main::$3 to zero page equivalence class [ main::$3 ] +Added variable main::vram_ptr#1 to zero page equivalence class [ main::vram_ptr#1 ] +Added variable main::$4 to zero page equivalence class [ main::$4 ] +Complete equivalence classes +[ main::pos_ptr#2 main::pos_ptr#1 ] +[ main::vram_ptr#3 main::vram_ptr#2 ] +[ main::i#2 main::i#1 ] +[ main::$2 ] +[ main::$3 ] +[ main::vram_ptr#1 ] +[ main::$4 ] +Allocated zp ZP_WORD:2 [ main::pos_ptr#2 main::pos_ptr#1 ] +Allocated zp ZP_WORD:4 [ main::vram_ptr#3 main::vram_ptr#2 ] +Allocated zp ZP_BYTE:6 [ main::i#2 main::i#1 ] +Allocated zp ZP_WORD:7 [ main::$2 ] +Allocated zp ZP_BYTE:9 [ main::$3 ] +Allocated zp ZP_WORD:10 [ main::vram_ptr#1 ] +Allocated zp ZP_BYTE:12 [ main::$4 ] + +INITIAL ASM +Target platform is c64basic + // File Comments +// Test binary ANDing pointers by Clay Cowgill + // Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" + // Global Constants & labels + .const SIZEOF_SIGNED_WORD = 2 + // @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 _2 = 7 + .label _3 = 9 + .label _4 = $c + .label vram_ptr = $a + .label vram_ptr_2 = 4 + .label pos_ptr = 2 + .label i = 6 + .label vram_ptr_3 = 4 + // [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + // [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 + lda #0 + sta.z i + // [5] phi (byte*) main::vram_ptr#3 = (byte*) 1064 [phi:main->main::@1#1] -- pbuz1=pbuc1 + lda #<$428 + sta.z vram_ptr_3 + lda #>$428 + sta.z vram_ptr_3+1 + // [5] phi (signed word*) main::pos_ptr#2 = (signed word*) 1024 [phi:main->main::@1#2] -- pwsz1=pwsc1 + lda #<$400 + sta.z pos_ptr + lda #>$400 + sta.z pos_ptr+1 + jmp b1 + // [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + b1_from_b1: + // [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + // [5] phi (byte*) main::vram_ptr#3 = (byte*) main::vram_ptr#2 [phi:main::@1->main::@1#1] -- register_copy + // [5] phi (signed word*) main::pos_ptr#2 = (signed word*) main::pos_ptr#1 [phi:main::@1->main::@1#2] -- register_copy + jmp b1 + // main::@1 + b1: + // [6] *((signed word*) main::pos_ptr#2) ← (signed word) $55aa -- _deref_pwsz1=vwsc1 + ldy #0 + lda #<$55aa + sta (pos_ptr),y + iny + lda #>$55aa + sta (pos_ptr),y + // [7] (signed word~) main::$2 ← *((signed word*) main::pos_ptr#2) & (signed word) $aa55 -- vwsz1=_deref_pwsz2_band_vwsc1 + ldy #0 + lda (pos_ptr),y + and #<$aa55 + sta.z _2 + iny + lda (pos_ptr),y + and #>$aa55 + sta.z _2+1 + // [8] (byte~) main::$3 ← < (signed word~) main::$2 -- vbuz1=_lo_vwsz2 + lda.z _2 + sta.z _3 + // [9] *((byte*) main::vram_ptr#3) ← (byte~) main::$3 -- _deref_pbuz1=vbuz2 + lda.z _3 + ldy #0 + sta (vram_ptr_3),y + // [10] (byte*) main::vram_ptr#1 ← ++ (byte*) main::vram_ptr#3 -- pbuz1=_inc_pbuz2 + lda.z vram_ptr_3 + clc + adc #1 + sta.z vram_ptr + lda.z vram_ptr_3+1 + adc #0 + sta.z vram_ptr+1 + // [11] (byte~) main::$4 ← > *((signed word*) main::pos_ptr#2) -- vbuz1=_hi__deref_pwsz2 + ldy #1 + lda (pos_ptr),y + sta.z _4 + // [12] *((byte*) main::vram_ptr#1) ← (byte~) main::$4 -- _deref_pbuz1=vbuz2 + // stores 0x00 + lda.z _4 + ldy #0 + sta (vram_ptr),y + // [13] (byte*) main::vram_ptr#2 ← ++ (byte*) main::vram_ptr#1 -- pbuz1=_inc_pbuz2 + lda.z vram_ptr + clc + adc #1 + sta.z vram_ptr_2 + lda.z vram_ptr+1 + adc #0 + sta.z vram_ptr_2+1 + // [14] (signed word*) main::pos_ptr#1 ← (signed word*) main::pos_ptr#2 + (const byte) SIZEOF_SIGNED_WORD -- pwsz1=pwsz1_plus_vbuc1 + lda #SIZEOF_SIGNED_WORD + clc + adc.z pos_ptr + sta.z pos_ptr + bcc !+ + inc.z pos_ptr+1 + !: + // [15] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 + inc.z i + // [16] if((byte) main::i#1!=(byte) 3) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 + lda #3 + cmp.z i + bne b1_from_b1 + jmp breturn + // main::@return + breturn: + // [17] return + rts +} + // File Data + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [6] *((signed word*) main::pos_ptr#2) ← (signed word) $55aa [ main::pos_ptr#2 main::vram_ptr#3 main::i#2 ] ( main:2 [ main::pos_ptr#2 main::vram_ptr#3 main::i#2 ] ) always clobbers reg byte a reg byte y +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:6 [ main::i#2 main::i#1 ] +Removing always clobbered register reg byte y as potential for zp ZP_BYTE:6 [ main::i#2 main::i#1 ] +Statement [7] (signed word~) main::$2 ← *((signed word*) main::pos_ptr#2) & (signed word) $aa55 [ main::pos_ptr#2 main::vram_ptr#3 main::i#2 main::$2 ] ( main:2 [ main::pos_ptr#2 main::vram_ptr#3 main::i#2 main::$2 ] ) always clobbers reg byte a reg byte y +Statement [8] (byte~) main::$3 ← < (signed word~) main::$2 [ main::pos_ptr#2 main::vram_ptr#3 main::i#2 main::$3 ] ( main:2 [ main::pos_ptr#2 main::vram_ptr#3 main::i#2 main::$3 ] ) always clobbers reg byte a +Statement [9] *((byte*) main::vram_ptr#3) ← (byte~) main::$3 [ main::pos_ptr#2 main::vram_ptr#3 main::i#2 ] ( main:2 [ main::pos_ptr#2 main::vram_ptr#3 main::i#2 ] ) always clobbers reg byte y +Statement [10] (byte*) main::vram_ptr#1 ← ++ (byte*) main::vram_ptr#3 [ main::pos_ptr#2 main::i#2 main::vram_ptr#1 ] ( main:2 [ main::pos_ptr#2 main::i#2 main::vram_ptr#1 ] ) always clobbers reg byte a +Statement [11] (byte~) main::$4 ← > *((signed word*) main::pos_ptr#2) [ main::pos_ptr#2 main::i#2 main::vram_ptr#1 main::$4 ] ( main:2 [ main::pos_ptr#2 main::i#2 main::vram_ptr#1 main::$4 ] ) always clobbers reg byte a reg byte y +Statement [12] *((byte*) main::vram_ptr#1) ← (byte~) main::$4 [ main::pos_ptr#2 main::i#2 main::vram_ptr#1 ] ( main:2 [ main::pos_ptr#2 main::i#2 main::vram_ptr#1 ] ) always clobbers reg byte y +Statement [13] (byte*) main::vram_ptr#2 ← ++ (byte*) main::vram_ptr#1 [ main::pos_ptr#2 main::i#2 main::vram_ptr#2 ] ( main:2 [ main::pos_ptr#2 main::i#2 main::vram_ptr#2 ] ) always clobbers reg byte a +Statement [14] (signed word*) main::pos_ptr#1 ← (signed word*) main::pos_ptr#2 + (const byte) SIZEOF_SIGNED_WORD [ main::i#2 main::pos_ptr#1 main::vram_ptr#2 ] ( main:2 [ main::i#2 main::pos_ptr#1 main::vram_ptr#2 ] ) always clobbers reg byte a +Statement [6] *((signed word*) main::pos_ptr#2) ← (signed word) $55aa [ main::pos_ptr#2 main::vram_ptr#3 main::i#2 ] ( main:2 [ main::pos_ptr#2 main::vram_ptr#3 main::i#2 ] ) always clobbers reg byte a reg byte y +Statement [7] (signed word~) main::$2 ← *((signed word*) main::pos_ptr#2) & (signed word) $aa55 [ main::pos_ptr#2 main::vram_ptr#3 main::i#2 main::$2 ] ( main:2 [ main::pos_ptr#2 main::vram_ptr#3 main::i#2 main::$2 ] ) always clobbers reg byte a reg byte y +Statement [8] (byte~) main::$3 ← < (signed word~) main::$2 [ main::pos_ptr#2 main::vram_ptr#3 main::i#2 main::$3 ] ( main:2 [ main::pos_ptr#2 main::vram_ptr#3 main::i#2 main::$3 ] ) always clobbers reg byte a +Statement [9] *((byte*) main::vram_ptr#3) ← (byte~) main::$3 [ main::pos_ptr#2 main::vram_ptr#3 main::i#2 ] ( main:2 [ main::pos_ptr#2 main::vram_ptr#3 main::i#2 ] ) always clobbers reg byte y +Statement [10] (byte*) main::vram_ptr#1 ← ++ (byte*) main::vram_ptr#3 [ main::pos_ptr#2 main::i#2 main::vram_ptr#1 ] ( main:2 [ main::pos_ptr#2 main::i#2 main::vram_ptr#1 ] ) always clobbers reg byte a +Statement [11] (byte~) main::$4 ← > *((signed word*) main::pos_ptr#2) [ main::pos_ptr#2 main::i#2 main::vram_ptr#1 main::$4 ] ( main:2 [ main::pos_ptr#2 main::i#2 main::vram_ptr#1 main::$4 ] ) always clobbers reg byte a reg byte y +Statement [12] *((byte*) main::vram_ptr#1) ← (byte~) main::$4 [ main::pos_ptr#2 main::i#2 main::vram_ptr#1 ] ( main:2 [ main::pos_ptr#2 main::i#2 main::vram_ptr#1 ] ) always clobbers reg byte y +Statement [13] (byte*) main::vram_ptr#2 ← ++ (byte*) main::vram_ptr#1 [ main::pos_ptr#2 main::i#2 main::vram_ptr#2 ] ( main:2 [ main::pos_ptr#2 main::i#2 main::vram_ptr#2 ] ) always clobbers reg byte a +Statement [14] (signed word*) main::pos_ptr#1 ← (signed word*) main::pos_ptr#2 + (const byte) SIZEOF_SIGNED_WORD [ main::i#2 main::pos_ptr#1 main::vram_ptr#2 ] ( main:2 [ main::i#2 main::pos_ptr#1 main::vram_ptr#2 ] ) always clobbers reg byte a +Potential registers zp ZP_WORD:2 [ main::pos_ptr#2 main::pos_ptr#1 ] : zp ZP_WORD:2 , +Potential registers zp ZP_WORD:4 [ main::vram_ptr#3 main::vram_ptr#2 ] : zp ZP_WORD:4 , +Potential registers zp ZP_BYTE:6 [ main::i#2 main::i#1 ] : zp ZP_BYTE:6 , reg byte x , +Potential registers zp ZP_WORD:7 [ main::$2 ] : zp ZP_WORD:7 , +Potential registers zp ZP_BYTE:9 [ main::$3 ] : zp ZP_BYTE:9 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_WORD:10 [ main::vram_ptr#1 ] : zp ZP_WORD:10 , +Potential registers zp ZP_BYTE:12 [ main::$4 ] : zp ZP_BYTE:12 , reg byte a , reg byte x , reg byte y , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 22: zp ZP_WORD:7 [ main::$2 ] 22: zp ZP_BYTE:9 [ main::$3 ] 22: zp ZP_BYTE:12 [ main::$4 ] 18.7: zp ZP_BYTE:6 [ main::i#2 main::i#1 ] 13.44: zp ZP_WORD:2 [ main::pos_ptr#2 main::pos_ptr#1 ] 12.1: zp ZP_WORD:4 [ main::vram_ptr#3 main::vram_ptr#2 ] 11: zp ZP_WORD:10 [ main::vram_ptr#1 ] +Uplift Scope [] + +Uplifting [main] best 1643 combination zp ZP_WORD:7 [ main::$2 ] reg byte a [ main::$3 ] reg byte a [ main::$4 ] reg byte x [ main::i#2 main::i#1 ] zp ZP_WORD:2 [ main::pos_ptr#2 main::pos_ptr#1 ] zp ZP_WORD:4 [ main::vram_ptr#3 main::vram_ptr#2 ] zp ZP_WORD:10 [ main::vram_ptr#1 ] +Uplifting [] best 1643 combination +Coalescing zero page register [ zp ZP_WORD:4 [ main::vram_ptr#3 main::vram_ptr#2 ] ] with [ zp ZP_WORD:10 [ main::vram_ptr#1 ] ] - score: 2 +Allocated (was zp ZP_WORD:7) zp ZP_WORD:6 [ main::$2 ] + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Test binary ANDing pointers by Clay Cowgill + // Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" + // Global Constants & labels + .const SIZEOF_SIGNED_WORD = 2 + // @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 _2 = 6 + .label vram_ptr = 4 + .label pos_ptr = 2 + // [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + // [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + ldx #0 + // [5] phi (byte*) main::vram_ptr#3 = (byte*) 1064 [phi:main->main::@1#1] -- pbuz1=pbuc1 + lda #<$428 + sta.z vram_ptr + lda #>$428 + sta.z vram_ptr+1 + // [5] phi (signed word*) main::pos_ptr#2 = (signed word*) 1024 [phi:main->main::@1#2] -- pwsz1=pwsc1 + lda #<$400 + sta.z pos_ptr + lda #>$400 + sta.z pos_ptr+1 + jmp b1 + // [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + b1_from_b1: + // [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + // [5] phi (byte*) main::vram_ptr#3 = (byte*) main::vram_ptr#2 [phi:main::@1->main::@1#1] -- register_copy + // [5] phi (signed word*) main::pos_ptr#2 = (signed word*) main::pos_ptr#1 [phi:main::@1->main::@1#2] -- register_copy + jmp b1 + // main::@1 + b1: + // [6] *((signed word*) main::pos_ptr#2) ← (signed word) $55aa -- _deref_pwsz1=vwsc1 + ldy #0 + lda #<$55aa + sta (pos_ptr),y + iny + lda #>$55aa + sta (pos_ptr),y + // [7] (signed word~) main::$2 ← *((signed word*) main::pos_ptr#2) & (signed word) $aa55 -- vwsz1=_deref_pwsz2_band_vwsc1 + ldy #0 + lda (pos_ptr),y + and #<$aa55 + sta.z _2 + iny + lda (pos_ptr),y + and #>$aa55 + sta.z _2+1 + // [8] (byte~) main::$3 ← < (signed word~) main::$2 -- vbuaa=_lo_vwsz1 + lda.z _2 + // [9] *((byte*) main::vram_ptr#3) ← (byte~) main::$3 -- _deref_pbuz1=vbuaa + ldy #0 + sta (vram_ptr),y + // [10] (byte*) main::vram_ptr#1 ← ++ (byte*) main::vram_ptr#3 -- pbuz1=_inc_pbuz1 + inc.z vram_ptr + bne !+ + inc.z vram_ptr+1 + !: + // [11] (byte~) main::$4 ← > *((signed word*) main::pos_ptr#2) -- vbuaa=_hi__deref_pwsz1 + ldy #1 + lda (pos_ptr),y + // [12] *((byte*) main::vram_ptr#1) ← (byte~) main::$4 -- _deref_pbuz1=vbuaa + // stores 0x00 + ldy #0 + sta (vram_ptr),y + // [13] (byte*) main::vram_ptr#2 ← ++ (byte*) main::vram_ptr#1 -- pbuz1=_inc_pbuz1 + inc.z vram_ptr + bne !+ + inc.z vram_ptr+1 + !: + // [14] (signed word*) main::pos_ptr#1 ← (signed word*) main::pos_ptr#2 + (const byte) SIZEOF_SIGNED_WORD -- pwsz1=pwsz1_plus_vbuc1 + lda #SIZEOF_SIGNED_WORD + clc + adc.z pos_ptr + sta.z pos_ptr + bcc !+ + inc.z pos_ptr+1 + !: + // [15] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx + inx + // [16] if((byte) main::i#1!=(byte) 3) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 + cpx #3 + bne b1_from_b1 + jmp breturn + // main::@return + breturn: + // [17] return + rts +} + // File Data + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp b1 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Replacing label b1_from_b1 with b1 +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction main_from_b1: +Removing instruction bend_from_b1: +Removing instruction b1_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction b1_from_main: +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 +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(const byte) SIZEOF_SIGNED_WORD SIZEOF_SIGNED_WORD = (byte) 2 +(void()) main() +(signed word~) main::$2 $2 zp ZP_WORD:6 22.0 +(byte~) main::$3 reg byte a 22.0 +(byte~) main::$4 reg byte a 22.0 +(label) main::@1 +(label) main::@return +(byte) main::i +(byte) main::i#1 reg byte x 16.5 +(byte) main::i#2 reg byte x 2.2 +(signed word*) main::pos_ptr +(signed word*) main::pos_ptr#1 pos_ptr zp ZP_WORD:2 7.333333333333333 +(signed word*) main::pos_ptr#2 pos_ptr zp ZP_WORD:2 6.111111111111112 +(byte*) main::vram_ptr +(byte*) main::vram_ptr#1 vram_ptr zp ZP_WORD:4 11.0 +(byte*) main::vram_ptr#2 vram_ptr zp ZP_WORD:4 5.5 +(byte*) main::vram_ptr#3 vram_ptr zp ZP_WORD:4 6.6000000000000005 + +zp ZP_WORD:2 [ main::pos_ptr#2 main::pos_ptr#1 ] +zp ZP_WORD:4 [ main::vram_ptr#3 main::vram_ptr#2 main::vram_ptr#1 ] +reg byte x [ main::i#2 main::i#1 ] +zp ZP_WORD:6 [ main::$2 ] +reg byte a [ main::$3 ] +reg byte a [ main::$4 ] + + +FINAL ASSEMBLER +Score: 1431 + + // File Comments +// Test binary ANDing pointers by Clay Cowgill + // Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + // Global Constants & labels + .const SIZEOF_SIGNED_WORD = 2 + // @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 _2 = 6 + .label vram_ptr = 4 + .label pos_ptr = 2 + // [5] phi from main to main::@1 [phi:main->main::@1] + // [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + ldx #0 + // [5] phi (byte*) main::vram_ptr#3 = (byte*) 1064 [phi:main->main::@1#1] -- pbuz1=pbuc1 + lda #<$428 + sta.z vram_ptr + lda #>$428 + sta.z vram_ptr+1 + // [5] phi (signed word*) main::pos_ptr#2 = (signed word*) 1024 [phi:main->main::@1#2] -- pwsz1=pwsc1 + lda #<$400 + sta.z pos_ptr + lda #>$400 + sta.z pos_ptr+1 + // [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + // [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + // [5] phi (byte*) main::vram_ptr#3 = (byte*) main::vram_ptr#2 [phi:main::@1->main::@1#1] -- register_copy + // [5] phi (signed word*) main::pos_ptr#2 = (signed word*) main::pos_ptr#1 [phi:main::@1->main::@1#2] -- register_copy + // main::@1 + b1: + // *pos_ptr=(int)0x55AA + // [6] *((signed word*) main::pos_ptr#2) ← (signed word) $55aa -- _deref_pwsz1=vwsc1 + ldy #0 + lda #<$55aa + sta (pos_ptr),y + iny + lda #>$55aa + sta (pos_ptr),y + // *pos_ptr&(int)0xAA55 + // [7] (signed word~) main::$2 ← *((signed word*) main::pos_ptr#2) & (signed word) $aa55 -- vwsz1=_deref_pwsz2_band_vwsc1 + ldy #0 + lda (pos_ptr),y + and #<$aa55 + sta.z _2 + iny + lda (pos_ptr),y + and #>$aa55 + sta.z _2+1 + // <(*pos_ptr&(int)0xAA55) + // [8] (byte~) main::$3 ← < (signed word~) main::$2 -- vbuaa=_lo_vwsz1 + lda.z _2 + // *vram_ptr++=<(*pos_ptr&(int)0xAA55) + // [9] *((byte*) main::vram_ptr#3) ← (byte~) main::$3 -- _deref_pbuz1=vbuaa + ldy #0 + sta (vram_ptr),y + // *vram_ptr++=<(*pos_ptr&(int)0xAA55); + // [10] (byte*) main::vram_ptr#1 ← ++ (byte*) main::vram_ptr#3 -- pbuz1=_inc_pbuz1 + inc.z vram_ptr + bne !+ + inc.z vram_ptr+1 + !: + // >*pos_ptr + // [11] (byte~) main::$4 ← > *((signed word*) main::pos_ptr#2) -- vbuaa=_hi__deref_pwsz1 + ldy #1 + lda (pos_ptr),y + // *vram_ptr++=>*pos_ptr + // [12] *((byte*) main::vram_ptr#1) ← (byte~) main::$4 -- _deref_pbuz1=vbuaa + // stores 0x00 + ldy #0 + sta (vram_ptr),y + // *vram_ptr++=>*pos_ptr; + // [13] (byte*) main::vram_ptr#2 ← ++ (byte*) main::vram_ptr#1 -- pbuz1=_inc_pbuz1 + inc.z vram_ptr + bne !+ + inc.z vram_ptr+1 + !: + // pos_ptr++; + // [14] (signed word*) main::pos_ptr#1 ← (signed word*) main::pos_ptr#2 + (const byte) SIZEOF_SIGNED_WORD -- pwsz1=pwsz1_plus_vbuc1 + lda #SIZEOF_SIGNED_WORD + clc + adc.z pos_ptr + sta.z pos_ptr + bcc !+ + inc.z pos_ptr+1 + !: + // for( char i:0..2) + // [15] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx + inx + // [16] if((byte) main::i#1!=(byte) 3) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 + cpx #3 + bne b1 + // main::@return + // } + // [17] return + rts +} + // File Data + diff --git a/src/test/ref/pointer-anding.kc.sym b/src/test/ref/pointer-anding.kc.sym new file mode 100644 index 000000000..33b3d44d3 --- /dev/null +++ b/src/test/ref/pointer-anding.kc.sym @@ -0,0 +1,27 @@ +(label) @1 +(label) @begin +(label) @end +(const byte) SIZEOF_SIGNED_WORD SIZEOF_SIGNED_WORD = (byte) 2 +(void()) main() +(signed word~) main::$2 $2 zp ZP_WORD:6 22.0 +(byte~) main::$3 reg byte a 22.0 +(byte~) main::$4 reg byte a 22.0 +(label) main::@1 +(label) main::@return +(byte) main::i +(byte) main::i#1 reg byte x 16.5 +(byte) main::i#2 reg byte x 2.2 +(signed word*) main::pos_ptr +(signed word*) main::pos_ptr#1 pos_ptr zp ZP_WORD:2 7.333333333333333 +(signed word*) main::pos_ptr#2 pos_ptr zp ZP_WORD:2 6.111111111111112 +(byte*) main::vram_ptr +(byte*) main::vram_ptr#1 vram_ptr zp ZP_WORD:4 11.0 +(byte*) main::vram_ptr#2 vram_ptr zp ZP_WORD:4 5.5 +(byte*) main::vram_ptr#3 vram_ptr zp ZP_WORD:4 6.6000000000000005 + +zp ZP_WORD:2 [ main::pos_ptr#2 main::pos_ptr#1 ] +zp ZP_WORD:4 [ main::vram_ptr#3 main::vram_ptr#2 main::vram_ptr#1 ] +reg byte x [ main::i#2 main::i#1 ] +zp ZP_WORD:6 [ main::$2 ] +reg byte a [ main::$3 ] +reg byte a [ main::$4 ]