mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-26 18:29:54 +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.SymbolTypeInference;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/** A constant defined by a binary operator applied to two constants */
|
||||
public class ConstantBinary implements ConstantValue {
|
||||
|
||||
@ -74,4 +76,18 @@ public class ConstantBinary implements ConstantValue {
|
||||
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");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostIncrementProblem2() throws IOException, URISyntaxException {
|
||||
compileAndCompare("post-increment-problem-2.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostIncrementProblem() throws IOException, URISyntaxException {
|
||||
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