From 0fb90dc8b78b49e5a7b066cb63a7fb23cf4c25ee Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Sun, 25 Aug 2019 14:51:07 +0200 Subject: [PATCH] Fixed problem casting a constant pointer to char. Closes #288 --- .../model/values/ConstantSymbolPointer.java | 11 + .../dk/camelot64/kickc/test/TestPrograms.java | 8 +- src/test/ref/long-pointer-1.asm | 20 ++ src/test/ref/long-pointer-1.cfg | 16 + src/test/ref/long-pointer-1.log | 282 ++++++++++++++++++ src/test/ref/long-pointer-1.sym | 11 + 6 files changed, 342 insertions(+), 6 deletions(-) create mode 100644 src/test/ref/long-pointer-1.asm create mode 100644 src/test/ref/long-pointer-1.cfg create mode 100644 src/test/ref/long-pointer-1.log create mode 100644 src/test/ref/long-pointer-1.sym diff --git a/src/main/java/dk/camelot64/kickc/model/values/ConstantSymbolPointer.java b/src/main/java/dk/camelot64/kickc/model/values/ConstantSymbolPointer.java index 4f7c079a9..f7008ccf1 100644 --- a/src/main/java/dk/camelot64/kickc/model/values/ConstantSymbolPointer.java +++ b/src/main/java/dk/camelot64/kickc/model/values/ConstantSymbolPointer.java @@ -3,6 +3,7 @@ package dk.camelot64.kickc.model.values; import dk.camelot64.kickc.model.*; import dk.camelot64.kickc.model.symbols.ProgramScope; import dk.camelot64.kickc.model.symbols.Symbol; +import dk.camelot64.kickc.model.symbols.Variable; import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.types.SymbolTypePointer; @@ -34,6 +35,16 @@ public class ConstantSymbolPointer implements ConstantValue { @Override public ConstantLiteral calculateLiteral(ProgramScope scope) { + // If the symbol has been allocated we can calculate a literal value! + Symbol symbol = scope.getSymbol(toSymbol); + if(symbol instanceof Variable) { + Registers.Register allocation = ((Variable) symbol).getAllocation(); + if(allocation!=null && allocation.isZp()) { + int zp = ((Registers.RegisterZp) allocation).getZp(); + return new ConstantInteger((long)zp, SymbolType.BYTE); + } + } + // WE cannot calculate a literal value throw new ConstantNotLiteral("Cannot calculate literal var pointer"); } diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 52ad04935..a8bb9e592 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -48,22 +48,19 @@ public class TestPrograms { } - // TODO: Fix cast of constant pointer https://gitlab.com/camelot/kickc/issues/288 - /* @Test public void testLongPointer1() throws IOException, URISyntaxException { compileAndCompare("long-pointer-1"); } - */ @Test public void testLongPointer0() throws IOException, URISyntaxException { - compileAndCompare("pointer-anding"); + compileAndCompare("long-pointer-0"); } @Test public void testPointerAnding() throws IOException, URISyntaxException { - compileAndCompare("long-pointer-0"); + compileAndCompare("pointer-anding"); } @Test @@ -71,7 +68,6 @@ public class TestPrograms { compileAndCompare("forced-zeropage"); } - @Test public void testFloatErrorMessage() throws IOException, URISyntaxException { assertError("float-error-message", "Non-integer numbers are not supported"); diff --git a/src/test/ref/long-pointer-1.asm b/src/test/ref/long-pointer-1.asm new file mode 100644 index 000000000..293d2f433 --- /dev/null +++ b/src/test/ref/long-pointer-1.asm @@ -0,0 +1,20 @@ +// Tests creating a long (32bit) pointer on zeropage for 45GS02 flat memory access +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +main: { + .const long_ptr_zp = long_ptr + .label long_ptr = 2 + lda #<$12345678 + sta.z long_ptr + lda #>$12345678 + sta.z long_ptr+1 + lda #<$12345678>>$10 + sta.z long_ptr+2 + lda #>$12345678>>$10 + sta.z long_ptr+3 + nop + lda (long_ptr_zp),y + sta.z $ff + rts +} diff --git a/src/test/ref/long-pointer-1.cfg b/src/test/ref/long-pointer-1.cfg new file mode 100644 index 000000000..713ba2f99 --- /dev/null +++ b/src/test/ref/long-pointer-1.cfg @@ -0,0 +1,16 @@ +@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] (dword) main::long_ptr#0 ← (dword) $12345678 + asm { nop lda(long_ptr_zp),y sta$ff } + to:main::@return +main::@return: scope:[main] from main + [6] return + to:@return diff --git a/src/test/ref/long-pointer-1.log b/src/test/ref/long-pointer-1.log new file mode 100644 index 000000000..fccdb2f21 --- /dev/null +++ b/src/test/ref/long-pointer-1.log @@ -0,0 +1,282 @@ +Setting inferred volatile on symbol affected by address-of (dword*~) main::$0 ← & (dword) main::long_ptr + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (dword) main::long_ptr#0 ← (number) $12345678 + (dword*~) main::$0 ← & (dword) main::long_ptr#0 + (byte~) main::$1 ← ((byte)) (dword*~) main::$0 + (byte) main::long_ptr_zp#0 ← (byte~) main::$1 + asm { nop lda(long_ptr_zp),y sta$ff } + 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 +(void()) main() +(dword*~) main::$0 +(byte~) main::$1 +(label) main::@return +(dword) main::long_ptr +(dword) main::long_ptr#0 +(byte) main::long_ptr_zp +(byte) main::long_ptr_zp#0 + +Adding number conversion cast (unumber) $12345678 in (dword) main::long_ptr#0 ← (number) $12345678 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (dword) main::long_ptr#0 ← (unumber)(number) $12345678 +Inlining cast (byte~) main::$1 ← (byte)(dword*~) main::$0 +Successful SSA optimization Pass2InlineCast +Simplifying constant integer cast $12345678 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (dword) $12345678 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias (byte) main::long_ptr_zp#0 = (byte~) main::$1 +Successful SSA optimization Pass2AliasElimination +Constant right-side identified [1] (dword*~) main::$0 ← & (dword) main::long_ptr#0 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const dword*) main::$0 = &main::long_ptr#0 +Successful SSA optimization Pass2ConstantIdentification +Constant value identified (byte)main::$0 in [2] (byte) main::long_ptr_zp#0 ← (byte)(const dword*) main::$0 +Successful SSA optimization Pass2ConstantValues +Constant (const byte) main::long_ptr_zp#0 = (byte)main::$0 +Successful SSA optimization Pass2ConstantIdentification +Constant inlined main::$0 = &(dword) main::long_ptr#0 +Successful SSA optimization Pass2ConstantInlining +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] (dword) main::long_ptr#0 ← (dword) $12345678 + asm { nop lda(long_ptr_zp),y sta$ff } + to:main::@return +main::@return: scope:[main] from main + [6] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(dword) main::long_ptr +(dword) main::long_ptr#0 20.0 +(byte) main::long_ptr_zp + +Initial phi equivalence classes +Complete equivalence classes +[ main::long_ptr#0 ] +Allocated zp ZP_DWORD:2 [ main::long_ptr#0 ] + +INITIAL ASM +Target platform is c64basic + // File Comments +// Tests creating a long (32bit) pointer on zeropage for 45GS02 flat memory access + // Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" + // Global Constants & labels + // @begin +bbegin: + // [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 + // @1 +b1: + // [2] call main + jsr main + // [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend + // @end +bend: + // main +main: { + .const long_ptr_zp = long_ptr + .label long_ptr = 2 + // [4] (dword) main::long_ptr#0 ← (dword) $12345678 -- vduz1=vduc1 + lda #<$12345678 + sta.z long_ptr + lda #>$12345678 + sta.z long_ptr+1 + lda #<$12345678>>$10 + sta.z long_ptr+2 + lda #>$12345678>>$10 + sta.z long_ptr+3 + // asm { nop lda(long_ptr_zp),y sta$ff } + nop + lda (long_ptr_zp),y + sta.z $ff + jmp breturn + // main::@return + breturn: + // [6] return + rts +} + // File Data + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] (dword) main::long_ptr#0 ← (dword) $12345678 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement asm { nop lda(long_ptr_zp),y sta$ff } always clobbers reg byte a +Potential registers zp ZP_DWORD:2 [ main::long_ptr#0 ] : zp ZP_DWORD:2 , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 20: zp ZP_DWORD:2 [ main::long_ptr#0 ] +Uplift Scope [] + +Uplifting [main] best 51 combination zp ZP_DWORD:2 [ main::long_ptr#0 ] +Uplifting [] best 51 combination + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Tests creating a long (32bit) pointer on zeropage for 45GS02 flat memory access + // Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" + // Global Constants & labels + // @begin +bbegin: + // [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 + // @1 +b1: + // [2] call main + jsr main + // [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend + // @end +bend: + // main +main: { + .const long_ptr_zp = long_ptr + .label long_ptr = 2 + // [4] (dword) main::long_ptr#0 ← (dword) $12345678 -- vduz1=vduc1 + lda #<$12345678 + sta.z long_ptr + lda #>$12345678 + sta.z long_ptr+1 + lda #<$12345678>>$10 + sta.z long_ptr+2 + lda #>$12345678>>$10 + sta.z long_ptr+3 + // asm { nop lda(long_ptr_zp),y sta$ff } + nop + lda (long_ptr_zp),y + sta.z $ff + jmp breturn + // main::@return + breturn: + // [6] return + rts +} + // File Data + +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 +(void()) main() +(label) main::@return +(dword) main::long_ptr +(dword) main::long_ptr#0 long_ptr zp ZP_DWORD:2 20.0 +(byte) main::long_ptr_zp +(const byte) main::long_ptr_zp#0 long_ptr_zp = (byte)&(dword) main::long_ptr#0 + +zp ZP_DWORD:2 [ main::long_ptr#0 ] + + +FINAL ASSEMBLER +Score: 36 + + // File Comments +// Tests creating a long (32bit) pointer on zeropage for 45GS02 flat memory access + // Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + // Global Constants & labels + // @begin + // [1] phi from @begin to @1 [phi:@begin->@1] + // @1 + // [2] call main + // [3] phi from @1 to @end [phi:@1->@end] + // @end + // main +main: { + .const long_ptr_zp = long_ptr + .label long_ptr = 2 + // long_ptr = 0x12345678 + // [4] (dword) main::long_ptr#0 ← (dword) $12345678 -- vduz1=vduc1 + lda #<$12345678 + sta.z long_ptr + lda #>$12345678 + sta.z long_ptr+1 + lda #<$12345678>>$10 + sta.z long_ptr+2 + lda #>$12345678>>$10 + sta.z long_ptr+3 + // asm + // asm { nop lda(long_ptr_zp),y sta$ff } + nop + lda (long_ptr_zp),y + sta.z $ff + // main::@return + // } + // [6] return + rts +} + // File Data + diff --git a/src/test/ref/long-pointer-1.sym b/src/test/ref/long-pointer-1.sym new file mode 100644 index 000000000..31c06d4d2 --- /dev/null +++ b/src/test/ref/long-pointer-1.sym @@ -0,0 +1,11 @@ +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@return +(dword) main::long_ptr +(dword) main::long_ptr#0 long_ptr zp ZP_DWORD:2 20.0 +(byte) main::long_ptr_zp +(const byte) main::long_ptr_zp#0 long_ptr_zp = (byte)&(dword) main::long_ptr#0 + +zp ZP_DWORD:2 [ main::long_ptr#0 ]