mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-26 12:49:21 +00:00
Fixes optimization problem with post-increment/decrement of calculated pointers. Closes #428
This commit is contained in:
parent
eed25ff1cd
commit
013159c16d
@ -6,6 +6,8 @@ import dk.camelot64.kickc.model.symbols.ProgramScope;
|
|||||||
import dk.camelot64.kickc.model.types.SymbolType;
|
import dk.camelot64.kickc.model.types.SymbolType;
|
||||||
import dk.camelot64.kickc.model.types.SymbolTypeInference;
|
import dk.camelot64.kickc.model.types.SymbolTypeInference;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/** A constant defined by a binary operator applied to two constants */
|
/** A constant defined by a binary operator applied to two constants */
|
||||||
public class ConstantBinary implements ConstantValue {
|
public class ConstantBinary implements ConstantValue {
|
||||||
|
|
||||||
@ -74,4 +76,18 @@ public class ConstantBinary implements ConstantValue {
|
|||||||
return toString(null);
|
return toString(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if(this == o) return true;
|
||||||
|
if(o == null || getClass() != o.getClass()) return false;
|
||||||
|
ConstantBinary that = (ConstantBinary) o;
|
||||||
|
return left.equals(that.left) &&
|
||||||
|
operator.equals(that.operator) &&
|
||||||
|
right.equals(that.right);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(left, operator, right);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,6 +165,11 @@ public class TestPrograms {
|
|||||||
compileAndCompare("examples/conio/nacht-screen.c");
|
compileAndCompare("examples/conio/nacht-screen.c");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPostIncrementProblem2() throws IOException, URISyntaxException {
|
||||||
|
compileAndCompare("post-increment-problem-2.c");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPostIncrementProblem() throws IOException, URISyntaxException {
|
public void testPostIncrementProblem() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("post-increment-problem.c");
|
compileAndCompare("post-increment-problem.c");
|
||||||
|
14
src/test/kc/post-increment-problem-2.c
Normal file
14
src/test/kc/post-increment-problem-2.c
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
const byte *screen=$0400;
|
||||||
|
void main() {
|
||||||
|
word offset=40*10;
|
||||||
|
for (char x=0;x<254;x++)
|
||||||
|
incscreen(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void incscreen(word ptr) {
|
||||||
|
--(*(screen+ptr));
|
||||||
|
(*(screen+ptr+1))--;
|
||||||
|
++(*(screen+ptr));
|
||||||
|
(*(screen+ptr+1))++;
|
||||||
|
}
|
32
src/test/ref/post-increment-problem-2.asm
Normal file
32
src/test/ref/post-increment-problem-2.asm
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
.pc = $801 "Basic"
|
||||||
|
:BasicUpstart(main)
|
||||||
|
.pc = $80d "Program"
|
||||||
|
.label screen = $400
|
||||||
|
main: {
|
||||||
|
.label offset = $28*$a
|
||||||
|
ldx #0
|
||||||
|
__b1:
|
||||||
|
// for (char x=0;x<254;x++)
|
||||||
|
cpx #$fe
|
||||||
|
bcc __b2
|
||||||
|
// }
|
||||||
|
rts
|
||||||
|
__b2:
|
||||||
|
// incscreen(offset)
|
||||||
|
jsr incscreen
|
||||||
|
// for (char x=0;x<254;x++)
|
||||||
|
inx
|
||||||
|
jmp __b1
|
||||||
|
}
|
||||||
|
incscreen: {
|
||||||
|
// --(*(screen+ptr));
|
||||||
|
dec screen+main.offset
|
||||||
|
// (*(screen+ptr+1))--;
|
||||||
|
dec screen+main.offset+1
|
||||||
|
// ++(*(screen+ptr));
|
||||||
|
inc screen+main.offset
|
||||||
|
// (*(screen+ptr+1))++;
|
||||||
|
inc screen+main.offset+1
|
||||||
|
// }
|
||||||
|
rts
|
||||||
|
}
|
39
src/test/ref/post-increment-problem-2.cfg
Normal file
39
src/test/ref/post-increment-problem-2.cfg
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
@begin: scope:[] from
|
||||||
|
[0] phi()
|
||||||
|
to:@1
|
||||||
|
@1: scope:[] from @begin
|
||||||
|
[1] phi()
|
||||||
|
[2] call main
|
||||||
|
to:@end
|
||||||
|
@end: scope:[] from @1
|
||||||
|
[3] phi()
|
||||||
|
|
||||||
|
(void()) main()
|
||||||
|
main: scope:[main] from @1
|
||||||
|
[4] phi()
|
||||||
|
to:main::@1
|
||||||
|
main::@1: scope:[main] from main main::@3
|
||||||
|
[5] (byte) main::x#2 ← phi( main/(byte) 0 main::@3/(byte) main::x#1 )
|
||||||
|
[6] if((byte) main::x#2<(byte) $fe) goto main::@2
|
||||||
|
to:main::@return
|
||||||
|
main::@return: scope:[main] from main::@1
|
||||||
|
[7] return
|
||||||
|
to:@return
|
||||||
|
main::@2: scope:[main] from main::@1
|
||||||
|
[8] phi()
|
||||||
|
[9] call incscreen
|
||||||
|
to:main::@3
|
||||||
|
main::@3: scope:[main] from main::@2
|
||||||
|
[10] (byte) main::x#1 ← ++ (byte) main::x#2
|
||||||
|
to:main::@1
|
||||||
|
|
||||||
|
(void()) incscreen((word) incscreen::ptr)
|
||||||
|
incscreen: scope:[incscreen] from main::@2
|
||||||
|
[11] *((const to_nomodify byte*) screen+(const word) main::offset) ← -- *((const to_nomodify byte*) screen+(const word) main::offset)
|
||||||
|
[12] *((const to_nomodify byte*) screen+(const word) main::offset+(byte) 1) ← -- *((const to_nomodify byte*) screen+(const word) main::offset+(byte) 1)
|
||||||
|
[13] *((const to_nomodify byte*) screen+(const word) main::offset) ← ++ *((const to_nomodify byte*) screen+(const word) main::offset)
|
||||||
|
[14] *((const to_nomodify byte*) screen+(const word) main::offset+(byte) 1) ← ++ *((const to_nomodify byte*) screen+(const word) main::offset+(byte) 1)
|
||||||
|
to:incscreen::@return
|
||||||
|
incscreen::@return: scope:[incscreen] from incscreen
|
||||||
|
[15] return
|
||||||
|
to:@return
|
499
src/test/ref/post-increment-problem-2.log
Normal file
499
src/test/ref/post-increment-problem-2.log
Normal file
@ -0,0 +1,499 @@
|
|||||||
|
|
||||||
|
CONTROL FLOW GRAPH SSA
|
||||||
|
@begin: scope:[] from
|
||||||
|
to:@1
|
||||||
|
|
||||||
|
(void()) main()
|
||||||
|
main: scope:[main] from @1
|
||||||
|
(byte) main::x#0 ← (byte) 0
|
||||||
|
to:main::@1
|
||||||
|
main::@1: scope:[main] from main main::@3
|
||||||
|
(byte) main::x#2 ← phi( main/(byte) main::x#0 main::@3/(byte) main::x#1 )
|
||||||
|
(bool~) main::$0 ← (byte) main::x#2 < (number) $fe
|
||||||
|
if((bool~) main::$0) goto main::@2
|
||||||
|
to:main::@return
|
||||||
|
main::@2: scope:[main] from main::@1
|
||||||
|
(byte) main::x#4 ← phi( main::@1/(byte) main::x#2 )
|
||||||
|
(word) incscreen::ptr#0 ← (const word) main::offset
|
||||||
|
call incscreen
|
||||||
|
to:main::@3
|
||||||
|
main::@3: scope:[main] from main::@2
|
||||||
|
(byte) main::x#3 ← phi( main::@2/(byte) main::x#4 )
|
||||||
|
(byte) main::x#1 ← ++ (byte) main::x#3
|
||||||
|
to:main::@1
|
||||||
|
main::@return: scope:[main] from main::@1
|
||||||
|
return
|
||||||
|
to:@return
|
||||||
|
|
||||||
|
(void()) incscreen((word) incscreen::ptr)
|
||||||
|
incscreen: scope:[incscreen] from main::@2
|
||||||
|
(word) incscreen::ptr#1 ← phi( main::@2/(word) incscreen::ptr#0 )
|
||||||
|
(byte*~) incscreen::$0 ← (const to_nomodify byte*) screen + (word) incscreen::ptr#1
|
||||||
|
*((byte*~) incscreen::$0) ← -- *((byte*~) incscreen::$0)
|
||||||
|
(byte*~) incscreen::$9 ← (const to_nomodify byte*) screen + (word) incscreen::ptr#1
|
||||||
|
(byte*~) incscreen::$10 ← (byte*~) incscreen::$9 + (number) 1
|
||||||
|
*((byte*~) incscreen::$10) ← -- *((byte*~) incscreen::$10)
|
||||||
|
(byte*~) incscreen::$11 ← (const to_nomodify byte*) screen + (word) incscreen::ptr#1
|
||||||
|
*((byte*~) incscreen::$11) ← ++ *((byte*~) incscreen::$11)
|
||||||
|
(byte*~) incscreen::$20 ← (const to_nomodify byte*) screen + (word) incscreen::ptr#1
|
||||||
|
(byte*~) incscreen::$21 ← (byte*~) incscreen::$20 + (number) 1
|
||||||
|
*((byte*~) incscreen::$21) ← ++ *((byte*~) incscreen::$21)
|
||||||
|
to:incscreen::@return
|
||||||
|
incscreen::@return: scope:[incscreen] from incscreen
|
||||||
|
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()) incscreen((word) incscreen::ptr)
|
||||||
|
(byte*~) incscreen::$0
|
||||||
|
(byte*~) incscreen::$10
|
||||||
|
(byte*~) incscreen::$11
|
||||||
|
(byte*~) incscreen::$20
|
||||||
|
(byte*~) incscreen::$21
|
||||||
|
(byte*~) incscreen::$9
|
||||||
|
(label) incscreen::@return
|
||||||
|
(word) incscreen::ptr
|
||||||
|
(word) incscreen::ptr#0
|
||||||
|
(word) incscreen::ptr#1
|
||||||
|
(void()) main()
|
||||||
|
(bool~) main::$0
|
||||||
|
(label) main::@1
|
||||||
|
(label) main::@2
|
||||||
|
(label) main::@3
|
||||||
|
(label) main::@return
|
||||||
|
(const word) main::offset = (word)(number) $28*(number) $a
|
||||||
|
(byte) main::x
|
||||||
|
(byte) main::x#0
|
||||||
|
(byte) main::x#1
|
||||||
|
(byte) main::x#2
|
||||||
|
(byte) main::x#3
|
||||||
|
(byte) main::x#4
|
||||||
|
(const to_nomodify byte*) screen = (byte*)(number) $400
|
||||||
|
|
||||||
|
Adding number conversion cast (unumber) $fe in (bool~) main::$0 ← (byte) main::x#2 < (number) $fe
|
||||||
|
Adding number conversion cast (unumber) 1 in (byte*~) incscreen::$10 ← (byte*~) incscreen::$9 + (number) 1
|
||||||
|
Adding number conversion cast (unumber) 1 in (byte*~) incscreen::$21 ← (byte*~) incscreen::$20 + (number) 1
|
||||||
|
Successful SSA optimization PassNAddNumberTypeConversions
|
||||||
|
Simplifying constant pointer cast (byte*) 1024
|
||||||
|
Simplifying constant integer cast $fe
|
||||||
|
Simplifying constant integer cast 1
|
||||||
|
Simplifying constant integer cast 1
|
||||||
|
Successful SSA optimization PassNCastSimplification
|
||||||
|
Finalized unsigned number type (byte) $fe
|
||||||
|
Finalized unsigned number type (byte) 1
|
||||||
|
Finalized unsigned number type (byte) 1
|
||||||
|
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||||
|
Alias main::x#2 = main::x#4 main::x#3
|
||||||
|
Successful SSA optimization Pass2AliasElimination
|
||||||
|
Identical Phi Values (word) incscreen::ptr#1 (word) incscreen::ptr#0
|
||||||
|
Successful SSA optimization Pass2IdenticalPhiElimination
|
||||||
|
Simple Condition (bool~) main::$0 [3] if((byte) main::x#2<(byte) $fe) goto main::@2
|
||||||
|
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||||
|
Constant (const byte) main::x#0 = 0
|
||||||
|
Constant (const word) incscreen::ptr#0 = main::offset
|
||||||
|
Successful SSA optimization Pass2ConstantIdentification
|
||||||
|
Converting *(pointer+n) to pointer[n] [13] *((byte*~) incscreen::$10) ← -- *((byte*~) incscreen::$10) -- *(incscreen::$9 + 1)
|
||||||
|
Converting *(pointer+n) to pointer[n] [13] *((byte*~) incscreen::$10) ← -- *((byte*~) incscreen::$9 + (byte) 1) -- *(incscreen::$9 + 1)
|
||||||
|
Converting *(pointer+n) to pointer[n] [18] *((byte*~) incscreen::$21) ← ++ *((byte*~) incscreen::$21) -- *(incscreen::$20 + 1)
|
||||||
|
Converting *(pointer+n) to pointer[n] [18] *((byte*~) incscreen::$21) ← ++ *((byte*~) incscreen::$20 + (byte) 1) -- *(incscreen::$20 + 1)
|
||||||
|
Successful SSA optimization Pass2InlineDerefIdx
|
||||||
|
Eliminating unused variable (byte*~) incscreen::$10 and assignment [8] (byte*~) incscreen::$10 ← (byte*~) incscreen::$9 + (byte) 1
|
||||||
|
Eliminating unused variable (byte*~) incscreen::$21 and assignment [13] (byte*~) incscreen::$21 ← (byte*~) incscreen::$20 + (byte) 1
|
||||||
|
Successful SSA optimization PassNEliminateUnusedVars
|
||||||
|
Constant right-side identified [5] (byte*~) incscreen::$0 ← (const to_nomodify byte*) screen + (const word) incscreen::ptr#0
|
||||||
|
Constant right-side identified [7] (byte*~) incscreen::$9 ← (const to_nomodify byte*) screen + (const word) incscreen::ptr#0
|
||||||
|
Constant right-side identified [9] (byte*~) incscreen::$11 ← (const to_nomodify byte*) screen + (const word) incscreen::ptr#0
|
||||||
|
Constant right-side identified [11] (byte*~) incscreen::$20 ← (const to_nomodify byte*) screen + (const word) incscreen::ptr#0
|
||||||
|
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||||
|
Constant (const byte*) incscreen::$0 = screen+incscreen::ptr#0
|
||||||
|
Constant (const byte*) incscreen::$9 = screen+incscreen::ptr#0
|
||||||
|
Constant (const byte*) incscreen::$11 = screen+incscreen::ptr#0
|
||||||
|
Constant (const byte*) incscreen::$20 = screen+incscreen::ptr#0
|
||||||
|
Successful SSA optimization Pass2ConstantIdentification
|
||||||
|
Inlining constant with var siblings (const byte) main::x#0
|
||||||
|
Constant inlined incscreen::$0 = (const to_nomodify byte*) screen+(const word) main::offset
|
||||||
|
Constant inlined incscreen::$9 = (const to_nomodify byte*) screen+(const word) main::offset
|
||||||
|
Constant inlined incscreen::$20 = (const to_nomodify byte*) screen+(const word) main::offset
|
||||||
|
Constant inlined main::x#0 = (byte) 0
|
||||||
|
Constant inlined incscreen::$11 = (const to_nomodify byte*) screen+(const word) main::offset
|
||||||
|
Constant inlined incscreen::ptr#0 = (const word) main::offset
|
||||||
|
Successful SSA optimization Pass2ConstantInlining
|
||||||
|
Consolidated array index constant in *(screen+main::offset+1)
|
||||||
|
Consolidated array index constant in *(screen+main::offset+1)
|
||||||
|
Consolidated array index constant in *(screen+main::offset+1)
|
||||||
|
Consolidated array index constant in *(screen+main::offset+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
|
||||||
|
Adding NOP phi() at start of main
|
||||||
|
Adding NOP phi() at start of main::@2
|
||||||
|
CALL GRAPH
|
||||||
|
Calls in [] to main:2
|
||||||
|
Calls in [main] to incscreen:10
|
||||||
|
|
||||||
|
Created 1 initial phi equivalence classes
|
||||||
|
Coalesced [12] main::x#5 ← main::x#1
|
||||||
|
Coalesced down to 1 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
|
||||||
|
Adding NOP phi() at start of main
|
||||||
|
Adding NOP phi() at start of main::@2
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
(void()) main()
|
||||||
|
main: scope:[main] from @1
|
||||||
|
[4] phi()
|
||||||
|
to:main::@1
|
||||||
|
main::@1: scope:[main] from main main::@3
|
||||||
|
[5] (byte) main::x#2 ← phi( main/(byte) 0 main::@3/(byte) main::x#1 )
|
||||||
|
[6] if((byte) main::x#2<(byte) $fe) goto main::@2
|
||||||
|
to:main::@return
|
||||||
|
main::@return: scope:[main] from main::@1
|
||||||
|
[7] return
|
||||||
|
to:@return
|
||||||
|
main::@2: scope:[main] from main::@1
|
||||||
|
[8] phi()
|
||||||
|
[9] call incscreen
|
||||||
|
to:main::@3
|
||||||
|
main::@3: scope:[main] from main::@2
|
||||||
|
[10] (byte) main::x#1 ← ++ (byte) main::x#2
|
||||||
|
to:main::@1
|
||||||
|
|
||||||
|
(void()) incscreen((word) incscreen::ptr)
|
||||||
|
incscreen: scope:[incscreen] from main::@2
|
||||||
|
[11] *((const to_nomodify byte*) screen+(const word) main::offset) ← -- *((const to_nomodify byte*) screen+(const word) main::offset)
|
||||||
|
[12] *((const to_nomodify byte*) screen+(const word) main::offset+(byte) 1) ← -- *((const to_nomodify byte*) screen+(const word) main::offset+(byte) 1)
|
||||||
|
[13] *((const to_nomodify byte*) screen+(const word) main::offset) ← ++ *((const to_nomodify byte*) screen+(const word) main::offset)
|
||||||
|
[14] *((const to_nomodify byte*) screen+(const word) main::offset+(byte) 1) ← ++ *((const to_nomodify byte*) screen+(const word) main::offset+(byte) 1)
|
||||||
|
to:incscreen::@return
|
||||||
|
incscreen::@return: scope:[incscreen] from incscreen
|
||||||
|
[15] return
|
||||||
|
to:@return
|
||||||
|
|
||||||
|
|
||||||
|
VARIABLE REGISTER WEIGHTS
|
||||||
|
(void()) incscreen((word) incscreen::ptr)
|
||||||
|
(word) incscreen::ptr
|
||||||
|
(void()) main()
|
||||||
|
(byte) main::x
|
||||||
|
(byte) main::x#1 202.0
|
||||||
|
(byte) main::x#2 75.75
|
||||||
|
|
||||||
|
Initial phi equivalence classes
|
||||||
|
[ main::x#2 main::x#1 ]
|
||||||
|
Complete equivalence classes
|
||||||
|
[ main::x#2 main::x#1 ]
|
||||||
|
Allocated zp[1]:2 [ main::x#2 main::x#1 ]
|
||||||
|
|
||||||
|
INITIAL ASM
|
||||||
|
Target platform is c64basic / MOS6502X
|
||||||
|
// File Comments
|
||||||
|
// 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 offset = $28*$a
|
||||||
|
.label x = 2
|
||||||
|
// [5] phi from main to main::@1 [phi:main->main::@1]
|
||||||
|
__b1_from_main:
|
||||||
|
// [5] phi (byte) main::x#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
|
||||||
|
lda #0
|
||||||
|
sta.z x
|
||||||
|
jmp __b1
|
||||||
|
// main::@1
|
||||||
|
__b1:
|
||||||
|
// [6] if((byte) main::x#2<(byte) $fe) goto main::@2 -- vbuz1_lt_vbuc1_then_la1
|
||||||
|
lda.z x
|
||||||
|
cmp #$fe
|
||||||
|
bcc __b2_from___b1
|
||||||
|
jmp __breturn
|
||||||
|
// main::@return
|
||||||
|
__breturn:
|
||||||
|
// [7] return
|
||||||
|
rts
|
||||||
|
// [8] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
|
||||||
|
__b2_from___b1:
|
||||||
|
jmp __b2
|
||||||
|
// main::@2
|
||||||
|
__b2:
|
||||||
|
// [9] call incscreen
|
||||||
|
jsr incscreen
|
||||||
|
jmp __b3
|
||||||
|
// main::@3
|
||||||
|
__b3:
|
||||||
|
// [10] (byte) main::x#1 ← ++ (byte) main::x#2 -- vbuz1=_inc_vbuz1
|
||||||
|
inc.z x
|
||||||
|
// [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1]
|
||||||
|
__b1_from___b3:
|
||||||
|
// [5] phi (byte) main::x#2 = (byte) main::x#1 [phi:main::@3->main::@1#0] -- register_copy
|
||||||
|
jmp __b1
|
||||||
|
}
|
||||||
|
// incscreen
|
||||||
|
incscreen: {
|
||||||
|
// [11] *((const to_nomodify byte*) screen+(const word) main::offset) ← -- *((const to_nomodify byte*) screen+(const word) main::offset) -- _deref_pbuc1=_dec__deref_pbuc1
|
||||||
|
dec screen+main.offset
|
||||||
|
// [12] *((const to_nomodify byte*) screen+(const word) main::offset+(byte) 1) ← -- *((const to_nomodify byte*) screen+(const word) main::offset+(byte) 1) -- _deref_pbuc1=_dec__deref_pbuc1
|
||||||
|
dec screen+main.offset+1
|
||||||
|
// [13] *((const to_nomodify byte*) screen+(const word) main::offset) ← ++ *((const to_nomodify byte*) screen+(const word) main::offset) -- _deref_pbuc1=_inc__deref_pbuc1
|
||||||
|
inc screen+main.offset
|
||||||
|
// [14] *((const to_nomodify byte*) screen+(const word) main::offset+(byte) 1) ← ++ *((const to_nomodify byte*) screen+(const word) main::offset+(byte) 1) -- _deref_pbuc1=_inc__deref_pbuc1
|
||||||
|
inc screen+main.offset+1
|
||||||
|
jmp __breturn
|
||||||
|
// incscreen::@return
|
||||||
|
__breturn:
|
||||||
|
// [15] return
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// File Data
|
||||||
|
|
||||||
|
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||||
|
Potential registers zp[1]:2 [ main::x#2 main::x#1 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
|
||||||
|
|
||||||
|
REGISTER UPLIFT SCOPES
|
||||||
|
Uplift Scope [main] 277.75: zp[1]:2 [ main::x#2 main::x#1 ]
|
||||||
|
Uplift Scope [incscreen]
|
||||||
|
Uplift Scope []
|
||||||
|
|
||||||
|
Uplifting [main] best 346 combination reg byte x [ main::x#2 main::x#1 ]
|
||||||
|
Uplifting [incscreen] best 346 combination
|
||||||
|
Uplifting [] best 346 combination
|
||||||
|
|
||||||
|
ASSEMBLER BEFORE OPTIMIZATION
|
||||||
|
// File Comments
|
||||||
|
// 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 offset = $28*$a
|
||||||
|
// [5] phi from main to main::@1 [phi:main->main::@1]
|
||||||
|
__b1_from_main:
|
||||||
|
// [5] phi (byte) main::x#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
|
||||||
|
ldx #0
|
||||||
|
jmp __b1
|
||||||
|
// main::@1
|
||||||
|
__b1:
|
||||||
|
// [6] if((byte) main::x#2<(byte) $fe) goto main::@2 -- vbuxx_lt_vbuc1_then_la1
|
||||||
|
cpx #$fe
|
||||||
|
bcc __b2_from___b1
|
||||||
|
jmp __breturn
|
||||||
|
// main::@return
|
||||||
|
__breturn:
|
||||||
|
// [7] return
|
||||||
|
rts
|
||||||
|
// [8] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
|
||||||
|
__b2_from___b1:
|
||||||
|
jmp __b2
|
||||||
|
// main::@2
|
||||||
|
__b2:
|
||||||
|
// [9] call incscreen
|
||||||
|
jsr incscreen
|
||||||
|
jmp __b3
|
||||||
|
// main::@3
|
||||||
|
__b3:
|
||||||
|
// [10] (byte) main::x#1 ← ++ (byte) main::x#2 -- vbuxx=_inc_vbuxx
|
||||||
|
inx
|
||||||
|
// [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1]
|
||||||
|
__b1_from___b3:
|
||||||
|
// [5] phi (byte) main::x#2 = (byte) main::x#1 [phi:main::@3->main::@1#0] -- register_copy
|
||||||
|
jmp __b1
|
||||||
|
}
|
||||||
|
// incscreen
|
||||||
|
incscreen: {
|
||||||
|
// [11] *((const to_nomodify byte*) screen+(const word) main::offset) ← -- *((const to_nomodify byte*) screen+(const word) main::offset) -- _deref_pbuc1=_dec__deref_pbuc1
|
||||||
|
dec screen+main.offset
|
||||||
|
// [12] *((const to_nomodify byte*) screen+(const word) main::offset+(byte) 1) ← -- *((const to_nomodify byte*) screen+(const word) main::offset+(byte) 1) -- _deref_pbuc1=_dec__deref_pbuc1
|
||||||
|
dec screen+main.offset+1
|
||||||
|
// [13] *((const to_nomodify byte*) screen+(const word) main::offset) ← ++ *((const to_nomodify byte*) screen+(const word) main::offset) -- _deref_pbuc1=_inc__deref_pbuc1
|
||||||
|
inc screen+main.offset
|
||||||
|
// [14] *((const to_nomodify byte*) screen+(const word) main::offset+(byte) 1) ← ++ *((const to_nomodify byte*) screen+(const word) main::offset+(byte) 1) -- _deref_pbuc1=_inc__deref_pbuc1
|
||||||
|
inc screen+main.offset+1
|
||||||
|
jmp __breturn
|
||||||
|
// incscreen::@return
|
||||||
|
__breturn:
|
||||||
|
// [15] return
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// File Data
|
||||||
|
|
||||||
|
ASSEMBLER OPTIMIZATIONS
|
||||||
|
Removing instruction jmp __b1
|
||||||
|
Removing instruction jmp __bend
|
||||||
|
Removing instruction jmp __b1
|
||||||
|
Removing instruction jmp __breturn
|
||||||
|
Removing instruction jmp __b2
|
||||||
|
Removing instruction jmp __b3
|
||||||
|
Removing instruction jmp __breturn
|
||||||
|
Succesful ASM optimization Pass5NextJumpElimination
|
||||||
|
Replacing label __b2_from___b1 with __b2
|
||||||
|
Removing instruction __b1_from___bbegin:
|
||||||
|
Removing instruction __b1:
|
||||||
|
Removing instruction main_from___b1:
|
||||||
|
Removing instruction __bend_from___b1:
|
||||||
|
Removing instruction __b2_from___b1:
|
||||||
|
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||||
|
Removing instruction __bend:
|
||||||
|
Removing instruction __b1_from_main:
|
||||||
|
Removing instruction __breturn:
|
||||||
|
Removing instruction __b3:
|
||||||
|
Removing instruction __b1_from___b3:
|
||||||
|
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()) incscreen((word) incscreen::ptr)
|
||||||
|
(label) incscreen::@return
|
||||||
|
(word) incscreen::ptr
|
||||||
|
(void()) main()
|
||||||
|
(label) main::@1
|
||||||
|
(label) main::@2
|
||||||
|
(label) main::@3
|
||||||
|
(label) main::@return
|
||||||
|
(const word) main::offset = (word)(number) $28*(number) $a
|
||||||
|
(byte) main::x
|
||||||
|
(byte) main::x#1 reg byte x 202.0
|
||||||
|
(byte) main::x#2 reg byte x 75.75
|
||||||
|
(const to_nomodify byte*) screen = (byte*) 1024
|
||||||
|
|
||||||
|
reg byte x [ main::x#2 main::x#1 ]
|
||||||
|
|
||||||
|
|
||||||
|
FINAL ASSEMBLER
|
||||||
|
Score: 211
|
||||||
|
|
||||||
|
// File Comments
|
||||||
|
// 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 offset = $28*$a
|
||||||
|
// [5] phi from main to main::@1 [phi:main->main::@1]
|
||||||
|
// [5] phi (byte) main::x#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
|
||||||
|
ldx #0
|
||||||
|
// main::@1
|
||||||
|
__b1:
|
||||||
|
// for (char x=0;x<254;x++)
|
||||||
|
// [6] if((byte) main::x#2<(byte) $fe) goto main::@2 -- vbuxx_lt_vbuc1_then_la1
|
||||||
|
cpx #$fe
|
||||||
|
bcc __b2
|
||||||
|
// main::@return
|
||||||
|
// }
|
||||||
|
// [7] return
|
||||||
|
rts
|
||||||
|
// [8] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
|
||||||
|
// main::@2
|
||||||
|
__b2:
|
||||||
|
// incscreen(offset)
|
||||||
|
// [9] call incscreen
|
||||||
|
jsr incscreen
|
||||||
|
// main::@3
|
||||||
|
// for (char x=0;x<254;x++)
|
||||||
|
// [10] (byte) main::x#1 ← ++ (byte) main::x#2 -- vbuxx=_inc_vbuxx
|
||||||
|
inx
|
||||||
|
// [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1]
|
||||||
|
// [5] phi (byte) main::x#2 = (byte) main::x#1 [phi:main::@3->main::@1#0] -- register_copy
|
||||||
|
jmp __b1
|
||||||
|
}
|
||||||
|
// incscreen
|
||||||
|
incscreen: {
|
||||||
|
// --(*(screen+ptr));
|
||||||
|
// [11] *((const to_nomodify byte*) screen+(const word) main::offset) ← -- *((const to_nomodify byte*) screen+(const word) main::offset) -- _deref_pbuc1=_dec__deref_pbuc1
|
||||||
|
dec screen+main.offset
|
||||||
|
// (*(screen+ptr+1))--;
|
||||||
|
// [12] *((const to_nomodify byte*) screen+(const word) main::offset+(byte) 1) ← -- *((const to_nomodify byte*) screen+(const word) main::offset+(byte) 1) -- _deref_pbuc1=_dec__deref_pbuc1
|
||||||
|
dec screen+main.offset+1
|
||||||
|
// ++(*(screen+ptr));
|
||||||
|
// [13] *((const to_nomodify byte*) screen+(const word) main::offset) ← ++ *((const to_nomodify byte*) screen+(const word) main::offset) -- _deref_pbuc1=_inc__deref_pbuc1
|
||||||
|
inc screen+main.offset
|
||||||
|
// (*(screen+ptr+1))++;
|
||||||
|
// [14] *((const to_nomodify byte*) screen+(const word) main::offset+(byte) 1) ← ++ *((const to_nomodify byte*) screen+(const word) main::offset+(byte) 1) -- _deref_pbuc1=_inc__deref_pbuc1
|
||||||
|
inc screen+main.offset+1
|
||||||
|
// incscreen::@return
|
||||||
|
// }
|
||||||
|
// [15] return
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// File Data
|
||||||
|
|
18
src/test/ref/post-increment-problem-2.sym
Normal file
18
src/test/ref/post-increment-problem-2.sym
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
(label) @1
|
||||||
|
(label) @begin
|
||||||
|
(label) @end
|
||||||
|
(void()) incscreen((word) incscreen::ptr)
|
||||||
|
(label) incscreen::@return
|
||||||
|
(word) incscreen::ptr
|
||||||
|
(void()) main()
|
||||||
|
(label) main::@1
|
||||||
|
(label) main::@2
|
||||||
|
(label) main::@3
|
||||||
|
(label) main::@return
|
||||||
|
(const word) main::offset = (word)(number) $28*(number) $a
|
||||||
|
(byte) main::x
|
||||||
|
(byte) main::x#1 reg byte x 202.0
|
||||||
|
(byte) main::x#2 reg byte x 75.75
|
||||||
|
(const to_nomodify byte*) screen = (byte*) 1024
|
||||||
|
|
||||||
|
reg byte x [ main::x#2 main::x#1 ]
|
Loading…
Reference in New Issue
Block a user