From a1fc0ace62dcbe0f534ba6bc5aed3c9f6d71d817 Mon Sep 17 00:00:00 2001 From: Jesper Gravgaard Date: Tue, 27 Aug 2019 14:31:30 +0200 Subject: [PATCH] Added test showing inline ASM preserving called functions. #294 --- .../pbuc1_neq__deref_pptz1_then_la1.asm | 8 + .../dk/camelot64/kickc/test/TestPrograms.java | 13 + src/test/kc/asm-uses-0.kc | 14 + src/test/kc/literal-string-array.kc | 22 ++ src/test/ref/asm-uses-0.asm | 15 + src/test/ref/asm-uses-0.cfg | 21 ++ src/test/ref/asm-uses-0.log | 283 ++++++++++++++++++ src/test/ref/asm-uses-0.sym | 10 + 8 files changed, 386 insertions(+) create mode 100644 src/main/fragment/pbuc1_neq__deref_pptz1_then_la1.asm create mode 100644 src/test/kc/asm-uses-0.kc create mode 100644 src/test/kc/literal-string-array.kc create mode 100644 src/test/ref/asm-uses-0.asm create mode 100644 src/test/ref/asm-uses-0.cfg create mode 100644 src/test/ref/asm-uses-0.log create mode 100644 src/test/ref/asm-uses-0.sym diff --git a/src/main/fragment/pbuc1_neq__deref_pptz1_then_la1.asm b/src/main/fragment/pbuc1_neq__deref_pptz1_then_la1.asm new file mode 100644 index 000000000..9bbd7eb78 --- /dev/null +++ b/src/main/fragment/pbuc1_neq__deref_pptz1_then_la1.asm @@ -0,0 +1,8 @@ +ldy #0 +lda #<{c1} +cmp ({z1}),y +bne {la1} +iny +lda #>{c1} +cmp ({z1}),y +bne {la1} diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 5fb00cc78..7ad608973 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -41,6 +41,11 @@ public class TestPrograms { compileAndCompare("kickasm-uses-prevent-deletion"); } + @Test + public void testAsmUses0() throws IOException, URISyntaxException { + compileAndCompare("asm-uses-0"); + } + // TODO: Fix inline kickasm uses handling of used variables. https://gitlab.com/camelot/kickc/issues/296 /* @Test @@ -1365,6 +1370,14 @@ public class TestPrograms { compileAndCompare("pointer-cast"); } + // TODO: Fix literal string array initialization. https://gitlab.com/camelot/kickc/issues/297 + /* + @Test + public void testLiteralStringArray() throws IOException, URISyntaxException { + compileAndCompare("literal-string-array"); + } + */ + @Test public void testLiteralStrings() throws IOException, URISyntaxException { compileAndCompare("literal-strings"); diff --git a/src/test/kc/asm-uses-0.kc b/src/test/kc/asm-uses-0.kc new file mode 100644 index 000000000..f99f994aa --- /dev/null +++ b/src/test/kc/asm-uses-0.kc @@ -0,0 +1,14 @@ +// Tests that inline asm uses clause makes the compiler not cull a procedure referenced + +void main() { + asm { + jsr init + } +} + +const char* BGCOL = 0xd020; + +// Function only used inside the inline asm +void init() { + *BGCOL = 0; +} diff --git a/src/test/kc/literal-string-array.kc b/src/test/kc/literal-string-array.kc new file mode 100644 index 000000000..2595c9456 --- /dev/null +++ b/src/test/kc/literal-string-array.kc @@ -0,0 +1,22 @@ +// Tests literal string array + +const char* SCREEN = 0x0400; +const void* NUL = (void*)0; + +// Works +// char*[] msgs = { (char*)"hello", (char*)"cruel", (char*)"world", (char*)NUL }; +// Not working +char*[] msgs = { "hello", "cruel", "world", NUL }; + +void main() { + char i=0; + char** msg = msgs; + while(*msg) { + char* c = *msg; + while(*c) { + SCREEN[i++] = *c++; + } + msg++; + } +} + diff --git a/src/test/ref/asm-uses-0.asm b/src/test/ref/asm-uses-0.asm new file mode 100644 index 000000000..c8b3ad70e --- /dev/null +++ b/src/test/ref/asm-uses-0.asm @@ -0,0 +1,15 @@ +// Tests that inline asm uses clause makes the compiler not cull a procedure referenced +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .label BGCOL = $d020 +main: { + jsr init + rts +} +// Function only used inside the inline asm +init: { + lda #0 + sta BGCOL + rts +} diff --git a/src/test/ref/asm-uses-0.cfg b/src/test/ref/asm-uses-0.cfg new file mode 100644 index 000000000..da4979c60 --- /dev/null +++ b/src/test/ref/asm-uses-0.cfg @@ -0,0 +1,21 @@ +@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 + asm { jsrinit } + to:main::@return +main::@return: scope:[main] from main + [5] return + to:@return +init: scope:[init] from + [6] *((const byte*) BGCOL#0) ← (byte) 0 + to:init::@return +init::@return: scope:[init] from init + [7] return + to:@return diff --git a/src/test/ref/asm-uses-0.log b/src/test/ref/asm-uses-0.log new file mode 100644 index 000000000..7fe1e5887 --- /dev/null +++ b/src/test/ref/asm-uses-0.log @@ -0,0 +1,283 @@ +Resolved forward reference init to (void()) init() + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 +main: scope:[main] from @2 + asm { jsrinit } + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + (byte*) BGCOL#0 ← ((byte*)) (number) $d020 + to:@2 +init: scope:[init] from + *((byte*) BGCOL#0) ← (number) 0 + to:init::@return +init::@return: scope:[init] from init + 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 +(byte*) BGCOL +(byte*) BGCOL#0 +(void()) init() +(label) init::@return +(void()) main() +(label) main::@return + +Adding number conversion cast (unumber) 0 in *((byte*) BGCOL#0) ← (number) 0 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (byte*) BGCOL#0 ← (byte*)(number) $d020 +Inlining cast *((byte*) BGCOL#0) ← (unumber)(number) 0 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (byte*) 53280 +Simplifying constant integer cast 0 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 0 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Constant (const byte*) BGCOL#0 = (byte*) 53280 +Successful SSA optimization Pass2ConstantIdentification +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 +CALL GRAPH +Calls in [] to main:3 + +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +Culled Empty Block (label) @1 +Culled Empty Block (label) @3 +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 + +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 + asm { jsrinit } + to:main::@return +main::@return: scope:[main] from main + [5] return + to:@return +init: scope:[init] from + [6] *((const byte*) BGCOL#0) ← (byte) 0 + to:init::@return +init::@return: scope:[init] from init + [7] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(byte*) BGCOL +(void()) init() +(void()) main() + +Initial phi equivalence classes +Complete equivalence classes + +INITIAL ASM +Target platform is c64basic + // File Comments +// Tests that inline asm uses clause makes the compiler not cull a procedure referenced + // Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" + // Global Constants & labels + .label BGCOL = $d020 + // @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: { + // asm { jsrinit } + jsr init + jmp breturn + // main::@return + breturn: + // [5] return + rts +} + // init +// Function only used inside the inline asm +init: { + // [6] *((const byte*) BGCOL#0) ← (byte) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta BGCOL + jmp breturn + // init::@return + breturn: + // [7] return + rts +} + // File Data + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement asm { jsrinit } always clobbers reg byte a reg byte x reg byte y +Statement [6] *((const byte*) BGCOL#0) ← (byte) 0 [ ] ( [ ] ) always clobbers reg byte a + +REGISTER UPLIFT SCOPES +Uplift Scope [main] +Uplift Scope [init] +Uplift Scope [] + +Uplifting [main] best 42 combination +Uplifting [init] best 42 combination +Uplifting [] best 42 combination + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Tests that inline asm uses clause makes the compiler not cull a procedure referenced + // Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" + // Global Constants & labels + .label BGCOL = $d020 + // @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: { + // asm { jsrinit } + jsr init + jmp breturn + // main::@return + breturn: + // [5] return + rts +} + // init +// Function only used inside the inline asm +init: { + // [6] *((const byte*) BGCOL#0) ← (byte) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta BGCOL + jmp breturn + // init::@return + breturn: + // [7] 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 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 +(byte*) BGCOL +(const byte*) BGCOL#0 BGCOL = (byte*) 53280 +(void()) init() +(label) init::@return +(void()) main() +(label) main::@return + + + +FINAL ASSEMBLER +Score: 24 + + // File Comments +// Tests that inline asm uses clause makes the compiler not cull a procedure referenced + // Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + // Global Constants & labels + .label BGCOL = $d020 + // @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: { + // asm + // asm { jsrinit } + jsr init + // main::@return + // } + // [5] return + rts +} + // init +// Function only used inside the inline asm +init: { + // *BGCOL = 0 + // [6] *((const byte*) BGCOL#0) ← (byte) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta BGCOL + // init::@return + // } + // [7] return + rts +} + // File Data + diff --git a/src/test/ref/asm-uses-0.sym b/src/test/ref/asm-uses-0.sym new file mode 100644 index 000000000..10988c9d0 --- /dev/null +++ b/src/test/ref/asm-uses-0.sym @@ -0,0 +1,10 @@ +(label) @1 +(label) @begin +(label) @end +(byte*) BGCOL +(const byte*) BGCOL#0 BGCOL = (byte*) 53280 +(void()) init() +(label) init::@return +(void()) main() +(label) main::@return +