From d6ad2c3b9b35a814f0c791d550ea06e5a167cb9d Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Mon, 9 Sep 2019 15:51:39 +0200 Subject: [PATCH] Added missing fragment. Fixed exception when casting literal string. Closes #309 --- .../mos6502-common/vduz1=vduz2_ror_16.asm | 8 + .../model/operators/OperatorCastDWord.java | 7 +- .../model/operators/OperatorCastWord.java | 7 +- .../dk/camelot64/kickc/test/TestPrograms.java | 10 + src/test/kc/inline-string-4.kc | 13 + src/test/ref/inline-string-4.asm | 23 ++ src/test/ref/inline-string-4.cfg | 22 ++ src/test/ref/inline-string-4.log | 351 ++++++++++++++++++ src/test/ref/inline-string-4.sym | 15 + 9 files changed, 452 insertions(+), 4 deletions(-) create mode 100644 src/main/fragment/mos6502-common/vduz1=vduz2_ror_16.asm create mode 100644 src/test/kc/inline-string-4.kc create mode 100644 src/test/ref/inline-string-4.asm create mode 100644 src/test/ref/inline-string-4.cfg create mode 100644 src/test/ref/inline-string-4.log create mode 100644 src/test/ref/inline-string-4.sym diff --git a/src/main/fragment/mos6502-common/vduz1=vduz2_ror_16.asm b/src/main/fragment/mos6502-common/vduz1=vduz2_ror_16.asm new file mode 100644 index 000000000..e567cfc1c --- /dev/null +++ b/src/main/fragment/mos6502-common/vduz1=vduz2_ror_16.asm @@ -0,0 +1,8 @@ +lda #0 +sta {z1}+2 +sta {z1}+3 +lda {z2}+3 +sta {z1}+1 +lda {z2}+2 +sta {z1} + diff --git a/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastDWord.java b/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastDWord.java index 54cb2efc7..14e7c1b9d 100644 --- a/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastDWord.java +++ b/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastDWord.java @@ -1,11 +1,13 @@ package dk.camelot64.kickc.model.operators; import dk.camelot64.kickc.model.CompileError; +import dk.camelot64.kickc.model.ConstantNotLiteral; import dk.camelot64.kickc.model.symbols.ProgramScope; import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.values.ConstantInteger; import dk.camelot64.kickc.model.values.ConstantLiteral; import dk.camelot64.kickc.model.values.ConstantPointer; +import dk.camelot64.kickc.model.values.ConstantString; /** Unary Cast to double word operator ( (dword) x ) */ public class OperatorCastDWord extends OperatorCast { @@ -18,9 +20,10 @@ public class OperatorCastDWord extends OperatorCast { public ConstantLiteral calculateLiteral(ConstantLiteral value, ProgramScope scope) { if(value instanceof ConstantInteger) { return new ConstantInteger(0xffffffffL & ((ConstantInteger) value).getValue(), SymbolType.DWORD); - } - if(value instanceof ConstantPointer) { + } else if(value instanceof ConstantPointer) { return new ConstantInteger(0xffff & ((ConstantPointer) value).getLocation(), SymbolType.DWORD); + } else if(value instanceof ConstantString) { + throw new ConstantNotLiteral("String cannot be cast to dword"); } throw new CompileError("Calculation not implemented " + getOperator() + " " + value ); } diff --git a/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastWord.java b/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastWord.java index aa0b6c1b6..c5b349696 100644 --- a/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastWord.java +++ b/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastWord.java @@ -1,11 +1,13 @@ package dk.camelot64.kickc.model.operators; import dk.camelot64.kickc.model.CompileError; +import dk.camelot64.kickc.model.ConstantNotLiteral; import dk.camelot64.kickc.model.symbols.ProgramScope; import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.values.ConstantInteger; import dk.camelot64.kickc.model.values.ConstantLiteral; import dk.camelot64.kickc.model.values.ConstantPointer; +import dk.camelot64.kickc.model.values.ConstantString; /** Unary Cast to word operator ( (word) x ) */ public class OperatorCastWord extends OperatorCast { @@ -18,9 +20,10 @@ public class OperatorCastWord extends OperatorCast { public ConstantLiteral calculateLiteral(ConstantLiteral value, ProgramScope scope) { if(value instanceof ConstantInteger) { return new ConstantInteger(0xffff & ((ConstantInteger) value).getValue(), SymbolType.WORD); - } - if(value instanceof ConstantPointer) { + } else if(value instanceof ConstantPointer) { return new ConstantInteger(0xffff & ((ConstantPointer) value).getLocation(), SymbolType.WORD); + } else if(value instanceof ConstantString) { + throw new ConstantNotLiteral("String cannot be cast to word"); } throw new CompileError("Calculation not implemented " + getOperator() + " " + value ); } diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 152223e6c..8c3169177 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -35,6 +35,11 @@ public class TestPrograms { public TestPrograms() { } + @Test + public void testOs51() throws IOException, URISyntaxException { + compileAndCompare("complex/unit5/os5.1", log().verboseSSAOptimize()); + } + @Test public void testCpu6502() throws IOException, URISyntaxException { compileAndCompare("cpu-6502"); @@ -2313,6 +2318,11 @@ public class TestPrograms { compileAndCompare("inline-string-3"); } + @Test + public void testInlineString4() throws IOException, URISyntaxException { + compileAndCompare("inline-string-4"); + } + @Test public void testEmptyBlockError() throws IOException, URISyntaxException { compileAndCompare("emptyblock-error"); diff --git a/src/test/kc/inline-string-4.kc b/src/test/kc/inline-string-4.kc new file mode 100644 index 000000000..9767dd134 --- /dev/null +++ b/src/test/kc/inline-string-4.kc @@ -0,0 +1,13 @@ +// Test casting the address of an inline string to a dword. + +void main() { + const char[] msg = "camelot"; + unsigned long dw = (unsigned long)msg; + output(dw); +} + +const unsigned long* screen = 0x0400; + +void output(unsigned long dw) { + *screen = dw; +} \ No newline at end of file diff --git a/src/test/ref/inline-string-4.asm b/src/test/ref/inline-string-4.asm new file mode 100644 index 000000000..a5171dcf1 --- /dev/null +++ b/src/test/ref/inline-string-4.asm @@ -0,0 +1,23 @@ +// Test casting the address of an inline string to a dword. +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .label screen = $400 +main: { + .label dw = msg + jsr output + rts + msg: .text "camelot" + .byte 0 +} +output: { + lda #main.dw + sta screen+1 + lda #>$10 + sta screen+2 + lda #>main.dw>>$10 + sta screen+3 + rts +} diff --git a/src/test/ref/inline-string-4.cfg b/src/test/ref/inline-string-4.cfg new file mode 100644 index 000000000..2e7587004 --- /dev/null +++ b/src/test/ref/inline-string-4.cfg @@ -0,0 +1,22 @@ +@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() + [5] call output + to:main::@return +main::@return: scope:[main] from main + [6] return + to:@return +output: scope:[output] from main + [7] *((const dword*) screen#0) ← (const dword) main::dw#0 + to:output::@return +output::@return: scope:[output] from output + [8] return + to:@return diff --git a/src/test/ref/inline-string-4.log b/src/test/ref/inline-string-4.log new file mode 100644 index 000000000..c0a80ab56 --- /dev/null +++ b/src/test/ref/inline-string-4.log @@ -0,0 +1,351 @@ + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 +main: scope:[main] from @2 + (byte[]) main::msg#0 ← (const string) main::$2 + (dword~) main::$0 ← ((dword)) (byte[]) main::msg#0 + (dword) main::dw#0 ← (dword~) main::$0 + (dword) output::dw#0 ← (dword) main::dw#0 + call output + to:main::@1 +main::@1: scope:[main] from main + to:main::@return +main::@return: scope:[main] from main::@1 + return + to:@return +@1: scope:[] from @begin + (dword*) screen#0 ← ((dword*)) (number) $400 + to:@2 +output: scope:[output] from main + (dword) output::dw#1 ← phi( main/(dword) output::dw#0 ) + *((dword*) screen#0) ← (dword) output::dw#1 + to:output::@return +output::@return: scope:[output] from output + return + to:@return +@2: scope:[] from @1 + call main + to:@3 +@3: scope:[] from @2 + to:@end +@end: scope:[] from @3 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @3 +(label) @begin +(label) @end +(void()) main() +(dword~) main::$0 +(const string) main::$2 = (string) "camelot" +(label) main::@1 +(label) main::@return +(dword) main::dw +(dword) main::dw#0 +(byte[]) main::msg +(byte[]) main::msg#0 +(void()) output((dword) output::dw) +(label) output::@return +(dword) output::dw +(dword) output::dw#0 +(dword) output::dw#1 +(dword*) screen +(dword*) screen#0 + +Inlining cast (dword~) main::$0 ← (dword)(byte[]) main::msg#0 +Inlining cast (dword*) screen#0 ← (dword*)(number) $400 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (dword*) 1024 +Successful SSA optimization PassNCastSimplification +Alias (dword) main::dw#0 = (dword~) main::$0 +Successful SSA optimization Pass2AliasElimination +Identical Phi Values (dword) output::dw#1 (dword) output::dw#0 +Successful SSA optimization Pass2IdenticalPhiElimination +Constant (const byte[]) main::msg#0 = main::$2 +Constant (const dword*) screen#0 = (dword*) 1024 +Successful SSA optimization Pass2ConstantIdentification +Constant value identified (dword)main::msg#0 in [1] (dword) main::dw#0 ← (dword)(const byte[]) main::msg#0 +Successful SSA optimization Pass2ConstantValues +Constant (const dword) main::dw#0 = (dword)main::msg#0 +Successful SSA optimization Pass2ConstantIdentification +Constant (const dword) output::dw#0 = main::dw#0 +Successful SSA optimization Pass2ConstantIdentification +Constant inlined main::$2 = (const byte[]) main::msg#0 +Constant inlined output::dw#0 = (const dword) main::dw#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 @3 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +Adding NOP phi() at start of main::@1 +CALL GRAPH +Calls in [] to main:3 +Calls in [main] to output:7 + +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +Culled Empty Block (label) @1 +Culled Empty Block (label) @3 +Culled Empty Block (label) main::@1 +Renumbering block @2 to @1 +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() + [5] call output + to:main::@return +main::@return: scope:[main] from main + [6] return + to:@return +output: scope:[output] from main + [7] *((const dword*) screen#0) ← (const dword) main::dw#0 + to:output::@return +output::@return: scope:[output] from output + [8] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(dword) main::dw +(byte[]) main::msg +(void()) output((dword) output::dw) +(dword) output::dw +(dword*) screen + +Initial phi equivalence classes +Complete equivalence classes + +INITIAL ASM +Target platform is c64basic / MOS6502X + // File Comments +// Test casting the address of an inline string to a dword. + // Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" + // Global Constants & labels + .label screen = $400 + // @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 dw = msg + // [5] call output + jsr output + jmp breturn + // main::@return + breturn: + // [6] return + rts + msg: .text "camelot" + .byte 0 +} + // output +output: { + // [7] *((const dword*) screen#0) ← (const dword) main::dw#0 -- _deref_pduc1=vduc2 + lda #main.dw + sta screen+1 + lda #>$10 + sta screen+2 + lda #>main.dw>>$10 + sta screen+3 + jmp breturn + // output::@return + breturn: + // [8] return + rts +} + // File Data + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [7] *((const dword*) screen#0) ← (const dword) main::dw#0 [ ] ( main:2::output:5 [ ] ) always clobbers reg byte a + +REGISTER UPLIFT SCOPES +Uplift Scope [main] +Uplift Scope [output] +Uplift Scope [] + +Uplifting [main] best 60 combination +Uplifting [output] best 60 combination +Uplifting [] best 60 combination + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Test casting the address of an inline string to a dword. + // Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" + // Global Constants & labels + .label screen = $400 + // @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 dw = msg + // [5] call output + jsr output + jmp breturn + // main::@return + breturn: + // [6] return + rts + msg: .text "camelot" + .byte 0 +} + // output +output: { + // [7] *((const dword*) screen#0) ← (const dword) main::dw#0 -- _deref_pduc1=vduc2 + lda #main.dw + sta screen+1 + lda #>$10 + sta screen+2 + lda #>main.dw>>$10 + sta screen+3 + jmp breturn + // output::@return + breturn: + // [8] return + rts +} + // File Data + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp breturn +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction main_from_b1: +Removing instruction bend_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction breturn: +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::dw +(const dword) main::dw#0 dw = (dword)(const byte[]) main::msg#0 +(byte[]) main::msg +(const byte[]) main::msg#0 msg = (string) "camelot" +(void()) output((dword) output::dw) +(label) output::@return +(dword) output::dw +(dword*) screen +(const dword*) screen#0 screen = (dword*) 1024 + + + +FINAL ASSEMBLER +Score: 42 + + // File Comments +// Test casting the address of an inline string to a dword. + // Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + // Global Constants & labels + .label screen = $400 + // @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 dw = msg + // output(dw) + // [5] call output + jsr output + // main::@return + // } + // [6] return + rts + msg: .text "camelot" + .byte 0 +} + // output +output: { + // *screen = dw + // [7] *((const dword*) screen#0) ← (const dword) main::dw#0 -- _deref_pduc1=vduc2 + lda #main.dw + sta screen+1 + lda #>$10 + sta screen+2 + lda #>main.dw>>$10 + sta screen+3 + // output::@return + // } + // [8] return + rts +} + // File Data + diff --git a/src/test/ref/inline-string-4.sym b/src/test/ref/inline-string-4.sym new file mode 100644 index 000000000..95473cf6c --- /dev/null +++ b/src/test/ref/inline-string-4.sym @@ -0,0 +1,15 @@ +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@return +(dword) main::dw +(const dword) main::dw#0 dw = (dword)(const byte[]) main::msg#0 +(byte[]) main::msg +(const byte[]) main::msg#0 msg = (string) "camelot" +(void()) output((dword) output::dw) +(label) output::@return +(dword) output::dw +(dword*) screen +(const dword*) screen#0 screen = (dword*) 1024 +