diff --git a/src/main/fragment/mos6502-common/_deref_(_deref_pptc1)=vbuaa.asm b/src/main/fragment/mos6502-common/_deref_(_deref_pptc1)=vbuaa.asm index a674d8937..2fef519b3 100644 --- a/src/main/fragment/mos6502-common/_deref_(_deref_pptc1)=vbuaa.asm +++ b/src/main/fragment/mos6502-common/_deref_(_deref_pptc1)=vbuaa.asm @@ -1,2 +1,6 @@ +ldy {c1} +sty $fe +ldy {c1}+1 +sty $ff ldy #0 -sta ({c1}),y +sta ($fe),y \ No newline at end of file diff --git a/src/main/fragment/mos6502-common/vbuaa=_deref_(_deref_pptc1).asm b/src/main/fragment/mos6502-common/vbuaa=_deref_(_deref_pptc1).asm index b2b71be97..f030e022a 100644 --- a/src/main/fragment/mos6502-common/vbuaa=_deref_(_deref_pptc1).asm +++ b/src/main/fragment/mos6502-common/vbuaa=_deref_(_deref_pptc1).asm @@ -1,2 +1,6 @@ +ldy {c1} +sty $fe +ldy {c1}+1 +sty $ff ldy #0 -lda ({c1}),y +lda ($fe),y diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 7217e9b3e..fbc5fd826 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -649,6 +649,12 @@ public class TestPrograms { } */ + + @Test + public void testStructPtr32() throws IOException, URISyntaxException { + compileAndCompare("struct-ptr-32", log()); + } + //@Test //public void testStructPtr31() throws IOException, URISyntaxException { // compileAndCompare("struct-ptr-31"); diff --git a/src/test/kc/struct-ptr-32.kc b/src/test/kc/struct-ptr-32.kc new file mode 100644 index 000000000..465f263d4 --- /dev/null +++ b/src/test/kc/struct-ptr-32.kc @@ -0,0 +1,23 @@ +// Example of a struct containing an array +// Fails (by displaying "BB" ) because the memory layout is wrong - and the name is treated like a pointer (to 0x0000) instead of a value. +// https://gitlab.com/camelot/kickc/issues/312 + +struct Person { + char id; + char[16] name; +}; + +struct Person[2] persons; + +void main() { + persons[0].name[0] = 'a'; + persons[1].name[0] = 'b'; + const char* SCREEN = 0x0400; + struct Person* person = persons; + SCREEN[0] = person->name[0]; + person++; + SCREEN[1] = person->name[0]; +} + + + diff --git a/src/test/ref/hex2dec-ptrptr.asm b/src/test/ref/hex2dec-ptrptr.asm index 25e2954df..2ecaa4139 100644 --- a/src/test/ref/hex2dec-ptrptr.asm +++ b/src/test/ref/hex2dec-ptrptr.asm @@ -91,8 +91,12 @@ utoa16n: { beq breturn tay lda DIGITS,y + ldy.z utoa16w.dst + sty.z $fe + ldy.z utoa16w.dst+1 + sty.z $ff ldy #0 - sta (utoa16w.dst),y + sta ($fe),y inc.z utoa16w.dst bne !+ inc.z utoa16w.dst+1 diff --git a/src/test/ref/hex2dec-ptrptr.log b/src/test/ref/hex2dec-ptrptr.log index bd575935e..3b87e0c97 100644 --- a/src/test/ref/hex2dec-ptrptr.log +++ b/src/test/ref/hex2dec-ptrptr.log @@ -1049,8 +1049,12 @@ utoa16n: { // [43] *(*(&(byte*) utoa16w::dst#5)) ← *((const byte[]) DIGITS#0 + (byte) utoa16n::nybble#4) -- _deref_(_deref_pptc1)=pbuc2_derefidx_vbuz1 ldy.z nybble lda DIGITS,y + ldy.z utoa16w.dst + sty.z $fe + ldy.z utoa16w.dst+1 + sty.z $ff ldy #0 - sta (utoa16w.dst),y + sta ($fe),y // [44] *(&(byte*) utoa16w::dst#5) ← ++ *(&(byte*) utoa16w::dst#5) -- _deref_pptc1=_inc__deref_pptc1 inc.z utoa16w.dst bne !+ @@ -1163,17 +1167,17 @@ Uplift Scope [cls] 33: zp ZP_WORD:8 [ cls::sc#2 cls::sc#1 ] Uplift Scope [main] Uplift Scope [] -Uplifting [utoa16w] best 955 combination zp ZP_WORD:4 [ utoa16w::dst#5 utoa16w::dst#0 utoa16w::dst#1 utoa16w::dst#2 utoa16w::dst#3 utoa16w::dst#4 ] reg byte a [ utoa16w::$0 ] reg byte a [ utoa16w::$4 ] reg byte a [ utoa16w::$8 ] reg byte a [ utoa16w::$12 ] zp ZP_BYTE:12 [ utoa16w::started#1 ] zp ZP_BYTE:15 [ utoa16w::started#2 ] zp ZP_WORD:2 [ utoa16w::value#5 ] +Uplifting [utoa16w] best 967 combination zp ZP_WORD:4 [ utoa16w::dst#5 utoa16w::dst#0 utoa16w::dst#1 utoa16w::dst#2 utoa16w::dst#3 utoa16w::dst#4 ] reg byte a [ utoa16w::$0 ] reg byte a [ utoa16w::$4 ] reg byte a [ utoa16w::$8 ] reg byte a [ utoa16w::$12 ] zp ZP_BYTE:12 [ utoa16w::started#1 ] zp ZP_BYTE:15 [ utoa16w::started#2 ] zp ZP_WORD:2 [ utoa16w::value#5 ] Limited combination testing to 100 combinations of 2304 possible. -Uplifting [utoa16n] best 903 combination reg byte a [ utoa16n::nybble#4 utoa16n::nybble#0 utoa16n::nybble#1 utoa16n::nybble#2 utoa16n::nybble#3 ] reg byte x [ utoa16n::return#4 utoa16n::started#7 utoa16n::started#1 utoa16n::started#2 ] reg byte x [ utoa16n::return#0 ] reg byte x [ utoa16n::return#1 ] +Uplifting [utoa16n] best 915 combination reg byte a [ utoa16n::nybble#4 utoa16n::nybble#0 utoa16n::nybble#1 utoa16n::nybble#2 utoa16n::nybble#3 ] reg byte x [ utoa16n::return#4 utoa16n::started#7 utoa16n::started#1 utoa16n::started#2 ] reg byte x [ utoa16n::return#0 ] reg byte x [ utoa16n::return#1 ] Limited combination testing to 100 combinations of 128 possible. -Uplifting [cls] best 903 combination zp ZP_WORD:8 [ cls::sc#2 cls::sc#1 ] -Uplifting [main] best 903 combination -Uplifting [] best 903 combination +Uplifting [cls] best 915 combination zp ZP_WORD:8 [ cls::sc#2 cls::sc#1 ] +Uplifting [main] best 915 combination +Uplifting [] best 915 combination Attempting to uplift remaining variables inzp ZP_BYTE:12 [ utoa16w::started#1 ] -Uplifting [utoa16w] best 897 combination reg byte x [ utoa16w::started#1 ] +Uplifting [utoa16w] best 909 combination reg byte x [ utoa16w::started#1 ] Attempting to uplift remaining variables inzp ZP_BYTE:15 [ utoa16w::started#2 ] -Uplifting [utoa16w] best 891 combination reg byte x [ utoa16w::started#2 ] +Uplifting [utoa16w] best 903 combination reg byte x [ utoa16w::started#2 ] Coalescing zero page register [ zp ZP_WORD:8 [ cls::sc#2 cls::sc#1 ] ] with [ zp ZP_WORD:2 [ utoa16w::value#5 ] ] Allocated (was zp ZP_WORD:4) zp ZP_WORD:2 [ utoa16w::dst#5 utoa16w::dst#0 utoa16w::dst#1 utoa16w::dst#2 utoa16w::dst#3 utoa16w::dst#4 ] Allocated (was zp ZP_WORD:8) zp ZP_WORD:4 [ cls::sc#2 cls::sc#1 utoa16w::value#5 ] @@ -1418,8 +1422,12 @@ utoa16n: { // [43] *(*(&(byte*) utoa16w::dst#5)) ← *((const byte[]) DIGITS#0 + (byte) utoa16n::nybble#4) -- _deref_(_deref_pptc1)=pbuc2_derefidx_vbuaa tay lda DIGITS,y + ldy.z utoa16w.dst + sty.z $fe + ldy.z utoa16w.dst+1 + sty.z $ff ldy #0 - sta (utoa16w.dst),y + sta ($fe),y // [44] *(&(byte*) utoa16w::dst#5) ← ++ *(&(byte*) utoa16w::dst#5) -- _deref_pptc1=_inc__deref_pptc1 inc.z utoa16w.dst bne !+ @@ -1628,7 +1636,7 @@ reg byte a [ utoa16w::$12 ] FINAL ASSEMBLER -Score: 739 +Score: 751 // File Comments // Testing binary to hex conversion using pointer to pointer @@ -1842,8 +1850,12 @@ utoa16n: { // [43] *(*(&(byte*) utoa16w::dst#5)) ← *((const byte[]) DIGITS#0 + (byte) utoa16n::nybble#4) -- _deref_(_deref_pptc1)=pbuc2_derefidx_vbuaa tay lda DIGITS,y + ldy.z utoa16w.dst + sty.z $fe + ldy.z utoa16w.dst+1 + sty.z $ff ldy #0 - sta (utoa16w.dst),y + sta ($fe),y // *(*dst)++ = DIGITS[nybble]; // [44] *(&(byte*) utoa16w::dst#5) ← ++ *(&(byte*) utoa16w::dst#5) -- _deref_pptc1=_inc__deref_pptc1 inc.z utoa16w.dst diff --git a/src/test/ref/hex2dec.asm b/src/test/ref/hex2dec.asm index 6d7e711c8..85b8eb1d9 100644 --- a/src/test/ref/hex2dec.asm +++ b/src/test/ref/hex2dec.asm @@ -217,8 +217,12 @@ utoa16n: { beq breturn tay lda DIGITS,y + ldy.z utoa16w.dst + sty.z $fe + ldy.z utoa16w.dst+1 + sty.z $ff ldy #0 - sta (utoa16w.dst),y + sta ($fe),y inc.z utoa16w.dst bne !+ inc.z utoa16w.dst+1 diff --git a/src/test/ref/hex2dec.log b/src/test/ref/hex2dec.log index 7971e70b6..10f6f0f21 100644 --- a/src/test/ref/hex2dec.log +++ b/src/test/ref/hex2dec.log @@ -1992,8 +1992,12 @@ utoa16n: { // [82] *(*(&(byte*) utoa16w::dst#5)) ← *((const byte[]) DIGITS#0 + (byte) utoa16n::nybble#4) -- _deref_(_deref_pptc1)=pbuc2_derefidx_vbuz1 ldy.z nybble lda DIGITS,y + ldy.z utoa16w.dst + sty.z $fe + ldy.z utoa16w.dst+1 + sty.z $ff ldy #0 - sta (utoa16w.dst),y + sta ($fe),y // [83] *(&(byte*) utoa16w::dst#5) ← ++ *(&(byte*) utoa16w::dst#5) -- _deref_pptc1=_inc__deref_pptc1 inc.z utoa16w.dst bne !+ @@ -2176,36 +2180,36 @@ Uplift Scope [utoa16n] 14.4: zp ZP_BYTE:14 [ utoa16n::nybble#4 utoa16n::nybble#0 Uplift Scope [cls] 33: zp ZP_WORD:16 [ cls::sc#2 cls::sc#1 ] Uplift Scope [] -Uplifting [utoa10w] best 28959 combination zp ZP_WORD:8 [ utoa10w::dst#7 utoa10w::dst#11 utoa10w::dst#4 utoa10w::dst#1 ] zp ZP_WORD:4 [ utoa10w::value#10 utoa10w::value#0 utoa10w::value#1 ] zp ZP_BYTE:6 [ utoa10w::digit#3 utoa10w::digit#7 utoa10w::digit#1 ] reg byte x [ utoa10w::i#2 utoa10w::i#1 ] reg byte a [ utoa10w::$8 ] reg byte a [ utoa10w::$2 ] zp ZP_BYTE:29 [ utoa10w::$9 ] zp ZP_BYTE:7 [ utoa10w::bStarted#2 ] zp ZP_BYTE:26 [ utoa10w::$0 ] zp ZP_WORD:27 [ utoa10w::dst#2 ] +Uplifting [utoa10w] best 28971 combination zp ZP_WORD:8 [ utoa10w::dst#7 utoa10w::dst#11 utoa10w::dst#4 utoa10w::dst#1 ] zp ZP_WORD:4 [ utoa10w::value#10 utoa10w::value#0 utoa10w::value#1 ] zp ZP_BYTE:6 [ utoa10w::digit#3 utoa10w::digit#7 utoa10w::digit#1 ] reg byte x [ utoa10w::i#2 utoa10w::i#1 ] reg byte a [ utoa10w::$8 ] reg byte a [ utoa10w::$2 ] zp ZP_BYTE:29 [ utoa10w::$9 ] zp ZP_BYTE:7 [ utoa10w::bStarted#2 ] zp ZP_BYTE:26 [ utoa10w::$0 ] zp ZP_WORD:27 [ utoa10w::dst#2 ] Limited combination testing to 100 combinations of 3072 possible. -Uplifting [main] best 26559 combination reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::$2 ] reg byte a [ main::rst#0 ] zp ZP_BYTE:18 [ main::$1 ] zp ZP_BYTE:22 [ main::time_end#0 ] zp ZP_BYTE:23 [ main::time#0 ] zp ZP_BYTE:21 [ main::time_start#0 ] +Uplifting [main] best 26571 combination reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::$2 ] reg byte a [ main::rst#0 ] zp ZP_BYTE:18 [ main::$1 ] zp ZP_BYTE:22 [ main::time_end#0 ] zp ZP_BYTE:23 [ main::time#0 ] zp ZP_BYTE:21 [ main::time_start#0 ] Limited combination testing to 100 combinations of 3456 possible. -Uplifting [utoa16w] best 26535 combination zp ZP_WORD:12 [ utoa16w::dst#5 utoa16w::dst#1 utoa16w::dst#2 utoa16w::dst#3 utoa16w::dst#4 utoa16w::dst#0 ] reg byte a [ utoa16w::$0 ] reg byte a [ utoa16w::$4 ] reg byte a [ utoa16w::$8 ] reg byte a [ utoa16w::$12 ] zp ZP_BYTE:32 [ utoa16w::started#1 ] zp ZP_BYTE:35 [ utoa16w::started#2 ] zp ZP_WORD:10 [ utoa16w::value#5 ] +Uplifting [utoa16w] best 26547 combination zp ZP_WORD:12 [ utoa16w::dst#5 utoa16w::dst#1 utoa16w::dst#2 utoa16w::dst#3 utoa16w::dst#4 utoa16w::dst#0 ] reg byte a [ utoa16w::$0 ] reg byte a [ utoa16w::$4 ] reg byte a [ utoa16w::$8 ] reg byte a [ utoa16w::$12 ] zp ZP_BYTE:32 [ utoa16w::started#1 ] zp ZP_BYTE:35 [ utoa16w::started#2 ] zp ZP_WORD:10 [ utoa16w::value#5 ] Limited combination testing to 100 combinations of 2304 possible. -Uplifting [utoa16n] best 26483 combination reg byte a [ utoa16n::nybble#4 utoa16n::nybble#0 utoa16n::nybble#1 utoa16n::nybble#2 utoa16n::nybble#3 ] reg byte x [ utoa16n::return#4 utoa16n::started#7 utoa16n::started#1 utoa16n::started#2 ] reg byte x [ utoa16n::return#0 ] reg byte x [ utoa16n::return#1 ] +Uplifting [utoa16n] best 26495 combination reg byte a [ utoa16n::nybble#4 utoa16n::nybble#0 utoa16n::nybble#1 utoa16n::nybble#2 utoa16n::nybble#3 ] reg byte x [ utoa16n::return#4 utoa16n::started#7 utoa16n::started#1 utoa16n::started#2 ] reg byte x [ utoa16n::return#0 ] reg byte x [ utoa16n::return#1 ] Limited combination testing to 100 combinations of 128 possible. -Uplifting [cls] best 26483 combination zp ZP_WORD:16 [ cls::sc#2 cls::sc#1 ] -Uplifting [] best 26483 combination +Uplifting [cls] best 26495 combination zp ZP_WORD:16 [ cls::sc#2 cls::sc#1 ] +Uplifting [] best 26495 combination Attempting to uplift remaining variables inzp ZP_BYTE:6 [ utoa10w::digit#3 utoa10w::digit#7 utoa10w::digit#1 ] -Uplifting [utoa10w] best 26483 combination zp ZP_BYTE:6 [ utoa10w::digit#3 utoa10w::digit#7 utoa10w::digit#1 ] +Uplifting [utoa10w] best 26495 combination zp ZP_BYTE:6 [ utoa10w::digit#3 utoa10w::digit#7 utoa10w::digit#1 ] Attempting to uplift remaining variables inzp ZP_BYTE:29 [ utoa10w::$9 ] -Uplifting [utoa10w] best 26083 combination reg byte a [ utoa10w::$9 ] +Uplifting [utoa10w] best 26095 combination reg byte a [ utoa10w::$9 ] Attempting to uplift remaining variables inzp ZP_BYTE:18 [ main::$1 ] -Uplifting [main] best 26083 combination zp ZP_BYTE:18 [ main::$1 ] +Uplifting [main] best 26095 combination zp ZP_BYTE:18 [ main::$1 ] Attempting to uplift remaining variables inzp ZP_BYTE:7 [ utoa10w::bStarted#2 ] -Uplifting [utoa10w] best 26083 combination zp ZP_BYTE:7 [ utoa10w::bStarted#2 ] +Uplifting [utoa10w] best 26095 combination zp ZP_BYTE:7 [ utoa10w::bStarted#2 ] Attempting to uplift remaining variables inzp ZP_BYTE:22 [ main::time_end#0 ] -Uplifting [main] best 26043 combination reg byte x [ main::time_end#0 ] +Uplifting [main] best 26055 combination reg byte x [ main::time_end#0 ] Attempting to uplift remaining variables inzp ZP_BYTE:23 [ main::time#0 ] -Uplifting [main] best 25983 combination reg byte a [ main::time#0 ] +Uplifting [main] best 25995 combination reg byte a [ main::time#0 ] Attempting to uplift remaining variables inzp ZP_BYTE:26 [ utoa10w::$0 ] -Uplifting [utoa10w] best 25979 combination reg byte a [ utoa10w::$0 ] +Uplifting [utoa10w] best 25991 combination reg byte a [ utoa10w::$0 ] Attempting to uplift remaining variables inzp ZP_BYTE:32 [ utoa16w::started#1 ] -Uplifting [utoa16w] best 25973 combination reg byte x [ utoa16w::started#1 ] +Uplifting [utoa16w] best 25985 combination reg byte x [ utoa16w::started#1 ] Attempting to uplift remaining variables inzp ZP_BYTE:35 [ utoa16w::started#2 ] -Uplifting [utoa16w] best 25967 combination reg byte x [ utoa16w::started#2 ] +Uplifting [utoa16w] best 25979 combination reg byte x [ utoa16w::started#2 ] Attempting to uplift remaining variables inzp ZP_BYTE:21 [ main::time_start#0 ] -Uplifting [main] best 25967 combination zp ZP_BYTE:21 [ main::time_start#0 ] +Uplifting [main] best 25979 combination zp ZP_BYTE:21 [ main::time_start#0 ] Coalescing zero page register [ zp ZP_WORD:8 [ utoa10w::dst#7 utoa10w::dst#11 utoa10w::dst#4 utoa10w::dst#1 ] ] with [ zp ZP_WORD:27 [ utoa10w::dst#2 ] ] - score: 1 Coalescing zero page register [ zp ZP_WORD:10 [ utoa16w::value#5 ] ] with [ zp ZP_WORD:4 [ utoa10w::value#10 utoa10w::value#0 utoa10w::value#1 ] ] Coalescing zero page register [ zp ZP_WORD:16 [ cls::sc#2 cls::sc#1 ] ] with [ zp ZP_WORD:8 [ utoa10w::dst#7 utoa10w::dst#11 utoa10w::dst#4 utoa10w::dst#1 utoa10w::dst#2 ] ] @@ -2688,8 +2692,12 @@ utoa16n: { // [82] *(*(&(byte*) utoa16w::dst#5)) ← *((const byte[]) DIGITS#0 + (byte) utoa16n::nybble#4) -- _deref_(_deref_pptc1)=pbuc2_derefidx_vbuaa tay lda DIGITS,y + ldy.z utoa16w.dst + sty.z $fe + ldy.z utoa16w.dst+1 + sty.z $ff ldy #0 - sta (utoa16w.dst),y + sta ($fe),y // [83] *(&(byte*) utoa16w::dst#5) ← ++ *(&(byte*) utoa16w::dst#5) -- _deref_pptc1=_inc__deref_pptc1 inc.z utoa16w.dst bne !+ @@ -3008,7 +3016,7 @@ reg byte a [ utoa16w::$12 ] FINAL ASSEMBLER -Score: 22306 +Score: 22318 // File Comments // Testing hex to decimal conversion @@ -3458,8 +3466,12 @@ utoa16n: { // [82] *(*(&(byte*) utoa16w::dst#5)) ← *((const byte[]) DIGITS#0 + (byte) utoa16n::nybble#4) -- _deref_(_deref_pptc1)=pbuc2_derefidx_vbuaa tay lda DIGITS,y + ldy.z utoa16w.dst + sty.z $fe + ldy.z utoa16w.dst+1 + sty.z $ff ldy #0 - sta (utoa16w.dst),y + sta ($fe),y // *(*dst)++ = DIGITS[nybble]; // [83] *(&(byte*) utoa16w::dst#5) ← ++ *(&(byte*) utoa16w::dst#5) -- _deref_pptc1=_inc__deref_pptc1 inc.z utoa16w.dst diff --git a/src/test/ref/pointer-pointer-1.asm b/src/test/ref/pointer-pointer-1.asm index 9f5602b7b..44908f2e2 100644 --- a/src/test/ref/pointer-pointer-1.asm +++ b/src/test/ref/pointer-pointer-1.asm @@ -13,8 +13,12 @@ main: { sta.z pb lda #>b sta.z pb+1 + ldy.z ppb + sty.z $fe + ldy.z ppb+1 + sty.z $ff ldy #0 - lda (ppb),y + lda ($fe),y sta SCREEN rts } diff --git a/src/test/ref/pointer-pointer-1.log b/src/test/ref/pointer-pointer-1.log index c64c26ed6..a991f32c4 100644 --- a/src/test/ref/pointer-pointer-1.log +++ b/src/test/ref/pointer-pointer-1.log @@ -146,8 +146,12 @@ main: { lda #>b sta.z pb+1 // [6] *((const byte*) main::SCREEN#0) ← *(*((const byte**) main::ppb#0)) -- _deref_pbuc1=_deref_(_deref_pptc2) + ldy.z ppb + sty.z $fe + ldy.z ppb+1 + sty.z $ff ldy #0 - lda (ppb),y + lda ($fe),y sta SCREEN jmp breturn // main::@return @@ -168,10 +172,10 @@ REGISTER UPLIFT SCOPES Uplift Scope [main] 20: zp ZP_WORD:3 [ main::pb#0 ] 2: zp ZP_BYTE:2 [ main::b#0 ] Uplift Scope [] -Uplifting [main] best 47 combination zp ZP_WORD:3 [ main::pb#0 ] zp ZP_BYTE:2 [ main::b#0 ] -Uplifting [] best 47 combination +Uplifting [main] best 59 combination zp ZP_WORD:3 [ main::pb#0 ] zp ZP_BYTE:2 [ main::b#0 ] +Uplifting [] best 59 combination Attempting to uplift remaining variables inzp ZP_BYTE:2 [ main::b#0 ] -Uplifting [main] best 47 combination zp ZP_BYTE:2 [ main::b#0 ] +Uplifting [main] best 59 combination zp ZP_BYTE:2 [ main::b#0 ] ASSEMBLER BEFORE OPTIMIZATION // File Comments @@ -210,8 +214,12 @@ main: { lda #>b sta.z pb+1 // [6] *((const byte*) main::SCREEN#0) ← *(*((const byte**) main::ppb#0)) -- _deref_pbuc1=_deref_(_deref_pptc2) + ldy.z ppb + sty.z $fe + ldy.z ppb+1 + sty.z $ff ldy #0 - lda (ppb),y + lda ($fe),y sta SCREEN jmp breturn // main::@return @@ -259,7 +267,7 @@ zp ZP_WORD:3 [ main::pb#0 ] FINAL ASSEMBLER -Score: 32 +Score: 44 // File Comments // Tests a simple pointer to a pointer @@ -292,8 +300,12 @@ main: { sta.z pb+1 // *SCREEN = **ppb // [6] *((const byte*) main::SCREEN#0) ← *(*((const byte**) main::ppb#0)) -- _deref_pbuc1=_deref_(_deref_pptc2) + ldy.z ppb + sty.z $fe + ldy.z ppb+1 + sty.z $ff ldy #0 - lda (ppb),y + lda ($fe),y sta SCREEN // main::@return // } diff --git a/src/test/ref/ptrptr-optimize-0.asm b/src/test/ref/ptrptr-optimize-0.asm index a59ec0f45..e5f97d3c8 100644 --- a/src/test/ref/ptrptr-optimize-0.asm +++ b/src/test/ref/ptrptr-optimize-0.asm @@ -10,14 +10,22 @@ main: { lda #>$400 sta.z screen+1 lda #'a' + ldy.z pscreen + sty.z $fe + ldy.z pscreen+1 + sty.z $ff ldy #0 - sta (pscreen),y + sta ($fe),y inc.z pscreen bne !+ inc.z pscreen+1 !: lda #'b' + ldy.z pscreen + sty.z $fe + ldy.z pscreen+1 + sty.z $ff ldy #0 - sta (pscreen),y + sta ($fe),y rts } diff --git a/src/test/ref/ptrptr-optimize-0.log b/src/test/ref/ptrptr-optimize-0.log index 6b1af61b2..b73c95ec3 100644 --- a/src/test/ref/ptrptr-optimize-0.log +++ b/src/test/ref/ptrptr-optimize-0.log @@ -124,8 +124,12 @@ main: { sta.z screen+1 // [5] *(*((const byte**) main::pscreen#0)) ← (byte) 'a' -- _deref_(_deref_pptc1)=vbuc2 lda #'a' + ldy.z pscreen + sty.z $fe + ldy.z pscreen+1 + sty.z $ff ldy #0 - sta (pscreen),y + sta ($fe),y // [6] *((const byte**) main::pscreen#0) ← ++ *((const byte**) main::pscreen#0) -- _deref_pptc1=_inc__deref_pptc1 inc.z pscreen bne !+ @@ -133,8 +137,12 @@ main: { !: // [7] *(*((const byte**) main::pscreen#0)) ← (byte) 'b' -- _deref_(_deref_pptc1)=vbuc2 lda #'b' + ldy.z pscreen + sty.z $fe + ldy.z pscreen+1 + sty.z $ff ldy #0 - sta (pscreen),y + sta ($fe),y jmp breturn // main::@return breturn: @@ -153,8 +161,8 @@ REGISTER UPLIFT SCOPES Uplift Scope [main] 20: zp ZP_WORD:2 [ main::screen#0 ] Uplift Scope [] -Uplifting [main] best 63 combination zp ZP_WORD:2 [ main::screen#0 ] -Uplifting [] best 63 combination +Uplifting [main] best 87 combination zp ZP_WORD:2 [ main::screen#0 ] +Uplifting [] best 87 combination ASSEMBLER BEFORE OPTIMIZATION // File Comments @@ -189,8 +197,12 @@ main: { sta.z screen+1 // [5] *(*((const byte**) main::pscreen#0)) ← (byte) 'a' -- _deref_(_deref_pptc1)=vbuc2 lda #'a' + ldy.z pscreen + sty.z $fe + ldy.z pscreen+1 + sty.z $ff ldy #0 - sta (pscreen),y + sta ($fe),y // [6] *((const byte**) main::pscreen#0) ← ++ *((const byte**) main::pscreen#0) -- _deref_pptc1=_inc__deref_pptc1 inc.z pscreen bne !+ @@ -198,8 +210,12 @@ main: { !: // [7] *(*((const byte**) main::pscreen#0)) ← (byte) 'b' -- _deref_(_deref_pptc1)=vbuc2 lda #'b' + ldy.z pscreen + sty.z $fe + ldy.z pscreen+1 + sty.z $ff ldy #0 - sta (pscreen),y + sta ($fe),y jmp breturn // main::@return breturn: @@ -241,7 +257,7 @@ zp ZP_WORD:2 [ main::screen#0 ] FINAL ASSEMBLER -Score: 48 +Score: 72 // File Comments // Tests optimization of constant pointers to pointers @@ -269,8 +285,12 @@ main: { // **pscreen = 'a' // [5] *(*((const byte**) main::pscreen#0)) ← (byte) 'a' -- _deref_(_deref_pptc1)=vbuc2 lda #'a' + ldy.z pscreen + sty.z $fe + ldy.z pscreen+1 + sty.z $ff ldy #0 - sta (pscreen),y + sta ($fe),y // (*pscreen)++; // [6] *((const byte**) main::pscreen#0) ← ++ *((const byte**) main::pscreen#0) -- _deref_pptc1=_inc__deref_pptc1 inc.z pscreen @@ -280,8 +300,12 @@ main: { // **pscreen = 'b' // [7] *(*((const byte**) main::pscreen#0)) ← (byte) 'b' -- _deref_(_deref_pptc1)=vbuc2 lda #'b' + ldy.z pscreen + sty.z $fe + ldy.z pscreen+1 + sty.z $ff ldy #0 - sta (pscreen),y + sta ($fe),y // main::@return // } // [8] return diff --git a/src/test/ref/ptrptr-optimize-1.asm b/src/test/ref/ptrptr-optimize-1.asm index 29bd41b36..7fb23630c 100644 --- a/src/test/ref/ptrptr-optimize-1.asm +++ b/src/test/ref/ptrptr-optimize-1.asm @@ -17,8 +17,12 @@ main: { } // sub(byte register(A) ch) sub: { + ldy.z main.pscreen + sty.z $fe + ldy.z main.pscreen+1 + sty.z $ff ldy #0 - sta (main.pscreen),y + sta ($fe),y inc.z main.pscreen bne !+ inc.z main.pscreen+1 diff --git a/src/test/ref/ptrptr-optimize-1.log b/src/test/ref/ptrptr-optimize-1.log index fdeed4982..b637e4801 100644 --- a/src/test/ref/ptrptr-optimize-1.log +++ b/src/test/ref/ptrptr-optimize-1.log @@ -223,8 +223,12 @@ sub: { .label ch = 2 // [10] *(*((const byte**) main::pscreen#0)) ← (byte) sub::ch#2 -- _deref_(_deref_pptc1)=vbuz1 lda.z ch + ldy.z main.pscreen + sty.z $fe + ldy.z main.pscreen+1 + sty.z $ff ldy #0 - sta (main.pscreen),y + sta ($fe),y // [11] *((const byte**) main::pscreen#0) ← ++ *((const byte**) main::pscreen#0) -- _deref_pptc1=_inc__deref_pptc1 inc.z main.pscreen bne !+ @@ -249,9 +253,9 @@ Uplift Scope [main] 20: zp ZP_WORD:3 [ main::screen#0 ] Uplift Scope [sub] 2: zp ZP_BYTE:2 [ sub::ch#2 ] Uplift Scope [] -Uplifting [main] best 88 combination zp ZP_WORD:3 [ main::screen#0 ] -Uplifting [sub] best 79 combination reg byte a [ sub::ch#2 ] -Uplifting [] best 79 combination +Uplifting [main] best 100 combination zp ZP_WORD:3 [ main::screen#0 ] +Uplifting [sub] best 91 combination reg byte a [ sub::ch#2 ] +Uplifting [] best 91 combination Allocated (was zp ZP_WORD:3) zp ZP_WORD:2 [ main::screen#0 ] ASSEMBLER BEFORE OPTIMIZATION @@ -312,8 +316,12 @@ main: { // sub(byte register(A) ch) sub: { // [10] *(*((const byte**) main::pscreen#0)) ← (byte) sub::ch#2 -- _deref_(_deref_pptc1)=vbuaa + ldy.z main.pscreen + sty.z $fe + ldy.z main.pscreen+1 + sty.z $ff ldy #0 - sta (main.pscreen),y + sta ($fe),y // [11] *((const byte**) main::pscreen#0) ← ++ *((const byte**) main::pscreen#0) -- _deref_pptc1=_inc__deref_pptc1 inc.z main.pscreen bne !+ @@ -374,7 +382,7 @@ zp ZP_WORD:2 [ main::screen#0 ] FINAL ASSEMBLER -Score: 58 +Score: 70 // File Comments // Tests optimization of constant pointers to pointers @@ -423,8 +431,12 @@ main: { sub: { // *(*dst)++ = ch // [10] *(*((const byte**) main::pscreen#0)) ← (byte) sub::ch#2 -- _deref_(_deref_pptc1)=vbuaa + ldy.z main.pscreen + sty.z $fe + ldy.z main.pscreen+1 + sty.z $ff ldy #0 - sta (main.pscreen),y + sta ($fe),y // *(*dst)++ = ch; // [11] *((const byte**) main::pscreen#0) ← ++ *((const byte**) main::pscreen#0) -- _deref_pptc1=_inc__deref_pptc1 inc.z main.pscreen diff --git a/src/test/ref/ptrptr-optimize-2.asm b/src/test/ref/ptrptr-optimize-2.asm index 900b06065..6219f5801 100644 --- a/src/test/ref/ptrptr-optimize-2.asm +++ b/src/test/ref/ptrptr-optimize-2.asm @@ -17,8 +17,12 @@ main: { } // sub(byte register(A) ch) sub: { + ldy.z main.screen + sty.z $fe + ldy.z main.screen+1 + sty.z $ff ldy #0 - sta (main.screen),y + sta ($fe),y inc.z main.screen bne !+ inc.z main.screen+1 diff --git a/src/test/ref/ptrptr-optimize-2.log b/src/test/ref/ptrptr-optimize-2.log index 2124ae77e..06547ede3 100644 --- a/src/test/ref/ptrptr-optimize-2.log +++ b/src/test/ref/ptrptr-optimize-2.log @@ -223,8 +223,12 @@ sub: { .label ch = 2 // [10] *(*(&(byte*) main::screen#0)) ← (byte) sub::ch#2 -- _deref_(_deref_pptc1)=vbuz1 lda.z ch + ldy.z main.screen + sty.z $fe + ldy.z main.screen+1 + sty.z $ff ldy #0 - sta (main.screen),y + sta ($fe),y // [11] *(&(byte*) main::screen#0) ← ++ *(&(byte*) main::screen#0) -- _deref_pptc1=_inc__deref_pptc1 inc.z main.screen bne !+ @@ -249,9 +253,9 @@ Uplift Scope [sub] 2: zp ZP_BYTE:2 [ sub::ch#2 ] Uplift Scope [main] 0.29: zp ZP_WORD:3 [ main::screen#0 ] Uplift Scope [] -Uplifting [sub] best 79 combination reg byte a [ sub::ch#2 ] -Uplifting [main] best 79 combination zp ZP_WORD:3 [ main::screen#0 ] -Uplifting [] best 79 combination +Uplifting [sub] best 91 combination reg byte a [ sub::ch#2 ] +Uplifting [main] best 91 combination zp ZP_WORD:3 [ main::screen#0 ] +Uplifting [] best 91 combination Allocated (was zp ZP_WORD:3) zp ZP_WORD:2 [ main::screen#0 ] ASSEMBLER BEFORE OPTIMIZATION @@ -312,8 +316,12 @@ main: { // sub(byte register(A) ch) sub: { // [10] *(*(&(byte*) main::screen#0)) ← (byte) sub::ch#2 -- _deref_(_deref_pptc1)=vbuaa + ldy.z main.screen + sty.z $fe + ldy.z main.screen+1 + sty.z $ff ldy #0 - sta (main.screen),y + sta ($fe),y // [11] *(&(byte*) main::screen#0) ← ++ *(&(byte*) main::screen#0) -- _deref_pptc1=_inc__deref_pptc1 inc.z main.screen bne !+ @@ -372,7 +380,7 @@ zp ZP_WORD:2 [ main::screen#0 ] FINAL ASSEMBLER -Score: 58 +Score: 70 // File Comments // Tests (non-)optimization of constant pointers to pointers @@ -421,8 +429,12 @@ main: { sub: { // *(*dst)++ = ch // [10] *(*(&(byte*) main::screen#0)) ← (byte) sub::ch#2 -- _deref_(_deref_pptc1)=vbuaa + ldy.z main.screen + sty.z $fe + ldy.z main.screen+1 + sty.z $ff ldy #0 - sta (main.screen),y + sta ($fe),y // *(*dst)++ = ch; // [11] *(&(byte*) main::screen#0) ← ++ *(&(byte*) main::screen#0) -- _deref_pptc1=_inc__deref_pptc1 inc.z main.screen diff --git a/src/test/ref/struct-ptr-32.asm b/src/test/ref/struct-ptr-32.asm new file mode 100644 index 000000000..e41bc7cc7 --- /dev/null +++ b/src/test/ref/struct-ptr-32.asm @@ -0,0 +1,42 @@ +// Example of a struct containing an array +// Fails (by displaying "BB" ) because the memory layout is wrong - and the name is treated like a pointer (to 0x0000) instead of a value. +// https://gitlab.com/camelot/kickc/issues/312 +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .const SIZEOF_STRUCT_PERSON = 3 + .const OFFSET_STRUCT_PERSON_NAME = 1 +main: { + .label SCREEN = $400 + .label person = persons+SIZEOF_STRUCT_PERSON + lda #'a' + ldy persons+OFFSET_STRUCT_PERSON_NAME + sty.z $fe + ldy persons+OFFSET_STRUCT_PERSON_NAME+1 + sty.z $ff + ldy #0 + sta ($fe),y + lda #'b' + ldy persons+OFFSET_STRUCT_PERSON_NAME+1*SIZEOF_STRUCT_PERSON + sty.z $fe + ldy persons+OFFSET_STRUCT_PERSON_NAME+1*SIZEOF_STRUCT_PERSON+1 + sty.z $ff + ldy #0 + sta ($fe),y + ldy persons+OFFSET_STRUCT_PERSON_NAME + sty.z $fe + ldy persons+OFFSET_STRUCT_PERSON_NAME+1 + sty.z $ff + ldy #0 + lda ($fe),y + sta SCREEN + ldy person+OFFSET_STRUCT_PERSON_NAME + sty.z $fe + ldy person+OFFSET_STRUCT_PERSON_NAME+1 + sty.z $ff + ldy #0 + lda ($fe),y + sta SCREEN+1 + rts +} + persons: .fill 3*2, 0 diff --git a/src/test/ref/struct-ptr-32.cfg b/src/test/ref/struct-ptr-32.cfg new file mode 100644 index 000000000..d9c28474a --- /dev/null +++ b/src/test/ref/struct-ptr-32.cfg @@ -0,0 +1,18 @@ +@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] *(*((byte[$10]*)(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME)) ← (byte) 'a' + [5] *(*((byte[$10]*)(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME+(byte) 1*(const byte) SIZEOF_STRUCT_PERSON)) ← (byte) 'b' + [6] *((const byte*) main::SCREEN#0) ← *(*((byte[$10]*)(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME)) + [7] *((const byte*) main::SCREEN#0+(byte) 1) ← *(*((byte[$10]*)(const struct Person*) main::person#1+(const byte) OFFSET_STRUCT_PERSON_NAME)) + to:main::@return +main::@return: scope:[main] from main + [8] return + to:@return diff --git a/src/test/ref/struct-ptr-32.log b/src/test/ref/struct-ptr-32.log new file mode 100644 index 000000000..0c4dd0baf --- /dev/null +++ b/src/test/ref/struct-ptr-32.log @@ -0,0 +1,457 @@ +Fixing pointer increment (struct Person*) main::person ← ++ (struct Person*) main::person +Fixing pointer array-indexing *((struct Person[2]) persons + (number) 0) +Fixing pointer array-indexing *((struct Person[2]) persons + (number) 1) +Rewriting struct pointer member access *((struct Person[2]) persons + (number~) main::$0).name +Rewriting struct pointer member access *((struct Person[2]) persons + (number~) main::$1).name +Rewriting struct pointer member access *((struct Person*) main::person).name +Rewriting struct pointer member access *((struct Person*) main::person).name + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (struct Person[2]) persons#0 ← { fill( 2, 0) } + to:@1 +main: scope:[main] from @1 + (number~) main::$0 ← (number) 0 * (const byte) SIZEOF_STRUCT_PERSON + (byte[$10]*) main::$2 ← (byte[$10]*)(struct Person[2]) persons#0 + (const byte) OFFSET_STRUCT_PERSON_NAME + *(*((byte[$10]*) main::$2 + (number~) main::$0) + (number) 0) ← (byte) 'a' + (number~) main::$1 ← (number) 1 * (const byte) SIZEOF_STRUCT_PERSON + (byte[$10]*) main::$3 ← (byte[$10]*)(struct Person[2]) persons#0 + (const byte) OFFSET_STRUCT_PERSON_NAME + *(*((byte[$10]*) main::$3 + (number~) main::$1) + (number) 0) ← (byte) 'b' + (byte*) main::SCREEN#0 ← ((byte*)) (number) $400 + (struct Person*) main::person#0 ← (struct Person[2]) persons#0 + (byte[$10]*) main::$4 ← (byte[$10]*)(struct Person*) main::person#0 + (const byte) OFFSET_STRUCT_PERSON_NAME + *((byte*) main::SCREEN#0 + (number) 0) ← *(*((byte[$10]*) main::$4) + (number) 0) + (struct Person*) main::person#1 ← (struct Person*) main::person#0 + (const byte) SIZEOF_STRUCT_PERSON + (byte[$10]*) main::$5 ← (byte[$10]*)(struct Person*) main::person#1 + (const byte) OFFSET_STRUCT_PERSON_NAME + *((byte*) main::SCREEN#0 + (number) 1) ← *(*((byte[$10]*) main::$5) + (number) 0) + to:main::@return +main::@return: scope:[main] from main + 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) OFFSET_STRUCT_PERSON_NAME = (byte) 1 +(byte) Person::id +(byte[$10]) Person::name +(const byte) SIZEOF_STRUCT_PERSON = (byte) 3 +(void()) main() +(number~) main::$0 +(number~) main::$1 +(byte[$10]*) main::$2 +(byte[$10]*) main::$3 +(byte[$10]*) main::$4 +(byte[$10]*) main::$5 +(label) main::@return +(byte*) main::SCREEN +(byte*) main::SCREEN#0 +(struct Person*) main::person +(struct Person*) main::person#0 +(struct Person*) main::person#1 +(struct Person[2]) persons +(struct Person[2]) persons#0 + +Adding number conversion cast (unumber) 0 in (number~) main::$0 ← (number) 0 * (const byte) SIZEOF_STRUCT_PERSON +Adding number conversion cast (unumber) main::$0 in (number~) main::$0 ← (unumber)(number) 0 * (const byte) SIZEOF_STRUCT_PERSON +Adding number conversion cast (unumber) 0 in *(*((byte[$10]*) main::$2 + (unumber~) main::$0) + (number) 0) ← (byte) 'a' +Adding number conversion cast (unumber) 1 in (number~) main::$1 ← (number) 1 * (const byte) SIZEOF_STRUCT_PERSON +Adding number conversion cast (unumber) main::$1 in (number~) main::$1 ← (unumber)(number) 1 * (const byte) SIZEOF_STRUCT_PERSON +Adding number conversion cast (unumber) 0 in *(*((byte[$10]*) main::$3 + (unumber~) main::$1) + (number) 0) ← (byte) 'b' +Adding number conversion cast (unumber) 0 in *((byte*) main::SCREEN#0 + (number) 0) ← *(*((byte[$10]*) main::$4) + (number) 0) +Adding number conversion cast (unumber) 0 in *((byte*) main::SCREEN#0 + (number) 0) ← *(*((byte[$10]*) main::$4) + (unumber)(number) 0) +Adding number conversion cast (unumber) 0 in *((byte*) main::SCREEN#0 + (number) 1) ← *(*((byte[$10]*) main::$5) + (number) 0) +Adding number conversion cast (unumber) 1 in *((byte*) main::SCREEN#0 + (number) 1) ← *(*((byte[$10]*) main::$5) + (unumber)(number) 0) +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (byte*) main::SCREEN#0 ← (byte*)(number) $400 +Successful SSA optimization Pass2InlineCast +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant integer cast 1 +Simplifying constant integer cast 0 +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant integer cast 1 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 1 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 1 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Inferred type updated to byte in (unumber~) main::$0 ← (byte) 0 * (const byte) SIZEOF_STRUCT_PERSON +Inferred type updated to byte in (unumber~) main::$1 ← (byte) 1 * (const byte) SIZEOF_STRUCT_PERSON +Constant right-side identified [0] (struct Person[2]) persons#0 ← { fill( 2, 0) } +Constant right-side identified [1] (byte~) main::$0 ← (byte) 0 * (const byte) SIZEOF_STRUCT_PERSON +Constant right-side identified [4] (byte~) main::$1 ← (byte) 1 * (const byte) SIZEOF_STRUCT_PERSON +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const struct Person[2]) persons#0 = { fill( 2, 0) } +Constant (const byte) main::$0 = 0*SIZEOF_STRUCT_PERSON +Constant (const byte) main::$1 = 1*SIZEOF_STRUCT_PERSON +Constant (const byte*) main::SCREEN#0 = (byte*) 1024 +Successful SSA optimization Pass2ConstantIdentification +Constant (const struct Person*) main::person#0 = persons#0 +Successful SSA optimization Pass2ConstantIdentification +Constant value identified (byte[$10]*)persons#0 in [2] (byte[$10]*) main::$2 ← (byte[$10]*)(const struct Person[2]) persons#0 + (const byte) OFFSET_STRUCT_PERSON_NAME +Constant value identified (byte[$10]*)persons#0 in [5] (byte[$10]*) main::$3 ← (byte[$10]*)(const struct Person[2]) persons#0 + (const byte) OFFSET_STRUCT_PERSON_NAME +Constant value identified (byte[$10]*)main::person#0 in [9] (byte[$10]*) main::$4 ← (byte[$10]*)(const struct Person*) main::person#0 + (const byte) OFFSET_STRUCT_PERSON_NAME +Successful SSA optimization Pass2ConstantValues +Converting *(pointer+n) to pointer[n] [10] *((const byte*) main::SCREEN#0 + (byte) 0) ← *(*((byte[$10]*) main::$4) + (byte) 0) -- *((byte[$10]*)main::person#0 + OFFSET_STRUCT_PERSON_NAME) +Converting *(pointer+n) to pointer[n] [13] *((const byte*) main::SCREEN#0 + (byte) 1) ← *(*((byte[$10]*) main::$5) + (byte) 0) -- *((byte[$10]*)main::person#1 + OFFSET_STRUCT_PERSON_NAME) +Successful SSA optimization Pass2InlineDerefIdx +Simplifying constant evaluating to zero (byte) 0*(const byte) SIZEOF_STRUCT_PERSON in +Successful SSA optimization PassNSimplifyConstantZero +Simplifying expression containing zero *(main::$2 + main::$0) in [3] *(*((byte[$10]*) main::$2 + (const byte) main::$0) + (byte) 0) ← (byte) 'a' +Simplifying expression containing zero main::$2 in [3] *(*((byte[$10]*) main::$2 + (const byte) main::$0)) ← (byte) 'a' +Simplifying expression containing zero *(main::$3 + main::$1) in [6] *(*((byte[$10]*) main::$3 + (const byte) main::$1) + (byte) 0) ← (byte) 'b' +Simplifying expression containing zero *((byte[$10]*)main::person#0 + OFFSET_STRUCT_PERSON_NAME) in [10] *((const byte*) main::SCREEN#0 + (byte) 0) ← *(*((byte[$10]*)(const struct Person*) main::person#0 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) 0) +Simplifying expression containing zero main::SCREEN#0 in [10] *((const byte*) main::SCREEN#0 + (byte) 0) ← *(*((byte[$10]*)(const struct Person*) main::person#0 + (const byte) OFFSET_STRUCT_PERSON_NAME)) +Simplifying expression containing zero *((byte[$10]*)main::person#1 + OFFSET_STRUCT_PERSON_NAME) in [13] *((const byte*) main::SCREEN#0 + (byte) 1) ← *(*((byte[$10]*)(struct Person*) main::person#1 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) 0) +Successful SSA optimization PassNSimplifyExpressionWithZero +Eliminating unused variable (byte[$10]*) main::$4 and assignment [4] (byte[$10]*) main::$4 ← (byte[$10]*)(const struct Person*) main::person#0 + (const byte) OFFSET_STRUCT_PERSON_NAME +Eliminating unused variable (byte[$10]*) main::$5 and assignment [7] (byte[$10]*) main::$5 ← (byte[$10]*)(struct Person*) main::person#1 + (const byte) OFFSET_STRUCT_PERSON_NAME +Eliminating unused constant (const byte) main::$0 +Successful SSA optimization PassNEliminateUnusedVars +Constant right-side identified [0] (byte[$10]*) main::$2 ← (byte[$10]*)(const struct Person[2]) persons#0 + (const byte) OFFSET_STRUCT_PERSON_NAME +Constant right-side identified [2] (byte[$10]*) main::$3 ← (byte[$10]*)(const struct Person[2]) persons#0 + (const byte) OFFSET_STRUCT_PERSON_NAME +Constant right-side identified [5] (struct Person*) main::person#1 ← (const struct Person*) main::person#0 + (const byte) SIZEOF_STRUCT_PERSON +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte[$10]*) main::$2 = (byte[$10]*)persons#0+OFFSET_STRUCT_PERSON_NAME +Constant (const byte[$10]*) main::$3 = (byte[$10]*)persons#0+OFFSET_STRUCT_PERSON_NAME +Constant (const struct Person*) main::person#1 = main::person#0+SIZEOF_STRUCT_PERSON +Successful SSA optimization Pass2ConstantIdentification +Constant value identified (byte[$10]*)main::person#1 in [6] *((const byte*) main::SCREEN#0 + (byte) 1) ← *(*((byte[$10]*)(const struct Person*) main::person#1 + (const byte) OFFSET_STRUCT_PERSON_NAME)) +Successful SSA optimization Pass2ConstantValues +Inlining constant with different constant siblings (const struct Person*) main::person#0 +Constant inlined main::$3 = (byte[$10]*)(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME +Constant inlined main::$1 = (byte) 1*(const byte) SIZEOF_STRUCT_PERSON +Constant inlined main::$2 = (byte[$10]*)(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME +Constant inlined main::person#0 = (const struct Person[2]) persons#0 +Successful SSA optimization Pass2ConstantInlining +Consolidated array index constant in *((byte[$10]*)persons#0+OFFSET_STRUCT_PERSON_NAME+1*SIZEOF_STRUCT_PERSON) +Consolidated array index constant in *((byte[$10]*)persons#0+OFFSET_STRUCT_PERSON_NAME) +Consolidated array index constant in *((byte[$10]*)main::person#1+OFFSET_STRUCT_PERSON_NAME) +Consolidated array index constant in *(main::SCREEN#0+1) +Successful SSA optimization Pass2ConstantAdditionElimination +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 +CALL GRAPH +Calls in [] to main:2 + +Created 0 initial phi equivalence classes +Coalesced down to 0 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 + +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] *(*((byte[$10]*)(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME)) ← (byte) 'a' + [5] *(*((byte[$10]*)(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME+(byte) 1*(const byte) SIZEOF_STRUCT_PERSON)) ← (byte) 'b' + [6] *((const byte*) main::SCREEN#0) ← *(*((byte[$10]*)(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME)) + [7] *((const byte*) main::SCREEN#0+(byte) 1) ← *(*((byte[$10]*)(const struct Person*) main::person#1+(const byte) OFFSET_STRUCT_PERSON_NAME)) + to:main::@return +main::@return: scope:[main] from main + [8] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(byte) Person::id +(byte[$10]) Person::name +(void()) main() +(byte*) main::SCREEN +(struct Person*) main::person +(struct Person[2]) persons + +Initial phi equivalence classes +Complete equivalence classes + +INITIAL ASM +Target platform is c64basic / MOS6502X + // File Comments +// Example of a struct containing an array +// Fails (by displaying "BB" ) because the memory layout is wrong - and the name is treated like a pointer (to 0x0000) instead of a value. +// https://gitlab.com/camelot/kickc/issues/312 + // Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" + // Global Constants & labels + .const SIZEOF_STRUCT_PERSON = 3 + .const OFFSET_STRUCT_PERSON_NAME = 1 + // @begin +bbegin: + // [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 + // @1 +b1: + // [2] call main + jsr main + // [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend + // @end +bend: + // main +main: { + .label SCREEN = $400 + .label person = persons+SIZEOF_STRUCT_PERSON + // [4] *(*((byte[$10]*)(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME)) ← (byte) 'a' -- _deref_(_deref_pptc1)=vbuc2 + lda #'a' + ldy persons+OFFSET_STRUCT_PERSON_NAME + sty.z $fe + ldy persons+OFFSET_STRUCT_PERSON_NAME+1 + sty.z $ff + ldy #0 + sta ($fe),y + // [5] *(*((byte[$10]*)(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME+(byte) 1*(const byte) SIZEOF_STRUCT_PERSON)) ← (byte) 'b' -- _deref_(_deref_pptc1)=vbuc2 + lda #'b' + ldy persons+OFFSET_STRUCT_PERSON_NAME+1*SIZEOF_STRUCT_PERSON + sty.z $fe + ldy persons+OFFSET_STRUCT_PERSON_NAME+1*SIZEOF_STRUCT_PERSON+1 + sty.z $ff + ldy #0 + sta ($fe),y + // [6] *((const byte*) main::SCREEN#0) ← *(*((byte[$10]*)(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME)) -- _deref_pbuc1=_deref_(_deref_pptc2) + ldy persons+OFFSET_STRUCT_PERSON_NAME + sty.z $fe + ldy persons+OFFSET_STRUCT_PERSON_NAME+1 + sty.z $ff + ldy #0 + lda ($fe),y + sta SCREEN + // [7] *((const byte*) main::SCREEN#0+(byte) 1) ← *(*((byte[$10]*)(const struct Person*) main::person#1+(const byte) OFFSET_STRUCT_PERSON_NAME)) -- _deref_pbuc1=_deref_(_deref_pptc2) + ldy person+OFFSET_STRUCT_PERSON_NAME + sty.z $fe + ldy person+OFFSET_STRUCT_PERSON_NAME+1 + sty.z $ff + ldy #0 + lda ($fe),y + sta SCREEN+1 + jmp breturn + // main::@return + breturn: + // [8] return + rts +} + // File Data + persons: .fill 3*2, 0 + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] *(*((byte[$10]*)(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME)) ← (byte) 'a' [ ] ( main:2 [ ] ) always clobbers reg byte a reg byte y +Statement [5] *(*((byte[$10]*)(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME+(byte) 1*(const byte) SIZEOF_STRUCT_PERSON)) ← (byte) 'b' [ ] ( main:2 [ ] ) always clobbers reg byte a reg byte y +Statement [6] *((const byte*) main::SCREEN#0) ← *(*((byte[$10]*)(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME)) [ ] ( main:2 [ ] ) always clobbers reg byte a reg byte y +Statement [7] *((const byte*) main::SCREEN#0+(byte) 1) ← *(*((byte[$10]*)(const struct Person*) main::person#1+(const byte) OFFSET_STRUCT_PERSON_NAME)) [ ] ( main:2 [ ] ) always clobbers reg byte a reg byte y + +REGISTER UPLIFT SCOPES +Uplift Scope [Person] +Uplift Scope [main] +Uplift Scope [] + +Uplifting [Person] best 119 combination +Uplifting [main] best 119 combination +Uplifting [] best 119 combination + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Example of a struct containing an array +// Fails (by displaying "BB" ) because the memory layout is wrong - and the name is treated like a pointer (to 0x0000) instead of a value. +// https://gitlab.com/camelot/kickc/issues/312 + // Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" + // Global Constants & labels + .const SIZEOF_STRUCT_PERSON = 3 + .const OFFSET_STRUCT_PERSON_NAME = 1 + // @begin +bbegin: + // [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 + // @1 +b1: + // [2] call main + jsr main + // [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend + // @end +bend: + // main +main: { + .label SCREEN = $400 + .label person = persons+SIZEOF_STRUCT_PERSON + // [4] *(*((byte[$10]*)(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME)) ← (byte) 'a' -- _deref_(_deref_pptc1)=vbuc2 + lda #'a' + ldy persons+OFFSET_STRUCT_PERSON_NAME + sty.z $fe + ldy persons+OFFSET_STRUCT_PERSON_NAME+1 + sty.z $ff + ldy #0 + sta ($fe),y + // [5] *(*((byte[$10]*)(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME+(byte) 1*(const byte) SIZEOF_STRUCT_PERSON)) ← (byte) 'b' -- _deref_(_deref_pptc1)=vbuc2 + lda #'b' + ldy persons+OFFSET_STRUCT_PERSON_NAME+1*SIZEOF_STRUCT_PERSON + sty.z $fe + ldy persons+OFFSET_STRUCT_PERSON_NAME+1*SIZEOF_STRUCT_PERSON+1 + sty.z $ff + ldy #0 + sta ($fe),y + // [6] *((const byte*) main::SCREEN#0) ← *(*((byte[$10]*)(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME)) -- _deref_pbuc1=_deref_(_deref_pptc2) + ldy persons+OFFSET_STRUCT_PERSON_NAME + sty.z $fe + ldy persons+OFFSET_STRUCT_PERSON_NAME+1 + sty.z $ff + ldy #0 + lda ($fe),y + sta SCREEN + // [7] *((const byte*) main::SCREEN#0+(byte) 1) ← *(*((byte[$10]*)(const struct Person*) main::person#1+(const byte) OFFSET_STRUCT_PERSON_NAME)) -- _deref_pbuc1=_deref_(_deref_pptc2) + ldy person+OFFSET_STRUCT_PERSON_NAME + sty.z $fe + ldy person+OFFSET_STRUCT_PERSON_NAME+1 + sty.z $ff + ldy #0 + lda ($fe),y + sta SCREEN+1 + jmp breturn + // main::@return + breturn: + // [8] return + rts +} + // File Data + persons: .fill 3*2, 0 + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction bend_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(const byte) OFFSET_STRUCT_PERSON_NAME OFFSET_STRUCT_PERSON_NAME = (byte) 1 +(byte) Person::id +(byte[$10]) Person::name +(const byte) SIZEOF_STRUCT_PERSON SIZEOF_STRUCT_PERSON = (byte) 3 +(void()) main() +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024 +(struct Person*) main::person +(const struct Person*) main::person#1 person = (const struct Person[2]) persons#0+(const byte) SIZEOF_STRUCT_PERSON +(struct Person[2]) persons +(const struct Person[2]) persons#0 persons = { fill( 2, 0) } + + + +FINAL ASSEMBLER +Score: 104 + + // File Comments +// Example of a struct containing an array +// Fails (by displaying "BB" ) because the memory layout is wrong - and the name is treated like a pointer (to 0x0000) instead of a value. +// https://gitlab.com/camelot/kickc/issues/312 + // Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + // Global Constants & labels + .const SIZEOF_STRUCT_PERSON = 3 + .const OFFSET_STRUCT_PERSON_NAME = 1 + // @begin + // [1] phi from @begin to @1 [phi:@begin->@1] + // @1 + // [2] call main + // [3] phi from @1 to @end [phi:@1->@end] + // @end + // main +main: { + .label SCREEN = $400 + .label person = persons+SIZEOF_STRUCT_PERSON + // persons[0].name[0] = 'a' + // [4] *(*((byte[$10]*)(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME)) ← (byte) 'a' -- _deref_(_deref_pptc1)=vbuc2 + lda #'a' + ldy persons+OFFSET_STRUCT_PERSON_NAME + sty.z $fe + ldy persons+OFFSET_STRUCT_PERSON_NAME+1 + sty.z $ff + ldy #0 + sta ($fe),y + // persons[1].name[0] = 'b' + // [5] *(*((byte[$10]*)(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME+(byte) 1*(const byte) SIZEOF_STRUCT_PERSON)) ← (byte) 'b' -- _deref_(_deref_pptc1)=vbuc2 + lda #'b' + ldy persons+OFFSET_STRUCT_PERSON_NAME+1*SIZEOF_STRUCT_PERSON + sty.z $fe + ldy persons+OFFSET_STRUCT_PERSON_NAME+1*SIZEOF_STRUCT_PERSON+1 + sty.z $ff + ldy #0 + sta ($fe),y + // SCREEN[0] = person->name[0] + // [6] *((const byte*) main::SCREEN#0) ← *(*((byte[$10]*)(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME)) -- _deref_pbuc1=_deref_(_deref_pptc2) + ldy persons+OFFSET_STRUCT_PERSON_NAME + sty.z $fe + ldy persons+OFFSET_STRUCT_PERSON_NAME+1 + sty.z $ff + ldy #0 + lda ($fe),y + sta SCREEN + // SCREEN[1] = person->name[0] + // [7] *((const byte*) main::SCREEN#0+(byte) 1) ← *(*((byte[$10]*)(const struct Person*) main::person#1+(const byte) OFFSET_STRUCT_PERSON_NAME)) -- _deref_pbuc1=_deref_(_deref_pptc2) + ldy person+OFFSET_STRUCT_PERSON_NAME + sty.z $fe + ldy person+OFFSET_STRUCT_PERSON_NAME+1 + sty.z $ff + ldy #0 + lda ($fe),y + sta SCREEN+1 + // main::@return + // } + // [8] return + rts +} + // File Data + persons: .fill 3*2, 0 + diff --git a/src/test/ref/struct-ptr-32.sym b/src/test/ref/struct-ptr-32.sym new file mode 100644 index 000000000..5951e026d --- /dev/null +++ b/src/test/ref/struct-ptr-32.sym @@ -0,0 +1,16 @@ +(label) @1 +(label) @begin +(label) @end +(const byte) OFFSET_STRUCT_PERSON_NAME OFFSET_STRUCT_PERSON_NAME = (byte) 1 +(byte) Person::id +(byte[$10]) Person::name +(const byte) SIZEOF_STRUCT_PERSON SIZEOF_STRUCT_PERSON = (byte) 3 +(void()) main() +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024 +(struct Person*) main::person +(const struct Person*) main::person#1 person = (const struct Person[2]) persons#0+(const byte) SIZEOF_STRUCT_PERSON +(struct Person[2]) persons +(const struct Person[2]) persons#0 persons = { fill( 2, 0) } +