diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 8503fb2d4..0569033fe 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -80,12 +80,10 @@ public class TestPrograms { assertError("pointer-void-err-0", "Void pointer math not allowed."); } - /* @Test public void testPointerVoid3() throws IOException, URISyntaxException { compileAndCompare("pointer-void-3"); } - */ @Test public void testPointerVoid2() throws IOException, URISyntaxException { @@ -749,6 +747,11 @@ public class TestPrograms { compileAndCompare("word-pointer-math"); } + @Test + public void testWordPointerMath1() throws IOException, URISyntaxException { + compileAndCompare("word-pointer-math-1"); + } + @Test public void testWordPointerMath0() throws IOException, URISyntaxException { compileAndCompare("word-pointer-math-0"); diff --git a/src/test/kc/pointer-void-3.kc b/src/test/kc/pointer-void-3.kc index 795f9c2b3..5f372ef25 100644 --- a/src/test/kc/pointer-void-3.kc +++ b/src/test/kc/pointer-void-3.kc @@ -1,24 +1,21 @@ // Test void pointer - issues when assigning returns from malloc() -void main() { - byte* buf1 = malloc(64); - byte* buf2 = malloc(64); +const byte* SCREEN = 0x0400; + +void main() { + byte* buf1 = malloc(); + byte* buf2 = malloc(); *buf1 = 'a'; *buf2 = 'b'; - - const byte* SCREEN = 0x0400; SCREEN[0] = *buf1; SCREEN[1] = *buf2; - } -unsigned char* HEAP_START = 0xc000; -unsigned char* heap_head = HEAP_START; +byte* heap_head = 0xc000; -void* malloc(unsigned int size) { - void* mem = heap_head; - heap_head+= size; - return mem; +void* malloc() { + heap_head++; + return heap_head; } diff --git a/src/test/kc/word-pointer-math-1.kc b/src/test/kc/word-pointer-math-1.kc new file mode 100644 index 000000000..6a267987d --- /dev/null +++ b/src/test/kc/word-pointer-math-1.kc @@ -0,0 +1,8 @@ +// Tests word pointer math - subtracting two word pointers +void main() { + word* w1 = 0x1000; + word* w2 = 0x1140; + word wd = w2 - w1; + const word* SCREEN = 0x0400; + *SCREEN = wd; +} diff --git a/src/test/ref/pointer-void-3.asm b/src/test/ref/pointer-void-3.asm new file mode 100644 index 000000000..1473248ac --- /dev/null +++ b/src/test/ref/pointer-void-3.asm @@ -0,0 +1,31 @@ +// Test void pointer - issues when assigning returns from malloc() +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .label SCREEN = $400 + .label heap_head = 2 +main: { + lda #<$c000 + sta heap_head + lda #>$c000 + sta heap_head+1 + jsr malloc + jsr malloc + lda #'a' + ldy #0 + sta (heap_head),y + lda #'b' + sta (heap_head),y + lda (heap_head),y + sta SCREEN + lda (heap_head),y + sta SCREEN+1 + rts +} +malloc: { + inc heap_head + bne !+ + inc heap_head+1 + !: + rts +} diff --git a/src/test/ref/pointer-void-3.cfg b/src/test/ref/pointer-void-3.cfg new file mode 100644 index 000000000..4540f68eb --- /dev/null +++ b/src/test/ref/pointer-void-3.cfg @@ -0,0 +1,33 @@ +@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 malloc + to:main::@1 +main::@1: scope:[main] from main + [6] phi() + [7] call malloc + to:main::@2 +main::@2: scope:[main] from main::@1 + [8] *((byte*)(void*)(byte*) heap_head#11) ← (byte) 'a' + [9] *((byte*)(void*)(byte*) heap_head#11) ← (byte) 'b' + [10] *((const byte*) SCREEN#0) ← *((byte*)(void*)(byte*) heap_head#11) + [11] *((const byte*) SCREEN#0+(byte) 1) ← *((byte*)(void*)(byte*) heap_head#11) + to:main::@return +main::@return: scope:[main] from main::@2 + [12] return + to:@return +malloc: scope:[malloc] from main main::@1 + [13] (byte*) heap_head#10 ← phi( main/(byte*) 49152 main::@1/(byte*) heap_head#11 ) + [14] (byte*) heap_head#11 ← ++ (byte*) heap_head#10 + to:malloc::@return +malloc::@return: scope:[malloc] from malloc + [15] return + to:@return diff --git a/src/test/ref/pointer-void-3.log b/src/test/ref/pointer-void-3.log new file mode 100644 index 000000000..b62114c84 --- /dev/null +++ b/src/test/ref/pointer-void-3.log @@ -0,0 +1,551 @@ +Adding pointer type conversion cast (byte*) SCREEN in (byte*) SCREEN ← (number) $400 +Adding pointer type conversion cast to void pointer (byte*) main::$0 in (byte*) main::buf1 ← (void*~) main::$0 +Adding pointer type conversion cast to void pointer (byte*) main::$1 in (byte*) main::buf2 ← (void*~) main::$1 +Adding pointer type conversion cast (byte*) heap_head in (byte*) heap_head ← (number) $c000 +Adding void pointer type conversion cast (void*) heap_head in (void*) malloc::return ← (byte*) heap_head +Culled Empty Block (label) malloc::@1 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (byte*) SCREEN#0 ← ((byte*)) (number) $400 + to:@1 +main: scope:[main] from @2 + (byte*) heap_head#13 ← phi( @2/(byte*) heap_head#14 ) + call malloc + (void*) malloc::return#0 ← (void*) malloc::return#3 + to:main::@1 +main::@1: scope:[main] from main + (byte*) heap_head#7 ← phi( main/(byte*) heap_head#5 ) + (void*) malloc::return#4 ← phi( main/(void*) malloc::return#0 ) + (void*~) main::$0 ← (void*) malloc::return#4 + (byte*) heap_head#0 ← (byte*) heap_head#7 + (byte*) main::buf1#0 ← ((byte*)) (void*~) main::$0 + call malloc + (void*) malloc::return#1 ← (void*) malloc::return#3 + to:main::@2 +main::@2: scope:[main] from main::@1 + (byte*) main::buf1#1 ← phi( main::@1/(byte*) main::buf1#0 ) + (byte*) heap_head#8 ← phi( main::@1/(byte*) heap_head#5 ) + (void*) malloc::return#5 ← phi( main::@1/(void*) malloc::return#1 ) + (void*~) main::$1 ← (void*) malloc::return#5 + (byte*) heap_head#1 ← (byte*) heap_head#8 + (byte*) main::buf2#0 ← ((byte*)) (void*~) main::$1 + *((byte*) main::buf1#1) ← (byte) 'a' + *((byte*) main::buf2#0) ← (byte) 'b' + *((byte*) SCREEN#0 + (number) 0) ← *((byte*) main::buf1#1) + *((byte*) SCREEN#0 + (number) 1) ← *((byte*) main::buf2#0) + to:main::@return +main::@return: scope:[main] from main::@2 + (byte*) heap_head#9 ← phi( main::@2/(byte*) heap_head#1 ) + (byte*) heap_head#2 ← (byte*) heap_head#9 + return + to:@return +@1: scope:[] from @begin + (byte*) heap_head#3 ← ((byte*)) (number) $c000 + to:@2 +malloc: scope:[malloc] from main main::@1 + (byte*) heap_head#10 ← phi( main/(byte*) heap_head#13 main::@1/(byte*) heap_head#0 ) + (byte*) heap_head#4 ← ++ (byte*) heap_head#10 + (void*) malloc::return#2 ← ((void*)) (byte*) heap_head#4 + to:malloc::@return +malloc::@return: scope:[malloc] from malloc + (byte*) heap_head#11 ← phi( malloc/(byte*) heap_head#4 ) + (void*) malloc::return#6 ← phi( malloc/(void*) malloc::return#2 ) + (void*) malloc::return#3 ← (void*) malloc::return#6 + (byte*) heap_head#5 ← (byte*) heap_head#11 + return + to:@return +@2: scope:[] from @1 + (byte*) heap_head#14 ← phi( @1/(byte*) heap_head#3 ) + call main + to:@3 +@3: scope:[] from @2 + (byte*) heap_head#12 ← phi( @2/(byte*) heap_head#2 ) + (byte*) heap_head#6 ← (byte*) heap_head#12 + to:@end +@end: scope:[] from @3 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @3 +(label) @begin +(label) @end +(byte*) SCREEN +(byte*) SCREEN#0 +(byte*) heap_head +(byte*) heap_head#0 +(byte*) heap_head#1 +(byte*) heap_head#10 +(byte*) heap_head#11 +(byte*) heap_head#12 +(byte*) heap_head#13 +(byte*) heap_head#14 +(byte*) heap_head#2 +(byte*) heap_head#3 +(byte*) heap_head#4 +(byte*) heap_head#5 +(byte*) heap_head#6 +(byte*) heap_head#7 +(byte*) heap_head#8 +(byte*) heap_head#9 +(void()) main() +(void*~) main::$0 +(void*~) main::$1 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte*) main::buf1 +(byte*) main::buf1#0 +(byte*) main::buf1#1 +(byte*) main::buf2 +(byte*) main::buf2#0 +(void*()) malloc() +(label) malloc::@return +(void*) malloc::return +(void*) malloc::return#0 +(void*) malloc::return#1 +(void*) malloc::return#2 +(void*) malloc::return#3 +(void*) malloc::return#4 +(void*) malloc::return#5 +(void*) malloc::return#6 + +Adding number conversion cast (unumber) 0 in *((byte*) SCREEN#0 + (number) 0) ← *((byte*) main::buf1#1) +Adding number conversion cast (unumber) 1 in *((byte*) SCREEN#0 + (number) 1) ← *((byte*) main::buf2#0) +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400 +Inlining cast (byte*) main::buf1#0 ← (byte*)(void*~) main::$0 +Inlining cast (byte*) main::buf2#0 ← (byte*)(void*~) main::$1 +Inlining cast (byte*) heap_head#3 ← (byte*)(number) $c000 +Inlining cast (void*) malloc::return#2 ← (void*)(byte*) heap_head#4 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast 0 +Simplifying constant integer cast 1 +Simplifying constant pointer cast (byte*) 49152 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 1 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias (void*) malloc::return#0 = (void*) malloc::return#4 +Alias (byte*) heap_head#0 = (byte*) heap_head#7 +Alias (void*) malloc::return#1 = (void*) malloc::return#5 +Alias (byte*) main::buf1#0 = (byte*) main::buf1#1 +Alias (byte*) heap_head#1 = (byte*) heap_head#8 (byte*) heap_head#9 (byte*) heap_head#2 +Alias (void*) malloc::return#2 = (void*) malloc::return#6 (void*) malloc::return#3 +Alias (byte*) heap_head#11 = (byte*) heap_head#4 (byte*) heap_head#5 +Alias (byte*) heap_head#14 = (byte*) heap_head#3 +Alias (byte*) heap_head#12 = (byte*) heap_head#6 +Successful SSA optimization Pass2AliasElimination +Identical Phi Values (byte*) heap_head#13 (byte*) heap_head#14 +Identical Phi Values (byte*) heap_head#0 (byte*) heap_head#11 +Identical Phi Values (byte*) heap_head#1 (byte*) heap_head#11 +Identical Phi Values (byte*) heap_head#12 (byte*) heap_head#1 +Successful SSA optimization Pass2IdenticalPhiElimination +Constant (const byte*) SCREEN#0 = (byte*) 1024 +Constant (const byte*) heap_head#14 = (byte*) 49152 +Successful SSA optimization Pass2ConstantIdentification +Simplifying expression containing zero SCREEN#0 in [16] *((const byte*) SCREEN#0 + (byte) 0) ← *((byte*) main::buf1#0) +Successful SSA optimization PassNSimplifyExpressionWithZero +Inlining Noop Cast [3] (byte*) main::buf1#0 ← (byte*)(void*~) main::$0 keeping main::buf1#0 +Inlining Noop Cast [7] (byte*) main::buf2#0 ← (byte*)(void*~) main::$1 keeping main::buf2#0 +Successful SSA optimization Pass2NopCastInlining +Inlining Noop Cast [15] (void*) malloc::return#2 ← (void*)(byte*) heap_head#11 keeping heap_head#11 +Successful SSA optimization Pass2NopCastInlining +Inlining Noop Cast [1] (void*) malloc::return#0 ← (void*)(byte*) heap_head#11 keeping heap_head#11 +Inlining Noop Cast [5] (void*) malloc::return#1 ← (void*)(byte*) heap_head#11 keeping heap_head#11 +Successful SSA optimization Pass2NopCastInlining +Inlining Noop Cast [2] (void*) main::buf1#0 ← (void*)(byte*) heap_head#11 keeping heap_head#11 +Inlining Noop Cast [6] (void*) main::buf2#0 ← (void*)(byte*) heap_head#11 keeping heap_head#11 +Successful SSA optimization Pass2NopCastInlining +Inlining constant with var siblings (const byte*) heap_head#14 +Constant inlined heap_head#14 = (byte*) 49152 +Successful SSA optimization Pass2ConstantInlining +Consolidated array index constant in *(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 @3 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +CALL GRAPH +Calls in [] to main:3 +Calls in [main] to malloc:7 malloc:9 + +Created 1 initial phi equivalence classes +Coalesced [8] heap_head#15 ← heap_head#11 +Coalesced down to 1 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 +Adding NOP phi() at start of main +Adding NOP phi() at start of main::@1 + +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 malloc + to:main::@1 +main::@1: scope:[main] from main + [6] phi() + [7] call malloc + to:main::@2 +main::@2: scope:[main] from main::@1 + [8] *((byte*)(void*)(byte*) heap_head#11) ← (byte) 'a' + [9] *((byte*)(void*)(byte*) heap_head#11) ← (byte) 'b' + [10] *((const byte*) SCREEN#0) ← *((byte*)(void*)(byte*) heap_head#11) + [11] *((const byte*) SCREEN#0+(byte) 1) ← *((byte*)(void*)(byte*) heap_head#11) + to:main::@return +main::@return: scope:[main] from main::@2 + [12] return + to:@return +malloc: scope:[malloc] from main main::@1 + [13] (byte*) heap_head#10 ← phi( main/(byte*) 49152 main::@1/(byte*) heap_head#11 ) + [14] (byte*) heap_head#11 ← ++ (byte*) heap_head#10 + to:malloc::@return +malloc::@return: scope:[malloc] from malloc + [15] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(byte*) SCREEN +(byte*) heap_head +(byte*) heap_head#10 4.0 +(byte*) heap_head#11 0.5 +(void()) main() +(byte*) main::buf1 +(byte*) main::buf2 +(void*()) malloc() +(void*) malloc::return + +Initial phi equivalence classes +[ heap_head#10 heap_head#11 ] +Complete equivalence classes +[ heap_head#10 heap_head#11 ] +Allocated zp ZP_WORD:2 [ heap_head#10 heap_head#11 ] + +INITIAL ASM +//SEG0 File Comments +// Test void pointer - issues when assigning returns from malloc() +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .label SCREEN = $400 + .label heap_head = 2 +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main +//SEG7 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG9 @end +bend: +//SEG10 main +main: { + //SEG11 [5] call malloc + //SEG12 [13] phi from main to malloc [phi:main->malloc] + malloc_from_main: + //SEG13 [13] phi (byte*) heap_head#10 = (byte*) 49152 [phi:main->malloc#0] -- pbuz1=pbuc1 + lda #<$c000 + sta heap_head + lda #>$c000 + sta heap_head+1 + jsr malloc + //SEG14 [6] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + jmp b1 + //SEG15 main::@1 + b1: + //SEG16 [7] call malloc + //SEG17 [13] phi from main::@1 to malloc [phi:main::@1->malloc] + malloc_from_b1: + //SEG18 [13] phi (byte*) heap_head#10 = (byte*) heap_head#11 [phi:main::@1->malloc#0] -- register_copy + jsr malloc + jmp b2 + //SEG19 main::@2 + b2: + //SEG20 [8] *((byte*)(void*)(byte*) heap_head#11) ← (byte) 'a' -- _deref_pbuz1=vbuc1 + lda #'a' + ldy #0 + sta (heap_head),y + //SEG21 [9] *((byte*)(void*)(byte*) heap_head#11) ← (byte) 'b' -- _deref_pbuz1=vbuc1 + lda #'b' + ldy #0 + sta (heap_head),y + //SEG22 [10] *((const byte*) SCREEN#0) ← *((byte*)(void*)(byte*) heap_head#11) -- _deref_pbuc1=_deref_pbuz1 + ldy #0 + lda (heap_head),y + sta SCREEN + //SEG23 [11] *((const byte*) SCREEN#0+(byte) 1) ← *((byte*)(void*)(byte*) heap_head#11) -- _deref_pbuc1=_deref_pbuz1 + ldy #0 + lda (heap_head),y + sta SCREEN+1 + jmp breturn + //SEG24 main::@return + breturn: + //SEG25 [12] return + rts +} +//SEG26 malloc +malloc: { + //SEG27 [14] (byte*) heap_head#11 ← ++ (byte*) heap_head#10 -- pbuz1=_inc_pbuz1 + inc heap_head + bne !+ + inc heap_head+1 + !: + jmp breturn + //SEG28 malloc::@return + breturn: + //SEG29 [15] return + rts +} +//SEG30 File Data + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [8] *((byte*)(void*)(byte*) heap_head#11) ← (byte) 'a' [ heap_head#11 ] ( main:2 [ heap_head#11 ] ) always clobbers reg byte a reg byte y +Statement [9] *((byte*)(void*)(byte*) heap_head#11) ← (byte) 'b' [ heap_head#11 ] ( main:2 [ heap_head#11 ] ) always clobbers reg byte a reg byte y +Statement [10] *((const byte*) SCREEN#0) ← *((byte*)(void*)(byte*) heap_head#11) [ heap_head#11 ] ( main:2 [ heap_head#11 ] ) always clobbers reg byte a reg byte y +Statement [11] *((const byte*) SCREEN#0+(byte) 1) ← *((byte*)(void*)(byte*) heap_head#11) [ ] ( main:2 [ ] ) always clobbers reg byte a reg byte y +Potential registers zp ZP_WORD:2 [ heap_head#10 heap_head#11 ] : zp ZP_WORD:2 , + +REGISTER UPLIFT SCOPES +Uplift Scope [] 4.5: zp ZP_WORD:2 [ heap_head#10 heap_head#11 ] +Uplift Scope [main] +Uplift Scope [malloc] + +Uplifting [] best 112 combination zp ZP_WORD:2 [ heap_head#10 heap_head#11 ] +Uplifting [main] best 112 combination +Uplifting [malloc] best 112 combination + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +// Test void pointer - issues when assigning returns from malloc() +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .label SCREEN = $400 + .label heap_head = 2 +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main +//SEG7 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG9 @end +bend: +//SEG10 main +main: { + //SEG11 [5] call malloc + //SEG12 [13] phi from main to malloc [phi:main->malloc] + malloc_from_main: + //SEG13 [13] phi (byte*) heap_head#10 = (byte*) 49152 [phi:main->malloc#0] -- pbuz1=pbuc1 + lda #<$c000 + sta heap_head + lda #>$c000 + sta heap_head+1 + jsr malloc + //SEG14 [6] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + jmp b1 + //SEG15 main::@1 + b1: + //SEG16 [7] call malloc + //SEG17 [13] phi from main::@1 to malloc [phi:main::@1->malloc] + malloc_from_b1: + //SEG18 [13] phi (byte*) heap_head#10 = (byte*) heap_head#11 [phi:main::@1->malloc#0] -- register_copy + jsr malloc + jmp b2 + //SEG19 main::@2 + b2: + //SEG20 [8] *((byte*)(void*)(byte*) heap_head#11) ← (byte) 'a' -- _deref_pbuz1=vbuc1 + lda #'a' + ldy #0 + sta (heap_head),y + //SEG21 [9] *((byte*)(void*)(byte*) heap_head#11) ← (byte) 'b' -- _deref_pbuz1=vbuc1 + lda #'b' + ldy #0 + sta (heap_head),y + //SEG22 [10] *((const byte*) SCREEN#0) ← *((byte*)(void*)(byte*) heap_head#11) -- _deref_pbuc1=_deref_pbuz1 + ldy #0 + lda (heap_head),y + sta SCREEN + //SEG23 [11] *((const byte*) SCREEN#0+(byte) 1) ← *((byte*)(void*)(byte*) heap_head#11) -- _deref_pbuc1=_deref_pbuz1 + ldy #0 + lda (heap_head),y + sta SCREEN+1 + jmp breturn + //SEG24 main::@return + breturn: + //SEG25 [12] return + rts +} +//SEG26 malloc +malloc: { + //SEG27 [14] (byte*) heap_head#11 ← ++ (byte*) heap_head#10 -- pbuz1=_inc_pbuz1 + inc heap_head + bne !+ + inc heap_head+1 + !: + jmp breturn + //SEG28 malloc::@return + breturn: + //SEG29 [15] return + rts +} +//SEG30 File Data + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp b1 +Removing instruction jmp b2 +Removing instruction jmp breturn +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction ldy #0 +Removing instruction ldy #0 +Removing instruction ldy #0 +Succesful ASM optimization Pass5UnnecesaryLoadElimination +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction main_from_b1: +Removing instruction bend_from_b1: +Removing instruction b1_from_main: +Removing instruction malloc_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction malloc_from_main: +Removing instruction b1: +Removing instruction b2: +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*) SCREEN +(const byte*) SCREEN#0 SCREEN = (byte*) 1024 +(byte*) heap_head +(byte*) heap_head#10 heap_head zp ZP_WORD:2 4.0 +(byte*) heap_head#11 heap_head zp ZP_WORD:2 0.5 +(void()) main() +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte*) main::buf1 +(byte*) main::buf2 +(void*()) malloc() +(label) malloc::@return +(void*) malloc::return + +zp ZP_WORD:2 [ heap_head#10 heap_head#11 ] + + +FINAL ASSEMBLER +Score: 82 + +//SEG0 File Comments +// Test void pointer - issues when assigning returns from malloc() +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .label SCREEN = $400 + .label heap_head = 2 +//SEG3 @begin +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG5 @1 +//SEG6 [2] call main +//SEG7 [4] phi from @1 to main [phi:@1->main] +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +//SEG9 @end +//SEG10 main +main: { + //SEG11 [5] call malloc + //SEG12 [13] phi from main to malloc [phi:main->malloc] + //SEG13 [13] phi (byte*) heap_head#10 = (byte*) 49152 [phi:main->malloc#0] -- pbuz1=pbuc1 + lda #<$c000 + sta heap_head + lda #>$c000 + sta heap_head+1 + jsr malloc + //SEG14 [6] phi from main to main::@1 [phi:main->main::@1] + //SEG15 main::@1 + //SEG16 [7] call malloc + //SEG17 [13] phi from main::@1 to malloc [phi:main::@1->malloc] + //SEG18 [13] phi (byte*) heap_head#10 = (byte*) heap_head#11 [phi:main::@1->malloc#0] -- register_copy + jsr malloc + //SEG19 main::@2 + //SEG20 [8] *((byte*)(void*)(byte*) heap_head#11) ← (byte) 'a' -- _deref_pbuz1=vbuc1 + lda #'a' + ldy #0 + sta (heap_head),y + //SEG21 [9] *((byte*)(void*)(byte*) heap_head#11) ← (byte) 'b' -- _deref_pbuz1=vbuc1 + lda #'b' + sta (heap_head),y + //SEG22 [10] *((const byte*) SCREEN#0) ← *((byte*)(void*)(byte*) heap_head#11) -- _deref_pbuc1=_deref_pbuz1 + lda (heap_head),y + sta SCREEN + //SEG23 [11] *((const byte*) SCREEN#0+(byte) 1) ← *((byte*)(void*)(byte*) heap_head#11) -- _deref_pbuc1=_deref_pbuz1 + lda (heap_head),y + sta SCREEN+1 + //SEG24 main::@return + //SEG25 [12] return + rts +} +//SEG26 malloc +malloc: { + //SEG27 [14] (byte*) heap_head#11 ← ++ (byte*) heap_head#10 -- pbuz1=_inc_pbuz1 + inc heap_head + bne !+ + inc heap_head+1 + !: + //SEG28 malloc::@return + //SEG29 [15] return + rts +} +//SEG30 File Data + diff --git a/src/test/ref/pointer-void-3.sym b/src/test/ref/pointer-void-3.sym new file mode 100644 index 000000000..c352d97c8 --- /dev/null +++ b/src/test/ref/pointer-void-3.sym @@ -0,0 +1,19 @@ +(label) @1 +(label) @begin +(label) @end +(byte*) SCREEN +(const byte*) SCREEN#0 SCREEN = (byte*) 1024 +(byte*) heap_head +(byte*) heap_head#10 heap_head zp ZP_WORD:2 4.0 +(byte*) heap_head#11 heap_head zp ZP_WORD:2 0.5 +(void()) main() +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte*) main::buf1 +(byte*) main::buf2 +(void*()) malloc() +(label) malloc::@return +(void*) malloc::return + +zp ZP_WORD:2 [ heap_head#10 heap_head#11 ] diff --git a/src/test/ref/word-pointer-math-1.asm b/src/test/ref/word-pointer-math-1.asm new file mode 100644 index 000000000..866464914 --- /dev/null +++ b/src/test/ref/word-pointer-math-1.asm @@ -0,0 +1,16 @@ +// Tests word pointer math - subtracting two word pointers +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .const SIZEOF_WORD = 2 +main: { + .label w1 = $1000 + .label w2 = $1140 + .label SCREEN = $400 + .const wd = w2-w1*SIZEOF_WORD + lda #wd + sta SCREEN+1 + rts +} diff --git a/src/test/ref/word-pointer-math-1.cfg b/src/test/ref/word-pointer-math-1.cfg new file mode 100644 index 000000000..85ffab70b --- /dev/null +++ b/src/test/ref/word-pointer-math-1.cfg @@ -0,0 +1,15 @@ +@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] *((const word*) main::SCREEN#0) ← (const word) main::wd#0 + to:main::@return +main::@return: scope:[main] from main + [5] return + to:@return diff --git a/src/test/ref/word-pointer-math-1.log b/src/test/ref/word-pointer-math-1.log new file mode 100644 index 000000000..7b8ceb2f5 --- /dev/null +++ b/src/test/ref/word-pointer-math-1.log @@ -0,0 +1,278 @@ +Adding pointer type conversion cast (word*) main::w1 in (word*) main::w1 ← (number) $1000 +Adding pointer type conversion cast (word*) main::w2 in (word*) main::w2 ← (number) $1140 +Adding pointer type conversion cast (word*) main::SCREEN in (word*) main::SCREEN ← (number) $400 +Fixing pointer addition (word~) main::$0 ← (word*) main::w2 - (word*) main::w1 +Identified constant variable (word*) main::w1 +Identified constant variable (word*) main::w2 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (word*) main::w1#0 ← ((word*)) (number) $1000 + (word*) main::w2#0 ← ((word*)) (number) $1140 + (word*~) main::$1 ← (word*) main::w1#0 * (const byte) SIZEOF_WORD + (word~) main::$0 ← (word*) main::w2#0 - (word*~) main::$1 + (word) main::wd#0 ← (word~) main::$0 + (word*) main::SCREEN#0 ← ((word*)) (number) $400 + *((word*) main::SCREEN#0) ← (word) main::wd#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) SIZEOF_WORD = (byte) 2 +(void()) main() +(word~) main::$0 +(word*~) main::$1 +(label) main::@return +(word*) main::SCREEN +(word*) main::SCREEN#0 +(word*) main::w1 +(word*) main::w1#0 +(word*) main::w2 +(word*) main::w2#0 +(word) main::wd +(word) main::wd#0 + +Inlining cast (word*) main::w1#0 ← (word*)(number) $1000 +Inlining cast (word*) main::w2#0 ← (word*)(number) $1140 +Inlining cast (word*) main::SCREEN#0 ← (word*)(number) $400 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (word*) 4096 +Simplifying constant pointer cast (word*) 4416 +Simplifying constant pointer cast (word*) 1024 +Successful SSA optimization PassNCastSimplification +Alias (word) main::wd#0 = (word~) main::$0 +Successful SSA optimization Pass2AliasElimination +Constant (const word*) main::w1#0 = (word*) 4096 +Constant (const word*) main::w2#0 = (word*) 4416 +Constant (const word*) main::SCREEN#0 = (word*) 1024 +Successful SSA optimization Pass2ConstantIdentification +Constant right-side identified [0] (word*~) main::$1 ← (const word*) main::w1#0 * (const byte) SIZEOF_WORD +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const word*) main::$1 = main::w1#0*SIZEOF_WORD +Successful SSA optimization Pass2ConstantIdentification +Constant right-side identified [0] (word) main::wd#0 ← (const word*) main::w2#0 - (const word*) main::$1 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const word) main::wd#0 = main::w2#0-main::$1 +Successful SSA optimization Pass2ConstantIdentification +Constant inlined main::$1 = (const word*) main::w1#0*(const byte) SIZEOF_WORD +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] *((const word*) main::SCREEN#0) ← (const word) main::wd#0 + to:main::@return +main::@return: scope:[main] from main + [5] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(word*) main::SCREEN +(word*) main::w1 +(word*) main::w2 +(word) main::wd + +Initial phi equivalence classes +Complete equivalence classes + +INITIAL ASM +//SEG0 File Comments +// Tests word pointer math - subtracting two word pointers +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const SIZEOF_WORD = 2 +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .label w1 = $1000 + .label w2 = $1140 + .label SCREEN = $400 + .const wd = w2-w1*SIZEOF_WORD + //SEG10 [4] *((const word*) main::SCREEN#0) ← (const word) main::wd#0 -- _deref_pwuc1=vwuc2 + lda #wd + sta SCREEN+1 + jmp breturn + //SEG11 main::@return + breturn: + //SEG12 [5] return + rts +} +//SEG13 File Data + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] *((const word*) main::SCREEN#0) ← (const word) main::wd#0 [ ] ( main:2 [ ] ) always clobbers reg byte a + +REGISTER UPLIFT SCOPES +Uplift Scope [main] +Uplift Scope [] + +Uplifting [main] best 33 combination +Uplifting [] best 33 combination + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +// Tests word pointer math - subtracting two word pointers +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const SIZEOF_WORD = 2 +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .label w1 = $1000 + .label w2 = $1140 + .label SCREEN = $400 + .const wd = w2-w1*SIZEOF_WORD + //SEG10 [4] *((const word*) main::SCREEN#0) ← (const word) main::wd#0 -- _deref_pwuc1=vwuc2 + lda #wd + sta SCREEN+1 + jmp breturn + //SEG11 main::@return + breturn: + //SEG12 [5] return + rts +} +//SEG13 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 +(const byte) SIZEOF_WORD SIZEOF_WORD = (byte) 2 +(void()) main() +(label) main::@return +(word*) main::SCREEN +(const word*) main::SCREEN#0 SCREEN = (word*) 1024 +(word*) main::w1 +(const word*) main::w1#0 w1 = (word*) 4096 +(word*) main::w2 +(const word*) main::w2#0 w2 = (word*) 4416 +(word) main::wd +(const word) main::wd#0 wd = (const word*) main::w2#0-(const word*) main::w1#0*(const byte) SIZEOF_WORD + + + +FINAL ASSEMBLER +Score: 18 + +//SEG0 File Comments +// Tests word pointer math - subtracting two word pointers +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const SIZEOF_WORD = 2 +//SEG3 @begin +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG5 @1 +//SEG6 [2] call main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +//SEG8 @end +//SEG9 main +main: { + .label w1 = $1000 + .label w2 = $1140 + .label SCREEN = $400 + .const wd = w2-w1*SIZEOF_WORD + //SEG10 [4] *((const word*) main::SCREEN#0) ← (const word) main::wd#0 -- _deref_pwuc1=vwuc2 + lda #wd + sta SCREEN+1 + //SEG11 main::@return + //SEG12 [5] return + rts +} +//SEG13 File Data + diff --git a/src/test/ref/word-pointer-math-1.sym b/src/test/ref/word-pointer-math-1.sym new file mode 100644 index 000000000..95f1e6269 --- /dev/null +++ b/src/test/ref/word-pointer-math-1.sym @@ -0,0 +1,15 @@ +(label) @1 +(label) @begin +(label) @end +(const byte) SIZEOF_WORD SIZEOF_WORD = (byte) 2 +(void()) main() +(label) main::@return +(word*) main::SCREEN +(const word*) main::SCREEN#0 SCREEN = (word*) 1024 +(word*) main::w1 +(const word*) main::w1#0 w1 = (word*) 4096 +(word*) main::w2 +(const word*) main::w2#0 w2 = (word*) 4416 +(word) main::wd +(const word) main::wd#0 wd = (const word*) main::w2#0-(const word*) main::w1#0*(const byte) SIZEOF_WORD +