1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-11-27 04:49:27 +00:00

Tests exploring sub-expression optimization.

This commit is contained in:
Jesper Gravgaard 2019-06-03 12:19:47 +02:00
parent 8289676723
commit 2f900a9102
19 changed files with 2271 additions and 10 deletions

View File

@ -171,6 +171,21 @@ public class TestPrograms {
compileAndCompare("statement-sequence-1");
}
@Test
public void testSubExprOptimize4() throws IOException, URISyntaxException {
compileAndCompare("subexpr-optimize-4");
}
@Test
public void testSubExprOptimize3() throws IOException, URISyntaxException {
compileAndCompare("subexpr-optimize-3");
}
@Test
public void testSubExprOptimize2() throws IOException, URISyntaxException {
compileAndCompare("subexpr-optimize-2");
}
@Test
public void testSubExprOptimize1() throws IOException, URISyntaxException {
compileAndCompare("subexpr-optimize-1");

View File

@ -1,5 +1,5 @@
// Tests (non-)optimization of identical sub-expressions
// The two examples of i+1 is not detected as identical leading to ASM that could be optimized more
// Tests optimization of identical sub-expressions
// The two examples of i*2 is detected as identical leading to optimized ASM where *2 is only calculated once
void main() {
byte* screen = 0x400;
for( byte i: 0..2) {

View File

@ -0,0 +1,9 @@
// Tests optimization of identical sub-expressions
void main() {
byte* screen = 0x400;
for( byte i: 0..2) {
*screen++ = (i+1)*2;
*screen++ = (i+1)*2;
}
}

View File

@ -0,0 +1,9 @@
// Tests optimization of identical sub-expressions
void main() {
byte* screen = 0x400;
for( byte i: 0..2) {
*screen++ = i*2+i+3;
*screen++ = i*2+i+3;
}
}

View File

@ -0,0 +1,9 @@
// Tests optimization of identical sub-expressions
void main() {
byte* screen = 0x400;
for( byte i: 0..2) {
*screen++ = (i&1)?i+3:i*4;
*screen++ = (i&1)?i+3:i*4;
}
}

View File

@ -1,5 +1,5 @@
// Tests (non-)optimization of identical sub-expressions
// The two examples of i+1 is not detected as identical leading to ASM that could be optimized more
// Tests optimization of identical sub-expressions
// The two examples of i*2 is detected as identical leading to optimized ASM where *2 is only calculated once
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"

View File

@ -169,8 +169,8 @@ Allocated zp ZP_WORD:6 [ main::screen#1 ]
INITIAL ASM
//SEG0 File Comments
// Tests (non-)optimization of identical sub-expressions
// The two examples of i+1 is not detected as identical leading to ASM that could be optimized more
// Tests optimization of identical sub-expressions
// The two examples of i*2 is detected as identical leading to optimized ASM where *2 is only calculated once
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
@ -292,8 +292,8 @@ Allocated (was zp ZP_BYTE:5) zp ZP_BYTE:4 [ main::$1 ]
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Tests (non-)optimization of identical sub-expressions
// The two examples of i+1 is not detected as identical leading to ASM that could be optimized more
// Tests optimization of identical sub-expressions
// The two examples of i*2 is detected as identical leading to optimized ASM where *2 is only calculated once
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
@ -422,8 +422,8 @@ FINAL ASSEMBLER
Score: 701
//SEG0 File Comments
// Tests (non-)optimization of identical sub-expressions
// The two examples of i+1 is not detected as identical leading to ASM that could be optimized more
// Tests optimization of identical sub-expressions
// The two examples of i*2 is detected as identical leading to optimized ASM where *2 is only calculated once
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)

View File

@ -0,0 +1,40 @@
// Tests optimization of identical sub-expressions
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
main: {
.label screen = 3
.label i = 2
lda #<$400
sta screen
lda #>$400
sta screen+1
lda #0
sta i
b1:
lda i
clc
adc #1
asl
ldy #0
sta (screen),y
inc screen
bne !+
inc screen+1
!:
lda i
clc
adc #1
asl
ldy #0
sta (screen),y
inc screen
bne !+
inc screen+1
!:
inc i
lda #3
cmp i
bne b1
rts
}

View File

@ -0,0 +1,29 @@
@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()
to:main::@1
main::@1: scope:[main] from main main::@1
[5] (byte*) main::screen#3 ← phi( main/(byte*) 1024 main::@1/(byte*) main::screen#2 )
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 )
[6] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1
[7] (byte~) main::$1 ← (byte~) main::$0 << (byte) 1
[8] *((byte*) main::screen#3) ← (byte~) main::$1
[9] (byte*) main::screen#1 ← ++ (byte*) main::screen#3
[10] (byte~) main::$2 ← (byte) main::i#2 + (byte) 1
[11] (byte~) main::$3 ← (byte~) main::$2 << (byte) 1
[12] *((byte*) main::screen#1) ← (byte~) main::$3
[13] (byte*) main::screen#2 ← ++ (byte*) main::screen#1
[14] (byte) main::i#1 ← ++ (byte) main::i#2
[15] if((byte) main::i#1!=(byte) 3) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[16] return
to:@return

View File

@ -0,0 +1,547 @@
Adding pointer type conversion cast (byte*) main::screen in (byte*) main::screen ← (number) $400
Culled Empty Block (label) main::@2
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@1
main: scope:[main] from @1
(byte*) main::screen#0 ← ((byte*)) (number) $400
(byte) main::i#0 ← (byte) 0
to:main::@1
main::@1: scope:[main] from main main::@1
(byte*) main::screen#3 ← phi( main/(byte*) main::screen#0 main::@1/(byte*) main::screen#2 )
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 )
(number~) main::$0 ← (byte) main::i#2 + (number) 1
(number~) main::$1 ← (number~) main::$0 * (number) 2
*((byte*) main::screen#3) ← (number~) main::$1
(byte*) main::screen#1 ← ++ (byte*) main::screen#3
(number~) main::$2 ← (byte) main::i#2 + (number) 1
(number~) main::$3 ← (number~) main::$2 * (number) 2
*((byte*) main::screen#1) ← (number~) main::$3
(byte*) main::screen#2 ← ++ (byte*) main::screen#1
(byte) main::i#1 ← (byte) main::i#2 + rangenext(0,2)
(bool~) main::$4 ← (byte) main::i#1 != rangelast(0,2)
if((bool~) main::$4) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
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()) main()
(number~) main::$0
(number~) main::$1
(number~) main::$2
(number~) main::$3
(bool~) main::$4
(label) main::@1
(label) main::@return
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
(byte*) main::screen
(byte*) main::screen#0
(byte*) main::screen#1
(byte*) main::screen#2
(byte*) main::screen#3
Adding number conversion cast (unumber) 1 in (number~) main::$0 ← (byte) main::i#2 + (number) 1
Adding number conversion cast (unumber) main::$0 in (number~) main::$0 ← (byte) main::i#2 + (unumber)(number) 1
Adding number conversion cast (unumber) 2 in (number~) main::$1 ← (unumber~) main::$0 * (number) 2
Adding number conversion cast (unumber) main::$1 in (number~) main::$1 ← (unumber~) main::$0 * (unumber)(number) 2
Adding number conversion cast (unumber) 1 in (number~) main::$2 ← (byte) main::i#2 + (number) 1
Adding number conversion cast (unumber) main::$2 in (number~) main::$2 ← (byte) main::i#2 + (unumber)(number) 1
Adding number conversion cast (unumber) 2 in (number~) main::$3 ← (unumber~) main::$2 * (number) 2
Adding number conversion cast (unumber) main::$3 in (number~) main::$3 ← (unumber~) main::$2 * (unumber)(number) 2
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (byte*) main::screen#0 ← (byte*)(number) $400
Successful SSA optimization Pass2InlineCast
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 1
Simplifying constant integer cast 2
Simplifying constant integer cast 1
Simplifying constant integer cast 2
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 2
Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 2
Successful SSA optimization PassNFinalizeNumberTypeConversions
Inferred type updated to byte in (unumber~) main::$0 ← (byte) main::i#2 + (byte) 1
Inferred type updated to byte in (unumber~) main::$1 ← (byte~) main::$0 * (byte) 2
Inferred type updated to byte in (unumber~) main::$2 ← (byte) main::i#2 + (byte) 1
Inferred type updated to byte in (unumber~) main::$3 ← (byte~) main::$2 * (byte) 2
Simple Condition (bool~) main::$4 [13] if((byte) main::i#1!=rangelast(0,2)) goto main::@1
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const byte*) main::screen#0 = (byte*) 1024
Constant (const byte) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Resolved ranged next value [11] main::i#1 ← ++ main::i#2 to ++
Resolved ranged comparison value [13] if(main::i#1!=rangelast(0,2)) goto main::@1 to (number) 3
Adding number conversion cast (unumber) 3 in if((byte) main::i#1!=(number) 3) goto main::@1
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant integer cast 3
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 3
Successful SSA optimization PassNFinalizeNumberTypeConversions
Rewriting multiplication to use shift [2] (byte~) main::$1 ← (byte~) main::$0 * (byte) 2
Rewriting multiplication to use shift [6] (byte~) main::$3 ← (byte~) main::$2 * (byte) 2
Successful SSA optimization Pass2MultiplyToShiftRewriting
Inlining constant with var siblings (const byte*) main::screen#0
Inlining constant with var siblings (const byte) main::i#0
Constant inlined main::screen#0 = (byte*) 1024
Constant inlined main::i#0 = (byte) 0
Successful SSA optimization Pass2ConstantInlining
Added new block during phi lifting main::@3(between main::@1 and main::@1)
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
CALL GRAPH
Calls in [] to main:2
Created 2 initial phi equivalence classes
Coalesced [18] main::i#3 ← main::i#1
Coalesced [19] main::screen#4 ← main::screen#2
Coalesced down to 2 phi equivalence classes
Culled Empty Block (label) @2
Culled Empty Block (label) main::@3
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@1
[5] (byte*) main::screen#3 ← phi( main/(byte*) 1024 main::@1/(byte*) main::screen#2 )
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 )
[6] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1
[7] (byte~) main::$1 ← (byte~) main::$0 << (byte) 1
[8] *((byte*) main::screen#3) ← (byte~) main::$1
[9] (byte*) main::screen#1 ← ++ (byte*) main::screen#3
[10] (byte~) main::$2 ← (byte) main::i#2 + (byte) 1
[11] (byte~) main::$3 ← (byte~) main::$2 << (byte) 1
[12] *((byte*) main::screen#1) ← (byte~) main::$3
[13] (byte*) main::screen#2 ← ++ (byte*) main::screen#1
[14] (byte) main::i#1 ← ++ (byte) main::i#2
[15] if((byte) main::i#1!=(byte) 3) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[16] return
to:@return
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte~) main::$0 22.0
(byte~) main::$1 22.0
(byte~) main::$2 22.0
(byte~) main::$3 22.0
(byte) main::i
(byte) main::i#1 16.5
(byte) main::i#2 4.888888888888889
(byte*) main::screen
(byte*) main::screen#1 8.25
(byte*) main::screen#2 7.333333333333333
(byte*) main::screen#3 8.25
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
[ main::screen#3 main::screen#2 ]
Added variable main::$0 to zero page equivalence class [ main::$0 ]
Added variable main::$1 to zero page equivalence class [ main::$1 ]
Added variable main::screen#1 to zero page equivalence class [ main::screen#1 ]
Added variable main::$2 to zero page equivalence class [ main::$2 ]
Added variable main::$3 to zero page equivalence class [ main::$3 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ main::screen#3 main::screen#2 ]
[ main::$0 ]
[ main::$1 ]
[ main::screen#1 ]
[ main::$2 ]
[ main::$3 ]
Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Allocated zp ZP_WORD:3 [ main::screen#3 main::screen#2 ]
Allocated zp ZP_BYTE:5 [ main::$0 ]
Allocated zp ZP_BYTE:6 [ main::$1 ]
Allocated zp ZP_WORD:7 [ main::screen#1 ]
Allocated zp ZP_BYTE:9 [ main::$2 ]
Allocated zp ZP_BYTE:10 [ main::$3 ]
INITIAL ASM
//SEG0 File Comments
// Tests optimization of identical sub-expressions
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//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: {
.label _0 = 5
.label _1 = 6
.label _2 = 9
.label _3 = $a
.label screen = 7
.label screen_2 = 3
.label i = 2
.label screen_3 = 3
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
//SEG12 [5] phi (byte*) main::screen#3 = (byte*) 1024 [phi:main->main::@1#0] -- pbuz1=pbuc1
lda #<$400
sta screen_3
lda #>$400
sta screen_3+1
//SEG13 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#1] -- vbuz1=vbuc1
lda #0
sta i
jmp b1
//SEG14 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
b1_from_b1:
//SEG15 [5] phi (byte*) main::screen#3 = (byte*) main::screen#2 [phi:main::@1->main::@1#0] -- register_copy
//SEG16 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#1] -- register_copy
jmp b1
//SEG17 main::@1
b1:
//SEG18 [6] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1 -- vbuz1=vbuz2_plus_1
ldy i
iny
sty _0
//SEG19 [7] (byte~) main::$1 ← (byte~) main::$0 << (byte) 1 -- vbuz1=vbuz2_rol_1
lda _0
asl
sta _1
//SEG20 [8] *((byte*) main::screen#3) ← (byte~) main::$1 -- _deref_pbuz1=vbuz2
lda _1
ldy #0
sta (screen_3),y
//SEG21 [9] (byte*) main::screen#1 ← ++ (byte*) main::screen#3 -- pbuz1=_inc_pbuz2
lda screen_3
clc
adc #1
sta screen
lda screen_3+1
adc #0
sta screen+1
//SEG22 [10] (byte~) main::$2 ← (byte) main::i#2 + (byte) 1 -- vbuz1=vbuz2_plus_1
ldy i
iny
sty _2
//SEG23 [11] (byte~) main::$3 ← (byte~) main::$2 << (byte) 1 -- vbuz1=vbuz2_rol_1
lda _2
asl
sta _3
//SEG24 [12] *((byte*) main::screen#1) ← (byte~) main::$3 -- _deref_pbuz1=vbuz2
lda _3
ldy #0
sta (screen),y
//SEG25 [13] (byte*) main::screen#2 ← ++ (byte*) main::screen#1 -- pbuz1=_inc_pbuz2
lda screen
clc
adc #1
sta screen_2
lda screen+1
adc #0
sta screen_2+1
//SEG26 [14] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG27 [15] if((byte) main::i#1!=(byte) 3) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda #3
cmp i
bne b1_from_b1
jmp breturn
//SEG28 main::@return
breturn:
//SEG29 [16] return
rts
}
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [7] (byte~) main::$1 ← (byte~) main::$0 << (byte) 1 [ main::i#2 main::screen#3 main::$1 ] ( main:2 [ main::i#2 main::screen#3 main::$1 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Statement [8] *((byte*) main::screen#3) ← (byte~) main::$1 [ main::i#2 main::screen#3 ] ( main:2 [ main::i#2 main::screen#3 ] ) always clobbers reg byte y
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Statement [9] (byte*) main::screen#1 ← ++ (byte*) main::screen#3 [ main::i#2 main::screen#1 ] ( main:2 [ main::i#2 main::screen#1 ] ) always clobbers reg byte a
Statement [11] (byte~) main::$3 ← (byte~) main::$2 << (byte) 1 [ main::i#2 main::screen#1 main::$3 ] ( main:2 [ main::i#2 main::screen#1 main::$3 ] ) always clobbers reg byte a
Statement [12] *((byte*) main::screen#1) ← (byte~) main::$3 [ main::i#2 main::screen#1 ] ( main:2 [ main::i#2 main::screen#1 ] ) always clobbers reg byte y
Statement [13] (byte*) main::screen#2 ← ++ (byte*) main::screen#1 [ main::i#2 main::screen#2 ] ( main:2 [ main::i#2 main::screen#2 ] ) always clobbers reg byte a
Statement [7] (byte~) main::$1 ← (byte~) main::$0 << (byte) 1 [ main::i#2 main::screen#3 main::$1 ] ( main:2 [ main::i#2 main::screen#3 main::$1 ] ) always clobbers reg byte a
Statement [8] *((byte*) main::screen#3) ← (byte~) main::$1 [ main::i#2 main::screen#3 ] ( main:2 [ main::i#2 main::screen#3 ] ) always clobbers reg byte y
Statement [9] (byte*) main::screen#1 ← ++ (byte*) main::screen#3 [ main::i#2 main::screen#1 ] ( main:2 [ main::i#2 main::screen#1 ] ) always clobbers reg byte a
Statement [11] (byte~) main::$3 ← (byte~) main::$2 << (byte) 1 [ main::i#2 main::screen#1 main::$3 ] ( main:2 [ main::i#2 main::screen#1 main::$3 ] ) always clobbers reg byte a
Statement [12] *((byte*) main::screen#1) ← (byte~) main::$3 [ main::i#2 main::screen#1 ] ( main:2 [ main::i#2 main::screen#1 ] ) always clobbers reg byte y
Statement [13] (byte*) main::screen#2 ← ++ (byte*) main::screen#1 [ main::i#2 main::screen#2 ] ( main:2 [ main::i#2 main::screen#2 ] ) always clobbers reg byte a
Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte x ,
Potential registers zp ZP_WORD:3 [ main::screen#3 main::screen#2 ] : zp ZP_WORD:3 ,
Potential registers zp ZP_BYTE:5 [ main::$0 ] : zp ZP_BYTE:5 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:6 [ main::$1 ] : zp ZP_BYTE:6 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_WORD:7 [ main::screen#1 ] : zp ZP_WORD:7 ,
Potential registers zp ZP_BYTE:9 [ main::$2 ] : zp ZP_BYTE:9 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:10 [ main::$3 ] : zp ZP_BYTE:10 , reg byte a , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 22: zp ZP_BYTE:5 [ main::$0 ] 22: zp ZP_BYTE:6 [ main::$1 ] 22: zp ZP_BYTE:9 [ main::$2 ] 22: zp ZP_BYTE:10 [ main::$3 ] 21.39: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 15.58: zp ZP_WORD:3 [ main::screen#3 main::screen#2 ] 8.25: zp ZP_WORD:7 [ main::screen#1 ]
Uplift Scope []
Uplifting [main] best 1083 combination reg byte a [ main::$0 ] reg byte a [ main::$1 ] reg byte a [ main::$2 ] reg byte a [ main::$3 ] zp ZP_BYTE:2 [ main::i#2 main::i#1 ] zp ZP_WORD:3 [ main::screen#3 main::screen#2 ] zp ZP_WORD:7 [ main::screen#1 ]
Limited combination testing to 100 combinations of 512 possible.
Uplifting [] best 1083 combination
Attempting to uplift remaining variables inzp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Uplifting [main] best 1083 combination zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Coalescing zero page register with common assignment [ zp ZP_WORD:3 [ main::screen#3 main::screen#2 ] ] with [ zp ZP_WORD:7 [ main::screen#1 ] ] - score: 2
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Tests optimization of identical sub-expressions
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//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: {
.label screen = 3
.label i = 2
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
//SEG12 [5] phi (byte*) main::screen#3 = (byte*) 1024 [phi:main->main::@1#0] -- pbuz1=pbuc1
lda #<$400
sta screen
lda #>$400
sta screen+1
//SEG13 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#1] -- vbuz1=vbuc1
lda #0
sta i
jmp b1
//SEG14 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
b1_from_b1:
//SEG15 [5] phi (byte*) main::screen#3 = (byte*) main::screen#2 [phi:main::@1->main::@1#0] -- register_copy
//SEG16 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#1] -- register_copy
jmp b1
//SEG17 main::@1
b1:
//SEG18 [6] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1 -- vbuaa=vbuz1_plus_1
lda i
clc
adc #1
//SEG19 [7] (byte~) main::$1 ← (byte~) main::$0 << (byte) 1 -- vbuaa=vbuaa_rol_1
asl
//SEG20 [8] *((byte*) main::screen#3) ← (byte~) main::$1 -- _deref_pbuz1=vbuaa
ldy #0
sta (screen),y
//SEG21 [9] (byte*) main::screen#1 ← ++ (byte*) main::screen#3 -- pbuz1=_inc_pbuz1
inc screen
bne !+
inc screen+1
!:
//SEG22 [10] (byte~) main::$2 ← (byte) main::i#2 + (byte) 1 -- vbuaa=vbuz1_plus_1
lda i
clc
adc #1
//SEG23 [11] (byte~) main::$3 ← (byte~) main::$2 << (byte) 1 -- vbuaa=vbuaa_rol_1
asl
//SEG24 [12] *((byte*) main::screen#1) ← (byte~) main::$3 -- _deref_pbuz1=vbuaa
ldy #0
sta (screen),y
//SEG25 [13] (byte*) main::screen#2 ← ++ (byte*) main::screen#1 -- pbuz1=_inc_pbuz1
inc screen
bne !+
inc screen+1
!:
//SEG26 [14] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG27 [15] if((byte) main::i#1!=(byte) 3) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda #3
cmp i
bne b1_from_b1
jmp breturn
//SEG28 main::@return
breturn:
//SEG29 [16] return
rts
}
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp b1
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing label b1_from_b1 with b1
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction main_from_b1:
Removing instruction bend_from_b1:
Removing instruction b1_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction b1_from_main:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction jmp b1
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(void()) main()
(byte~) main::$0 reg byte a 22.0
(byte~) main::$1 reg byte a 22.0
(byte~) main::$2 reg byte a 22.0
(byte~) main::$3 reg byte a 22.0
(label) main::@1
(label) main::@return
(byte) main::i
(byte) main::i#1 i zp ZP_BYTE:2 16.5
(byte) main::i#2 i zp ZP_BYTE:2 4.888888888888889
(byte*) main::screen
(byte*) main::screen#1 screen zp ZP_WORD:3 8.25
(byte*) main::screen#2 screen zp ZP_WORD:3 7.333333333333333
(byte*) main::screen#3 screen zp ZP_WORD:3 8.25
zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
zp ZP_WORD:3 [ main::screen#3 main::screen#2 main::screen#1 ]
reg byte a [ main::$0 ]
reg byte a [ main::$1 ]
reg byte a [ main::$2 ]
reg byte a [ main::$3 ]
FINAL ASSEMBLER
Score: 871
//SEG0 File Comments
// Tests optimization of identical sub-expressions
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//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: {
.label screen = 3
.label i = 2
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
//SEG12 [5] phi (byte*) main::screen#3 = (byte*) 1024 [phi:main->main::@1#0] -- pbuz1=pbuc1
lda #<$400
sta screen
lda #>$400
sta screen+1
//SEG13 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#1] -- vbuz1=vbuc1
lda #0
sta i
//SEG14 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
//SEG15 [5] phi (byte*) main::screen#3 = (byte*) main::screen#2 [phi:main::@1->main::@1#0] -- register_copy
//SEG16 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#1] -- register_copy
//SEG17 main::@1
b1:
//SEG18 [6] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1 -- vbuaa=vbuz1_plus_1
lda i
clc
adc #1
//SEG19 [7] (byte~) main::$1 ← (byte~) main::$0 << (byte) 1 -- vbuaa=vbuaa_rol_1
asl
//SEG20 [8] *((byte*) main::screen#3) ← (byte~) main::$1 -- _deref_pbuz1=vbuaa
ldy #0
sta (screen),y
//SEG21 [9] (byte*) main::screen#1 ← ++ (byte*) main::screen#3 -- pbuz1=_inc_pbuz1
inc screen
bne !+
inc screen+1
!:
//SEG22 [10] (byte~) main::$2 ← (byte) main::i#2 + (byte) 1 -- vbuaa=vbuz1_plus_1
lda i
clc
adc #1
//SEG23 [11] (byte~) main::$3 ← (byte~) main::$2 << (byte) 1 -- vbuaa=vbuaa_rol_1
asl
//SEG24 [12] *((byte*) main::screen#1) ← (byte~) main::$3 -- _deref_pbuz1=vbuaa
ldy #0
sta (screen),y
//SEG25 [13] (byte*) main::screen#2 ← ++ (byte*) main::screen#1 -- pbuz1=_inc_pbuz1
inc screen
bne !+
inc screen+1
!:
//SEG26 [14] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG27 [15] if((byte) main::i#1!=(byte) 3) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda #3
cmp i
bne b1
//SEG28 main::@return
//SEG29 [16] return
rts
}

View File

@ -0,0 +1 @@
program

View File

@ -0,0 +1,43 @@
// Tests optimization of identical sub-expressions
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
main: {
.label _3 = 4
.label screen = 2
lda #<$400
sta screen
lda #>$400
sta screen+1
ldx #0
b1:
txa
asl
sta _3
txa
clc
adc _3
clc
adc #3
ldy #0
sta (screen),y
inc screen
bne !+
inc screen+1
!:
txa
clc
adc _3
clc
adc #3
ldy #0
sta (screen),y
inc screen
bne !+
inc screen+1
!:
inx
cpx #3
bne b1
rts
}

View File

@ -0,0 +1,30 @@
@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()
to:main::@1
main::@1: scope:[main] from main main::@1
[5] (byte*) main::screen#3 ← phi( main/(byte*) 1024 main::@1/(byte*) main::screen#2 )
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 )
[6] (byte~) main::$3 ← (byte) main::i#2 << (byte) 1
[7] (byte~) main::$1 ← (byte~) main::$3 + (byte) main::i#2
[8] (byte~) main::$2 ← (byte~) main::$1 + (byte) 3
[9] *((byte*) main::screen#3) ← (byte~) main::$2
[10] (byte*) main::screen#1 ← ++ (byte*) main::screen#3
[11] (byte~) main::$4 ← (byte~) main::$3 + (byte) main::i#2
[12] (byte~) main::$5 ← (byte~) main::$4 + (byte) 3
[13] *((byte*) main::screen#1) ← (byte~) main::$5
[14] (byte*) main::screen#2 ← ++ (byte*) main::screen#1
[15] (byte) main::i#1 ← ++ (byte) main::i#2
[16] if((byte) main::i#1!=(byte) 3) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[17] return
to:@return

View File

@ -0,0 +1,589 @@
Adding pointer type conversion cast (byte*) main::screen in (byte*) main::screen ← (number) $400
Culled Empty Block (label) main::@2
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@1
main: scope:[main] from @1
(byte*) main::screen#0 ← ((byte*)) (number) $400
(byte) main::i#0 ← (byte) 0
to:main::@1
main::@1: scope:[main] from main main::@1
(byte*) main::screen#3 ← phi( main/(byte*) main::screen#0 main::@1/(byte*) main::screen#2 )
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 )
(number~) main::$0 ← (byte) main::i#2 * (number) 2
(number~) main::$1 ← (number~) main::$0 + (byte) main::i#2
(number~) main::$2 ← (number~) main::$1 + (number) 3
*((byte*) main::screen#3) ← (number~) main::$2
(byte*) main::screen#1 ← ++ (byte*) main::screen#3
(number~) main::$3 ← (byte) main::i#2 * (number) 2
(number~) main::$4 ← (number~) main::$3 + (byte) main::i#2
(number~) main::$5 ← (number~) main::$4 + (number) 3
*((byte*) main::screen#1) ← (number~) main::$5
(byte*) main::screen#2 ← ++ (byte*) main::screen#1
(byte) main::i#1 ← (byte) main::i#2 + rangenext(0,2)
(bool~) main::$6 ← (byte) main::i#1 != rangelast(0,2)
if((bool~) main::$6) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
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()) main()
(number~) main::$0
(number~) main::$1
(number~) main::$2
(number~) main::$3
(number~) main::$4
(number~) main::$5
(bool~) main::$6
(label) main::@1
(label) main::@return
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
(byte*) main::screen
(byte*) main::screen#0
(byte*) main::screen#1
(byte*) main::screen#2
(byte*) main::screen#3
Adding number conversion cast (unumber) 2 in (number~) main::$0 ← (byte) main::i#2 * (number) 2
Adding number conversion cast (unumber) main::$0 in (number~) main::$0 ← (byte) main::i#2 * (unumber)(number) 2
Adding number conversion cast (unumber) main::$1 in (number~) main::$1 ← (unumber~) main::$0 + (byte) main::i#2
Adding number conversion cast (unumber) 3 in (number~) main::$2 ← (unumber~) main::$1 + (number) 3
Adding number conversion cast (unumber) main::$2 in (number~) main::$2 ← (unumber~) main::$1 + (unumber)(number) 3
Adding number conversion cast (unumber) 2 in (number~) main::$3 ← (byte) main::i#2 * (number) 2
Adding number conversion cast (unumber) main::$3 in (number~) main::$3 ← (byte) main::i#2 * (unumber)(number) 2
Adding number conversion cast (unumber) main::$4 in (number~) main::$4 ← (unumber~) main::$3 + (byte) main::i#2
Adding number conversion cast (unumber) 3 in (number~) main::$5 ← (unumber~) main::$4 + (number) 3
Adding number conversion cast (unumber) main::$5 in (number~) main::$5 ← (unumber~) main::$4 + (unumber)(number) 3
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (byte*) main::screen#0 ← (byte*)(number) $400
Successful SSA optimization Pass2InlineCast
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 2
Simplifying constant integer cast 3
Simplifying constant integer cast 2
Simplifying constant integer cast 3
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 2
Finalized unsigned number type (byte) 3
Finalized unsigned number type (byte) 2
Finalized unsigned number type (byte) 3
Successful SSA optimization PassNFinalizeNumberTypeConversions
Inferred type updated to byte in (unumber~) main::$0 ← (byte) main::i#2 * (byte) 2
Inferred type updated to byte in (unumber~) main::$1 ← (byte~) main::$0 + (byte) main::i#2
Inferred type updated to byte in (unumber~) main::$2 ← (byte~) main::$1 + (byte) 3
Inferred type updated to byte in (unumber~) main::$3 ← (byte) main::i#2 * (byte) 2
Inferred type updated to byte in (unumber~) main::$4 ← (byte~) main::$3 + (byte) main::i#2
Inferred type updated to byte in (unumber~) main::$5 ← (byte~) main::$4 + (byte) 3
Identified duplicate assignment right side [8] (byte~) main::$3 ← (byte) main::i#2 * (byte) 2
Successful SSA optimization Pass2DuplicateRValueIdentification
Simple Condition (bool~) main::$6 [15] if((byte) main::i#1!=rangelast(0,2)) goto main::@1
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const byte*) main::screen#0 = (byte*) 1024
Constant (const byte) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Resolved ranged next value [13] main::i#1 ← ++ main::i#2 to ++
Resolved ranged comparison value [15] if(main::i#1!=rangelast(0,2)) goto main::@1 to (number) 3
Adding number conversion cast (unumber) 3 in if((byte) main::i#1!=(number) 3) goto main::@1
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant integer cast 3
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 3
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias (byte~) main::$3 = (byte~) main::$0
Successful SSA optimization Pass2AliasElimination
Rewriting multiplication to use shift [1] (byte~) main::$3 ← (byte) main::i#2 * (byte) 2
Successful SSA optimization Pass2MultiplyToShiftRewriting
Inlining constant with var siblings (const byte*) main::screen#0
Inlining constant with var siblings (const byte) main::i#0
Constant inlined main::screen#0 = (byte*) 1024
Constant inlined main::i#0 = (byte) 0
Successful SSA optimization Pass2ConstantInlining
Added new block during phi lifting main::@3(between main::@1 and main::@1)
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
CALL GRAPH
Calls in [] to main:2
Created 2 initial phi equivalence classes
Coalesced [19] main::i#3 ← main::i#1
Coalesced [20] main::screen#4 ← main::screen#2
Coalesced down to 2 phi equivalence classes
Culled Empty Block (label) @2
Culled Empty Block (label) main::@3
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@1
[5] (byte*) main::screen#3 ← phi( main/(byte*) 1024 main::@1/(byte*) main::screen#2 )
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 )
[6] (byte~) main::$3 ← (byte) main::i#2 << (byte) 1
[7] (byte~) main::$1 ← (byte~) main::$3 + (byte) main::i#2
[8] (byte~) main::$2 ← (byte~) main::$1 + (byte) 3
[9] *((byte*) main::screen#3) ← (byte~) main::$2
[10] (byte*) main::screen#1 ← ++ (byte*) main::screen#3
[11] (byte~) main::$4 ← (byte~) main::$3 + (byte) main::i#2
[12] (byte~) main::$5 ← (byte~) main::$4 + (byte) 3
[13] *((byte*) main::screen#1) ← (byte~) main::$5
[14] (byte*) main::screen#2 ← ++ (byte*) main::screen#1
[15] (byte) main::i#1 ← ++ (byte) main::i#2
[16] if((byte) main::i#1!=(byte) 3) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[17] return
to:@return
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte~) main::$1 22.0
(byte~) main::$2 22.0
(byte~) main::$3 6.6000000000000005
(byte~) main::$4 22.0
(byte~) main::$5 22.0
(byte) main::i
(byte) main::i#1 16.5
(byte) main::i#2 5.5
(byte*) main::screen
(byte*) main::screen#1 8.25
(byte*) main::screen#2 7.333333333333333
(byte*) main::screen#3 6.6000000000000005
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
[ main::screen#3 main::screen#2 ]
Added variable main::$3 to zero page equivalence class [ main::$3 ]
Added variable main::$1 to zero page equivalence class [ main::$1 ]
Added variable main::$2 to zero page equivalence class [ main::$2 ]
Added variable main::screen#1 to zero page equivalence class [ main::screen#1 ]
Added variable main::$4 to zero page equivalence class [ main::$4 ]
Added variable main::$5 to zero page equivalence class [ main::$5 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ main::screen#3 main::screen#2 ]
[ main::$3 ]
[ main::$1 ]
[ main::$2 ]
[ main::screen#1 ]
[ main::$4 ]
[ main::$5 ]
Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Allocated zp ZP_WORD:3 [ main::screen#3 main::screen#2 ]
Allocated zp ZP_BYTE:5 [ main::$3 ]
Allocated zp ZP_BYTE:6 [ main::$1 ]
Allocated zp ZP_BYTE:7 [ main::$2 ]
Allocated zp ZP_WORD:8 [ main::screen#1 ]
Allocated zp ZP_BYTE:10 [ main::$4 ]
Allocated zp ZP_BYTE:11 [ main::$5 ]
INITIAL ASM
//SEG0 File Comments
// Tests optimization of identical sub-expressions
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//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: {
.label _1 = 6
.label _2 = 7
.label _3 = 5
.label _4 = $a
.label _5 = $b
.label screen = 8
.label screen_2 = 3
.label i = 2
.label screen_3 = 3
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
//SEG12 [5] phi (byte*) main::screen#3 = (byte*) 1024 [phi:main->main::@1#0] -- pbuz1=pbuc1
lda #<$400
sta screen_3
lda #>$400
sta screen_3+1
//SEG13 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#1] -- vbuz1=vbuc1
lda #0
sta i
jmp b1
//SEG14 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
b1_from_b1:
//SEG15 [5] phi (byte*) main::screen#3 = (byte*) main::screen#2 [phi:main::@1->main::@1#0] -- register_copy
//SEG16 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#1] -- register_copy
jmp b1
//SEG17 main::@1
b1:
//SEG18 [6] (byte~) main::$3 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuz2_rol_1
lda i
asl
sta _3
//SEG19 [7] (byte~) main::$1 ← (byte~) main::$3 + (byte) main::i#2 -- vbuz1=vbuz2_plus_vbuz3
lda _3
clc
adc i
sta _1
//SEG20 [8] (byte~) main::$2 ← (byte~) main::$1 + (byte) 3 -- vbuz1=vbuz2_plus_vbuc1
lax _1
axs #-[3]
stx _2
//SEG21 [9] *((byte*) main::screen#3) ← (byte~) main::$2 -- _deref_pbuz1=vbuz2
lda _2
ldy #0
sta (screen_3),y
//SEG22 [10] (byte*) main::screen#1 ← ++ (byte*) main::screen#3 -- pbuz1=_inc_pbuz2
lda screen_3
clc
adc #1
sta screen
lda screen_3+1
adc #0
sta screen+1
//SEG23 [11] (byte~) main::$4 ← (byte~) main::$3 + (byte) main::i#2 -- vbuz1=vbuz2_plus_vbuz3
lda _3
clc
adc i
sta _4
//SEG24 [12] (byte~) main::$5 ← (byte~) main::$4 + (byte) 3 -- vbuz1=vbuz2_plus_vbuc1
lax _4
axs #-[3]
stx _5
//SEG25 [13] *((byte*) main::screen#1) ← (byte~) main::$5 -- _deref_pbuz1=vbuz2
lda _5
ldy #0
sta (screen),y
//SEG26 [14] (byte*) main::screen#2 ← ++ (byte*) main::screen#1 -- pbuz1=_inc_pbuz2
lda screen
clc
adc #1
sta screen_2
lda screen+1
adc #0
sta screen_2+1
//SEG27 [15] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG28 [16] if((byte) main::i#1!=(byte) 3) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda #3
cmp i
bne b1_from_b1
jmp breturn
//SEG29 main::@return
breturn:
//SEG30 [17] return
rts
}
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [6] (byte~) main::$3 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::screen#3 main::$3 ] ( main:2 [ main::i#2 main::screen#3 main::$3 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Statement [7] (byte~) main::$1 ← (byte~) main::$3 + (byte) main::i#2 [ main::i#2 main::screen#3 main::$3 main::$1 ] ( main:2 [ main::i#2 main::screen#3 main::$3 main::$1 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:5 [ main::$3 ]
Statement [9] *((byte*) main::screen#3) ← (byte~) main::$2 [ main::i#2 main::screen#3 main::$3 ] ( main:2 [ main::i#2 main::screen#3 main::$3 ] ) always clobbers reg byte y
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:5 [ main::$3 ]
Statement [10] (byte*) main::screen#1 ← ++ (byte*) main::screen#3 [ main::i#2 main::$3 main::screen#1 ] ( main:2 [ main::i#2 main::$3 main::screen#1 ] ) always clobbers reg byte a
Statement [11] (byte~) main::$4 ← (byte~) main::$3 + (byte) main::i#2 [ main::i#2 main::screen#1 main::$4 ] ( main:2 [ main::i#2 main::screen#1 main::$4 ] ) always clobbers reg byte a
Statement [13] *((byte*) main::screen#1) ← (byte~) main::$5 [ main::i#2 main::screen#1 ] ( main:2 [ main::i#2 main::screen#1 ] ) always clobbers reg byte y
Statement [14] (byte*) main::screen#2 ← ++ (byte*) main::screen#1 [ main::i#2 main::screen#2 ] ( main:2 [ main::i#2 main::screen#2 ] ) always clobbers reg byte a
Statement [6] (byte~) main::$3 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::screen#3 main::$3 ] ( main:2 [ main::i#2 main::screen#3 main::$3 ] ) always clobbers reg byte a
Statement [7] (byte~) main::$1 ← (byte~) main::$3 + (byte) main::i#2 [ main::i#2 main::screen#3 main::$3 main::$1 ] ( main:2 [ main::i#2 main::screen#3 main::$3 main::$1 ] ) always clobbers reg byte a
Statement [9] *((byte*) main::screen#3) ← (byte~) main::$2 [ main::i#2 main::screen#3 main::$3 ] ( main:2 [ main::i#2 main::screen#3 main::$3 ] ) always clobbers reg byte y
Statement [10] (byte*) main::screen#1 ← ++ (byte*) main::screen#3 [ main::i#2 main::$3 main::screen#1 ] ( main:2 [ main::i#2 main::$3 main::screen#1 ] ) always clobbers reg byte a
Statement [11] (byte~) main::$4 ← (byte~) main::$3 + (byte) main::i#2 [ main::i#2 main::screen#1 main::$4 ] ( main:2 [ main::i#2 main::screen#1 main::$4 ] ) always clobbers reg byte a
Statement [13] *((byte*) main::screen#1) ← (byte~) main::$5 [ main::i#2 main::screen#1 ] ( main:2 [ main::i#2 main::screen#1 ] ) always clobbers reg byte y
Statement [14] (byte*) main::screen#2 ← ++ (byte*) main::screen#1 [ main::i#2 main::screen#2 ] ( main:2 [ main::i#2 main::screen#2 ] ) always clobbers reg byte a
Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte x ,
Potential registers zp ZP_WORD:3 [ main::screen#3 main::screen#2 ] : zp ZP_WORD:3 ,
Potential registers zp ZP_BYTE:5 [ main::$3 ] : zp ZP_BYTE:5 , reg byte x ,
Potential registers zp ZP_BYTE:6 [ main::$1 ] : zp ZP_BYTE:6 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:7 [ main::$2 ] : zp ZP_BYTE:7 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_WORD:8 [ main::screen#1 ] : zp ZP_WORD:8 ,
Potential registers zp ZP_BYTE:10 [ main::$4 ] : zp ZP_BYTE:10 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:11 [ main::$5 ] : zp ZP_BYTE:11 , reg byte a , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 22: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 22: zp ZP_BYTE:6 [ main::$1 ] 22: zp ZP_BYTE:7 [ main::$2 ] 22: zp ZP_BYTE:10 [ main::$4 ] 22: zp ZP_BYTE:11 [ main::$5 ] 13.93: zp ZP_WORD:3 [ main::screen#3 main::screen#2 ] 8.25: zp ZP_WORD:8 [ main::screen#1 ] 6.6: zp ZP_BYTE:5 [ main::$3 ]
Uplift Scope []
Uplifting [main] best 1163 combination reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::$1 ] reg byte a [ main::$2 ] reg byte a [ main::$4 ] zp ZP_BYTE:11 [ main::$5 ] zp ZP_WORD:3 [ main::screen#3 main::screen#2 ] zp ZP_WORD:8 [ main::screen#1 ] zp ZP_BYTE:5 [ main::$3 ]
Limited combination testing to 100 combinations of 1024 possible.
Uplifting [] best 1163 combination
Attempting to uplift remaining variables inzp ZP_BYTE:11 [ main::$5 ]
Uplifting [main] best 1103 combination reg byte a [ main::$5 ]
Attempting to uplift remaining variables inzp ZP_BYTE:5 [ main::$3 ]
Uplifting [main] best 1103 combination zp ZP_BYTE:5 [ main::$3 ]
Coalescing zero page register with common assignment [ zp ZP_WORD:3 [ main::screen#3 main::screen#2 ] ] with [ zp ZP_WORD:8 [ main::screen#1 ] ] - score: 2
Allocated (was zp ZP_WORD:3) zp ZP_WORD:2 [ main::screen#3 main::screen#2 main::screen#1 ]
Allocated (was zp ZP_BYTE:5) zp ZP_BYTE:4 [ main::$3 ]
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Tests optimization of identical sub-expressions
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//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: {
.label _3 = 4
.label screen = 2
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
//SEG12 [5] phi (byte*) main::screen#3 = (byte*) 1024 [phi:main->main::@1#0] -- pbuz1=pbuc1
lda #<$400
sta screen
lda #>$400
sta screen+1
//SEG13 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1
ldx #0
jmp b1
//SEG14 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
b1_from_b1:
//SEG15 [5] phi (byte*) main::screen#3 = (byte*) main::screen#2 [phi:main::@1->main::@1#0] -- register_copy
//SEG16 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#1] -- register_copy
jmp b1
//SEG17 main::@1
b1:
//SEG18 [6] (byte~) main::$3 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuxx_rol_1
txa
asl
sta _3
//SEG19 [7] (byte~) main::$1 ← (byte~) main::$3 + (byte) main::i#2 -- vbuaa=vbuz1_plus_vbuxx
txa
clc
adc _3
//SEG20 [8] (byte~) main::$2 ← (byte~) main::$1 + (byte) 3 -- vbuaa=vbuaa_plus_vbuc1
clc
adc #3
//SEG21 [9] *((byte*) main::screen#3) ← (byte~) main::$2 -- _deref_pbuz1=vbuaa
ldy #0
sta (screen),y
//SEG22 [10] (byte*) main::screen#1 ← ++ (byte*) main::screen#3 -- pbuz1=_inc_pbuz1
inc screen
bne !+
inc screen+1
!:
//SEG23 [11] (byte~) main::$4 ← (byte~) main::$3 + (byte) main::i#2 -- vbuaa=vbuz1_plus_vbuxx
txa
clc
adc _3
//SEG24 [12] (byte~) main::$5 ← (byte~) main::$4 + (byte) 3 -- vbuaa=vbuaa_plus_vbuc1
clc
adc #3
//SEG25 [13] *((byte*) main::screen#1) ← (byte~) main::$5 -- _deref_pbuz1=vbuaa
ldy #0
sta (screen),y
//SEG26 [14] (byte*) main::screen#2 ← ++ (byte*) main::screen#1 -- pbuz1=_inc_pbuz1
inc screen
bne !+
inc screen+1
!:
//SEG27 [15] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
//SEG28 [16] if((byte) main::i#1!=(byte) 3) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #3
bne b1_from_b1
jmp breturn
//SEG29 main::@return
breturn:
//SEG30 [17] return
rts
}
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp b1
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing label b1_from_b1 with b1
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction main_from_b1:
Removing instruction bend_from_b1:
Removing instruction b1_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction b1_from_main:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction jmp b1
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(void()) main()
(byte~) main::$1 reg byte a 22.0
(byte~) main::$2 reg byte a 22.0
(byte~) main::$3 $3 zp ZP_BYTE:4 6.6000000000000005
(byte~) main::$4 reg byte a 22.0
(byte~) main::$5 reg byte a 22.0
(label) main::@1
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte x 16.5
(byte) main::i#2 reg byte x 5.5
(byte*) main::screen
(byte*) main::screen#1 screen zp ZP_WORD:2 8.25
(byte*) main::screen#2 screen zp ZP_WORD:2 7.333333333333333
(byte*) main::screen#3 screen zp ZP_WORD:2 6.6000000000000005
reg byte x [ main::i#2 main::i#1 ]
zp ZP_WORD:2 [ main::screen#3 main::screen#2 main::screen#1 ]
zp ZP_BYTE:4 [ main::$3 ]
reg byte a [ main::$1 ]
reg byte a [ main::$2 ]
reg byte a [ main::$4 ]
reg byte a [ main::$5 ]
FINAL ASSEMBLER
Score: 891
//SEG0 File Comments
// Tests optimization of identical sub-expressions
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//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: {
.label _3 = 4
.label screen = 2
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
//SEG12 [5] phi (byte*) main::screen#3 = (byte*) 1024 [phi:main->main::@1#0] -- pbuz1=pbuc1
lda #<$400
sta screen
lda #>$400
sta screen+1
//SEG13 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1
ldx #0
//SEG14 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
//SEG15 [5] phi (byte*) main::screen#3 = (byte*) main::screen#2 [phi:main::@1->main::@1#0] -- register_copy
//SEG16 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#1] -- register_copy
//SEG17 main::@1
b1:
//SEG18 [6] (byte~) main::$3 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuxx_rol_1
txa
asl
sta _3
//SEG19 [7] (byte~) main::$1 ← (byte~) main::$3 + (byte) main::i#2 -- vbuaa=vbuz1_plus_vbuxx
txa
clc
adc _3
//SEG20 [8] (byte~) main::$2 ← (byte~) main::$1 + (byte) 3 -- vbuaa=vbuaa_plus_vbuc1
clc
adc #3
//SEG21 [9] *((byte*) main::screen#3) ← (byte~) main::$2 -- _deref_pbuz1=vbuaa
ldy #0
sta (screen),y
//SEG22 [10] (byte*) main::screen#1 ← ++ (byte*) main::screen#3 -- pbuz1=_inc_pbuz1
inc screen
bne !+
inc screen+1
!:
//SEG23 [11] (byte~) main::$4 ← (byte~) main::$3 + (byte) main::i#2 -- vbuaa=vbuz1_plus_vbuxx
txa
clc
adc _3
//SEG24 [12] (byte~) main::$5 ← (byte~) main::$4 + (byte) 3 -- vbuaa=vbuaa_plus_vbuc1
clc
adc #3
//SEG25 [13] *((byte*) main::screen#1) ← (byte~) main::$5 -- _deref_pbuz1=vbuaa
ldy #0
sta (screen),y
//SEG26 [14] (byte*) main::screen#2 ← ++ (byte*) main::screen#1 -- pbuz1=_inc_pbuz1
inc screen
bne !+
inc screen+1
!:
//SEG27 [15] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
//SEG28 [16] if((byte) main::i#1!=(byte) 3) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #3
bne b1
//SEG29 main::@return
//SEG30 [17] return
rts
}

View File

@ -0,0 +1 @@
program

View File

@ -0,0 +1,55 @@
// Tests optimization of identical sub-expressions
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
main: {
.label screen = 2
lda #<$400
sta screen
lda #>$400
sta screen+1
ldx #0
b1:
txa
and #1
cmp #0
bne b2
txa
asl
asl
b4:
ldy #0
sta (screen),y
inc screen
bne !+
inc screen+1
!:
txa
and #1
cmp #0
bne b5
txa
asl
asl
b7:
ldy #0
sta (screen),y
inc screen
bne !+
inc screen+1
!:
inx
cpx #3
bne b1
rts
b5:
txa
clc
adc #3
jmp b7
b2:
txa
clc
adc #3
jmp b4
}

View File

@ -0,0 +1,47 @@
@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()
to:main::@1
main::@1: scope:[main] from main main::@7
[5] (byte*) main::screen#3 ← phi( main/(byte*) 1024 main::@7/(byte*) main::screen#2 )
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@7/(byte) main::i#1 )
[6] (byte~) main::$0 ← (byte) main::i#2 & (byte) 1
[7] if((byte) 0!=(byte~) main::$0) goto main::@2
to:main::@3
main::@3: scope:[main] from main::@1
[8] (byte~) main::$2 ← (byte) main::i#2 << (byte) 2
to:main::@4
main::@4: scope:[main] from main::@2 main::@3
[9] (byte~) main::$5 ← phi( main::@2/(byte~) main::$4 main::@3/(byte~) main::$2 )
[10] *((byte*) main::screen#3) ← (byte~) main::$5
[11] (byte*) main::screen#1 ← ++ (byte*) main::screen#3
[12] (byte~) main::$6 ← (byte) main::i#2 & (byte) 1
[13] if((byte) 0!=(byte~) main::$6) goto main::@5
to:main::@6
main::@6: scope:[main] from main::@4
[14] (byte~) main::$8 ← (byte) main::i#2 << (byte) 2
to:main::@7
main::@7: scope:[main] from main::@5 main::@6
[15] (byte~) main::$11 ← phi( main::@5/(byte~) main::$10 main::@6/(byte~) main::$8 )
[16] *((byte*) main::screen#1) ← (byte~) main::$11
[17] (byte*) main::screen#2 ← ++ (byte*) main::screen#1
[18] (byte) main::i#1 ← ++ (byte) main::i#2
[19] if((byte) main::i#1!=(byte) 3) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@7
[20] return
to:@return
main::@5: scope:[main] from main::@4
[21] (byte~) main::$10 ← (byte) main::i#2 + (byte) 3
to:main::@7
main::@2: scope:[main] from main::@1
[22] (byte~) main::$4 ← (byte) main::i#2 + (byte) 3
to:main::@4

View File

@ -0,0 +1,836 @@
Warning! Adding boolean cast to non-boolean condition (number~) main::$0
Warning! Adding boolean cast to non-boolean condition (number~) main::$6
Adding pointer type conversion cast (byte*) main::screen in (byte*) main::screen ← (number) $400
Culled Empty Block (label) main::@8
Culled Empty Block (label) main::@9
Culled Empty Block (label) main::@10
Culled Empty Block (label) main::@11
Culled Empty Block (label) main::@12
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@1
main: scope:[main] from @1
(byte*) main::screen#0 ← ((byte*)) (number) $400
(byte) main::i#0 ← (byte) 0
to:main::@1
main::@1: scope:[main] from main main::@7
(byte*) main::screen#9 ← phi( main/(byte*) main::screen#0 main::@7/(byte*) main::screen#2 )
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@7/(byte) main::i#1 )
(number~) main::$0 ← (byte) main::i#2 & (number) 1
(bool~) main::$13 ← (number) 0 != (number~) main::$0
if((bool~) main::$13) goto main::@2
to:main::@3
main::@2: scope:[main] from main::@1
(byte*) main::screen#5 ← phi( main::@1/(byte*) main::screen#9 )
(byte) main::i#3 ← phi( main::@1/(byte) main::i#2 )
(number~) main::$3 ← (byte) main::i#3 + (number) 3
(number~) main::$4 ← (number~) main::$3
to:main::@4
main::@3: scope:[main] from main::@1
(byte*) main::screen#6 ← phi( main::@1/(byte*) main::screen#9 )
(byte) main::i#4 ← phi( main::@1/(byte) main::i#2 )
(number~) main::$1 ← (byte) main::i#4 * (number) 4
(number~) main::$2 ← (number~) main::$1
to:main::@4
main::@4: scope:[main] from main::@2 main::@3
(byte) main::i#5 ← phi( main::@2/(byte) main::i#3 main::@3/(byte) main::i#4 )
(byte*) main::screen#3 ← phi( main::@2/(byte*) main::screen#5 main::@3/(byte*) main::screen#6 )
(number~) main::$5 ← phi( main::@2/(number~) main::$4 main::@3/(number~) main::$2 )
*((byte*) main::screen#3) ← (number~) main::$5
(byte*) main::screen#1 ← ++ (byte*) main::screen#3
(number~) main::$6 ← (byte) main::i#5 & (number) 1
(bool~) main::$14 ← (number) 0 != (number~) main::$6
if((bool~) main::$14) goto main::@5
to:main::@6
main::@5: scope:[main] from main::@4
(byte*) main::screen#7 ← phi( main::@4/(byte*) main::screen#1 )
(byte) main::i#6 ← phi( main::@4/(byte) main::i#5 )
(number~) main::$9 ← (byte) main::i#6 + (number) 3
(number~) main::$10 ← (number~) main::$9
to:main::@7
main::@6: scope:[main] from main::@4
(byte*) main::screen#8 ← phi( main::@4/(byte*) main::screen#1 )
(byte) main::i#7 ← phi( main::@4/(byte) main::i#5 )
(number~) main::$7 ← (byte) main::i#7 * (number) 4
(number~) main::$8 ← (number~) main::$7
to:main::@7
main::@7: scope:[main] from main::@5 main::@6
(byte) main::i#8 ← phi( main::@5/(byte) main::i#6 main::@6/(byte) main::i#7 )
(byte*) main::screen#4 ← phi( main::@5/(byte*) main::screen#7 main::@6/(byte*) main::screen#8 )
(number~) main::$11 ← phi( main::@5/(number~) main::$10 main::@6/(number~) main::$8 )
*((byte*) main::screen#4) ← (number~) main::$11
(byte*) main::screen#2 ← ++ (byte*) main::screen#4
(byte) main::i#1 ← (byte) main::i#8 + rangenext(0,2)
(bool~) main::$12 ← (byte) main::i#1 != rangelast(0,2)
if((bool~) main::$12) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@7
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()) main()
(number~) main::$0
(number~) main::$1
(number~) main::$10
(number~) main::$11
(bool~) main::$12
(bool~) main::$13
(bool~) main::$14
(number~) main::$2
(number~) main::$3
(number~) main::$4
(number~) main::$5
(number~) main::$6
(number~) main::$7
(number~) main::$8
(number~) main::$9
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@4
(label) main::@5
(label) main::@6
(label) main::@7
(label) main::@return
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
(byte) main::i#3
(byte) main::i#4
(byte) main::i#5
(byte) main::i#6
(byte) main::i#7
(byte) main::i#8
(byte*) main::screen
(byte*) main::screen#0
(byte*) main::screen#1
(byte*) main::screen#2
(byte*) main::screen#3
(byte*) main::screen#4
(byte*) main::screen#5
(byte*) main::screen#6
(byte*) main::screen#7
(byte*) main::screen#8
(byte*) main::screen#9
Adding number conversion cast (unumber) 1 in (number~) main::$0 ← (byte) main::i#2 & (number) 1
Adding number conversion cast (unumber) main::$0 in (number~) main::$0 ← (byte) main::i#2 & (unumber)(number) 1
Adding number conversion cast (unumber) 0 in (bool~) main::$13 ← (number) 0 != (unumber~) main::$0
Adding number conversion cast (unumber) 3 in (number~) main::$3 ← (byte) main::i#3 + (number) 3
Adding number conversion cast (unumber) main::$3 in (number~) main::$3 ← (byte) main::i#3 + (unumber)(number) 3
Adding number conversion cast (unumber) main::$4 in (number~) main::$4 ← (unumber~) main::$3
Adding number conversion cast (unumber) 4 in (number~) main::$1 ← (byte) main::i#4 * (number) 4
Adding number conversion cast (unumber) main::$1 in (number~) main::$1 ← (byte) main::i#4 * (unumber)(number) 4
Adding number conversion cast (unumber) main::$2 in (number~) main::$2 ← (unumber~) main::$1
Adding number conversion cast (unumber) main::$5 in (byte) main::i#5 ← phi( main::@2/(byte) main::i#3 main::@3/(byte) main::i#4 )
(byte*) main::screen#3 ← phi( main::@2/(byte*) main::screen#5 main::@3/(byte*) main::screen#6 )
(number~) main::$5 ← phi( main::@2/(unumber~) main::$4 main::@3/(unumber~) main::$2 )
Adding number conversion cast (unumber) 1 in (number~) main::$6 ← (byte) main::i#5 & (number) 1
Adding number conversion cast (unumber) main::$6 in (number~) main::$6 ← (byte) main::i#5 & (unumber)(number) 1
Adding number conversion cast (unumber) 0 in (bool~) main::$14 ← (number) 0 != (unumber~) main::$6
Adding number conversion cast (unumber) 3 in (number~) main::$9 ← (byte) main::i#6 + (number) 3
Adding number conversion cast (unumber) main::$9 in (number~) main::$9 ← (byte) main::i#6 + (unumber)(number) 3
Adding number conversion cast (unumber) main::$10 in (number~) main::$10 ← (unumber~) main::$9
Adding number conversion cast (unumber) 4 in (number~) main::$7 ← (byte) main::i#7 * (number) 4
Adding number conversion cast (unumber) main::$7 in (number~) main::$7 ← (byte) main::i#7 * (unumber)(number) 4
Adding number conversion cast (unumber) main::$8 in (number~) main::$8 ← (unumber~) main::$7
Adding number conversion cast (unumber) main::$11 in (byte) main::i#8 ← phi( main::@5/(byte) main::i#6 main::@6/(byte) main::i#7 )
(byte*) main::screen#4 ← phi( main::@5/(byte*) main::screen#7 main::@6/(byte*) main::screen#8 )
(number~) main::$11 ← phi( main::@5/(unumber~) main::$10 main::@6/(unumber~) main::$8 )
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (byte*) main::screen#0 ← (byte*)(number) $400
Successful SSA optimization Pass2InlineCast
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 1
Simplifying constant integer cast 0
Simplifying constant integer cast 3
Simplifying constant integer cast 4
Simplifying constant integer cast 1
Simplifying constant integer cast 0
Simplifying constant integer cast 3
Simplifying constant integer cast 4
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 3
Finalized unsigned number type (byte) 4
Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 3
Finalized unsigned number type (byte) 4
Successful SSA optimization PassNFinalizeNumberTypeConversions
Inferred type updated to byte in (unumber~) main::$0 ← (byte) main::i#2 & (byte) 1
Inferred type updated to byte in (unumber~) main::$3 ← (byte) main::i#3 + (byte) 3
Inferred type updated to byte in (unumber~) main::$4 ← (byte~) main::$3
Inferred type updated to byte in (unumber~) main::$1 ← (byte) main::i#4 * (byte) 4
Inferred type updated to byte in (unumber~) main::$2 ← (byte~) main::$1
Inferred type updated to byte for (unumber~) main::$5
Inferred type updated to byte in (unumber~) main::$6 ← (byte) main::i#5 & (byte) 1
Inferred type updated to byte in (unumber~) main::$9 ← (byte) main::i#6 + (byte) 3
Inferred type updated to byte in (unumber~) main::$10 ← (byte~) main::$9
Inferred type updated to byte in (unumber~) main::$7 ← (byte) main::i#7 * (byte) 4
Inferred type updated to byte in (unumber~) main::$8 ← (byte~) main::$7
Inferred type updated to byte for (unumber~) main::$11
Alias (byte) main::i#2 = (byte) main::i#3 (byte) main::i#4
Alias (byte*) main::screen#5 = (byte*) main::screen#9 (byte*) main::screen#6
Alias (byte~) main::$4 = (byte~) main::$3
Alias (byte~) main::$2 = (byte~) main::$1
Alias (byte) main::i#5 = (byte) main::i#6 (byte) main::i#7
Alias (byte*) main::screen#1 = (byte*) main::screen#7 (byte*) main::screen#8
Alias (byte~) main::$10 = (byte~) main::$9
Alias (byte~) main::$8 = (byte~) main::$7
Successful SSA optimization Pass2AliasElimination
Alias (byte*) main::screen#3 = (byte*) main::screen#5
Alias (byte) main::i#2 = (byte) main::i#5 (byte) main::i#8
Alias (byte*) main::screen#1 = (byte*) main::screen#4
Successful SSA optimization Pass2AliasElimination
Simple Condition (bool~) main::$13 [5] if((byte) 0!=(byte~) main::$0) goto main::@2
Simple Condition (bool~) main::$14 [17] if((byte) 0!=(byte~) main::$6) goto main::@5
Simple Condition (bool~) main::$12 [29] if((byte) main::i#1!=rangelast(0,2)) goto main::@1
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const byte*) main::screen#0 = (byte*) 1024
Constant (const byte) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Resolved ranged next value [27] main::i#1 ← ++ main::i#2 to ++
Resolved ranged comparison value [29] if(main::i#1!=rangelast(0,2)) goto main::@1 to (number) 3
Adding number conversion cast (unumber) 3 in if((byte) main::i#1!=(number) 3) goto main::@1
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant integer cast 3
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 3
Successful SSA optimization PassNFinalizeNumberTypeConversions
Rewriting multiplication to use shift [4] (byte~) main::$2 ← (byte) main::i#2 * (byte) 4
Rewriting multiplication to use shift [11] (byte~) main::$8 ← (byte) main::i#2 * (byte) 4
Successful SSA optimization Pass2MultiplyToShiftRewriting
Inlining constant with var siblings (const byte*) main::screen#0
Inlining constant with var siblings (const byte) main::i#0
Constant inlined main::screen#0 = (byte*) 1024
Constant inlined main::i#0 = (byte) 0
Successful SSA optimization Pass2ConstantInlining
Added new block during phi lifting main::@13(between main::@7 and main::@1)
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
CALL GRAPH
Calls in [] to main:2
Created 4 initial phi equivalence classes
Coalesced [10] main::$16 ← main::$2
Coalesced [17] main::$18 ← main::$8
Coalesced [24] main::i#9 ← main::i#1
Coalesced [25] main::screen#10 ← main::screen#2
Coalesced [27] main::$17 ← main::$10
Coalesced [29] main::$15 ← main::$4
Coalesced down to 4 phi equivalence classes
Culled Empty Block (label) @2
Culled Empty Block (label) main::@13
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@7
[5] (byte*) main::screen#3 ← phi( main/(byte*) 1024 main::@7/(byte*) main::screen#2 )
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@7/(byte) main::i#1 )
[6] (byte~) main::$0 ← (byte) main::i#2 & (byte) 1
[7] if((byte) 0!=(byte~) main::$0) goto main::@2
to:main::@3
main::@3: scope:[main] from main::@1
[8] (byte~) main::$2 ← (byte) main::i#2 << (byte) 2
to:main::@4
main::@4: scope:[main] from main::@2 main::@3
[9] (byte~) main::$5 ← phi( main::@2/(byte~) main::$4 main::@3/(byte~) main::$2 )
[10] *((byte*) main::screen#3) ← (byte~) main::$5
[11] (byte*) main::screen#1 ← ++ (byte*) main::screen#3
[12] (byte~) main::$6 ← (byte) main::i#2 & (byte) 1
[13] if((byte) 0!=(byte~) main::$6) goto main::@5
to:main::@6
main::@6: scope:[main] from main::@4
[14] (byte~) main::$8 ← (byte) main::i#2 << (byte) 2
to:main::@7
main::@7: scope:[main] from main::@5 main::@6
[15] (byte~) main::$11 ← phi( main::@5/(byte~) main::$10 main::@6/(byte~) main::$8 )
[16] *((byte*) main::screen#1) ← (byte~) main::$11
[17] (byte*) main::screen#2 ← ++ (byte*) main::screen#1
[18] (byte) main::i#1 ← ++ (byte) main::i#2
[19] if((byte) main::i#1!=(byte) 3) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@7
[20] return
to:@return
main::@5: scope:[main] from main::@4
[21] (byte~) main::$10 ← (byte) main::i#2 + (byte) 3
to:main::@7
main::@2: scope:[main] from main::@1
[22] (byte~) main::$4 ← (byte) main::i#2 + (byte) 3
to:main::@4
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte~) main::$0 22.0
(byte~) main::$10 22.0
(byte~) main::$11 33.0
(byte~) main::$2 22.0
(byte~) main::$4 22.0
(byte~) main::$5 33.0
(byte~) main::$6 22.0
(byte~) main::$8 22.0
(byte) main::i
(byte) main::i#1 16.5
(byte) main::i#2 5.866666666666666
(byte*) main::screen
(byte*) main::screen#1 4.714285714285714
(byte*) main::screen#2 7.333333333333333
(byte*) main::screen#3 4.714285714285714
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
[ main::screen#3 main::screen#2 ]
[ main::$5 main::$4 main::$2 ]
[ main::$11 main::$10 main::$8 ]
Added variable main::$0 to zero page equivalence class [ main::$0 ]
Added variable main::screen#1 to zero page equivalence class [ main::screen#1 ]
Added variable main::$6 to zero page equivalence class [ main::$6 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ main::screen#3 main::screen#2 ]
[ main::$5 main::$4 main::$2 ]
[ main::$11 main::$10 main::$8 ]
[ main::$0 ]
[ main::screen#1 ]
[ main::$6 ]
Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Allocated zp ZP_WORD:3 [ main::screen#3 main::screen#2 ]
Allocated zp ZP_BYTE:5 [ main::$5 main::$4 main::$2 ]
Allocated zp ZP_BYTE:6 [ main::$11 main::$10 main::$8 ]
Allocated zp ZP_BYTE:7 [ main::$0 ]
Allocated zp ZP_WORD:8 [ main::screen#1 ]
Allocated zp ZP_BYTE:10 [ main::$6 ]
INITIAL ASM
//SEG0 File Comments
// Tests optimization of identical sub-expressions
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//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: {
.label _0 = 7
.label _2 = 5
.label _4 = 5
.label _5 = 5
.label _6 = $a
.label _8 = 6
.label _10 = 6
.label _11 = 6
.label screen = 8
.label screen_2 = 3
.label i = 2
.label screen_3 = 3
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
//SEG12 [5] phi (byte*) main::screen#3 = (byte*) 1024 [phi:main->main::@1#0] -- pbuz1=pbuc1
lda #<$400
sta screen_3
lda #>$400
sta screen_3+1
//SEG13 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#1] -- vbuz1=vbuc1
lda #0
sta i
jmp b1
//SEG14 [5] phi from main::@7 to main::@1 [phi:main::@7->main::@1]
b1_from_b7:
//SEG15 [5] phi (byte*) main::screen#3 = (byte*) main::screen#2 [phi:main::@7->main::@1#0] -- register_copy
//SEG16 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@7->main::@1#1] -- register_copy
jmp b1
//SEG17 main::@1
b1:
//SEG18 [6] (byte~) main::$0 ← (byte) main::i#2 & (byte) 1 -- vbuz1=vbuz2_band_vbuc1
lda #1
and i
sta _0
//SEG19 [7] if((byte) 0!=(byte~) main::$0) goto main::@2 -- vbuc1_neq_vbuz1_then_la1
lda #0
cmp _0
bne b2
jmp b3
//SEG20 main::@3
b3:
//SEG21 [8] (byte~) main::$2 ← (byte) main::i#2 << (byte) 2 -- vbuz1=vbuz2_rol_2
lda i
asl
asl
sta _2
//SEG22 [9] phi from main::@2 main::@3 to main::@4 [phi:main::@2/main::@3->main::@4]
b4_from_b2:
b4_from_b3:
//SEG23 [9] phi (byte~) main::$5 = (byte~) main::$4 [phi:main::@2/main::@3->main::@4#0] -- register_copy
jmp b4
//SEG24 main::@4
b4:
//SEG25 [10] *((byte*) main::screen#3) ← (byte~) main::$5 -- _deref_pbuz1=vbuz2
lda _5
ldy #0
sta (screen_3),y
//SEG26 [11] (byte*) main::screen#1 ← ++ (byte*) main::screen#3 -- pbuz1=_inc_pbuz2
lda screen_3
clc
adc #1
sta screen
lda screen_3+1
adc #0
sta screen+1
//SEG27 [12] (byte~) main::$6 ← (byte) main::i#2 & (byte) 1 -- vbuz1=vbuz2_band_vbuc1
lda #1
and i
sta _6
//SEG28 [13] if((byte) 0!=(byte~) main::$6) goto main::@5 -- vbuc1_neq_vbuz1_then_la1
lda #0
cmp _6
bne b5
jmp b6
//SEG29 main::@6
b6:
//SEG30 [14] (byte~) main::$8 ← (byte) main::i#2 << (byte) 2 -- vbuz1=vbuz2_rol_2
lda i
asl
asl
sta _8
//SEG31 [15] phi from main::@5 main::@6 to main::@7 [phi:main::@5/main::@6->main::@7]
b7_from_b5:
b7_from_b6:
//SEG32 [15] phi (byte~) main::$11 = (byte~) main::$10 [phi:main::@5/main::@6->main::@7#0] -- register_copy
jmp b7
//SEG33 main::@7
b7:
//SEG34 [16] *((byte*) main::screen#1) ← (byte~) main::$11 -- _deref_pbuz1=vbuz2
lda _11
ldy #0
sta (screen),y
//SEG35 [17] (byte*) main::screen#2 ← ++ (byte*) main::screen#1 -- pbuz1=_inc_pbuz2
lda screen
clc
adc #1
sta screen_2
lda screen+1
adc #0
sta screen_2+1
//SEG36 [18] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG37 [19] if((byte) main::i#1!=(byte) 3) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda #3
cmp i
bne b1_from_b7
jmp breturn
//SEG38 main::@return
breturn:
//SEG39 [20] return
rts
//SEG40 main::@5
b5:
//SEG41 [21] (byte~) main::$10 ← (byte) main::i#2 + (byte) 3 -- vbuz1=vbuz2_plus_vbuc1
lax i
axs #-[3]
stx _10
jmp b7_from_b5
//SEG42 main::@2
b2:
//SEG43 [22] (byte~) main::$4 ← (byte) main::i#2 + (byte) 3 -- vbuz1=vbuz2_plus_vbuc1
lax i
axs #-[3]
stx _4
jmp b4_from_b2
}
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [8] (byte~) main::$2 ← (byte) main::i#2 << (byte) 2 [ main::i#2 main::screen#3 main::$2 ] ( main:2 [ main::i#2 main::screen#3 main::$2 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Statement [10] *((byte*) main::screen#3) ← (byte~) main::$5 [ main::i#2 main::screen#3 ] ( main:2 [ main::i#2 main::screen#3 ] ) always clobbers reg byte y
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Statement [11] (byte*) main::screen#1 ← ++ (byte*) main::screen#3 [ main::i#2 main::screen#1 ] ( main:2 [ main::i#2 main::screen#1 ] ) always clobbers reg byte a
Statement [12] (byte~) main::$6 ← (byte) main::i#2 & (byte) 1 [ main::i#2 main::screen#1 main::$6 ] ( main:2 [ main::i#2 main::screen#1 main::$6 ] ) always clobbers reg byte a
Statement [14] (byte~) main::$8 ← (byte) main::i#2 << (byte) 2 [ main::i#2 main::screen#1 main::$8 ] ( main:2 [ main::i#2 main::screen#1 main::$8 ] ) always clobbers reg byte a
Statement [16] *((byte*) main::screen#1) ← (byte~) main::$11 [ main::i#2 main::screen#1 ] ( main:2 [ main::i#2 main::screen#1 ] ) always clobbers reg byte y
Statement [17] (byte*) main::screen#2 ← ++ (byte*) main::screen#1 [ main::i#2 main::screen#2 ] ( main:2 [ main::i#2 main::screen#2 ] ) always clobbers reg byte a
Statement [21] (byte~) main::$10 ← (byte) main::i#2 + (byte) 3 [ main::i#2 main::screen#1 main::$10 ] ( main:2 [ main::i#2 main::screen#1 main::$10 ] ) always clobbers reg byte a
Statement [22] (byte~) main::$4 ← (byte) main::i#2 + (byte) 3 [ main::i#2 main::screen#3 main::$4 ] ( main:2 [ main::i#2 main::screen#3 main::$4 ] ) always clobbers reg byte a
Statement [6] (byte~) main::$0 ← (byte) main::i#2 & (byte) 1 [ main::i#2 main::screen#3 main::$0 ] ( main:2 [ main::i#2 main::screen#3 main::$0 ] ) always clobbers reg byte a
Statement [8] (byte~) main::$2 ← (byte) main::i#2 << (byte) 2 [ main::i#2 main::screen#3 main::$2 ] ( main:2 [ main::i#2 main::screen#3 main::$2 ] ) always clobbers reg byte a
Statement [10] *((byte*) main::screen#3) ← (byte~) main::$5 [ main::i#2 main::screen#3 ] ( main:2 [ main::i#2 main::screen#3 ] ) always clobbers reg byte y
Statement [11] (byte*) main::screen#1 ← ++ (byte*) main::screen#3 [ main::i#2 main::screen#1 ] ( main:2 [ main::i#2 main::screen#1 ] ) always clobbers reg byte a
Statement [12] (byte~) main::$6 ← (byte) main::i#2 & (byte) 1 [ main::i#2 main::screen#1 main::$6 ] ( main:2 [ main::i#2 main::screen#1 main::$6 ] ) always clobbers reg byte a
Statement [14] (byte~) main::$8 ← (byte) main::i#2 << (byte) 2 [ main::i#2 main::screen#1 main::$8 ] ( main:2 [ main::i#2 main::screen#1 main::$8 ] ) always clobbers reg byte a
Statement [16] *((byte*) main::screen#1) ← (byte~) main::$11 [ main::i#2 main::screen#1 ] ( main:2 [ main::i#2 main::screen#1 ] ) always clobbers reg byte y
Statement [17] (byte*) main::screen#2 ← ++ (byte*) main::screen#1 [ main::i#2 main::screen#2 ] ( main:2 [ main::i#2 main::screen#2 ] ) always clobbers reg byte a
Statement [21] (byte~) main::$10 ← (byte) main::i#2 + (byte) 3 [ main::i#2 main::screen#1 main::$10 ] ( main:2 [ main::i#2 main::screen#1 main::$10 ] ) always clobbers reg byte a
Statement [22] (byte~) main::$4 ← (byte) main::i#2 + (byte) 3 [ main::i#2 main::screen#3 main::$4 ] ( main:2 [ main::i#2 main::screen#3 main::$4 ] ) always clobbers reg byte a
Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte x ,
Potential registers zp ZP_WORD:3 [ main::screen#3 main::screen#2 ] : zp ZP_WORD:3 ,
Potential registers zp ZP_BYTE:5 [ main::$5 main::$4 main::$2 ] : zp ZP_BYTE:5 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:6 [ main::$11 main::$10 main::$8 ] : zp ZP_BYTE:6 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:7 [ main::$0 ] : zp ZP_BYTE:7 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_WORD:8 [ main::screen#1 ] : zp ZP_WORD:8 ,
Potential registers zp ZP_BYTE:10 [ main::$6 ] : zp ZP_BYTE:10 , reg byte a , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 77: zp ZP_BYTE:5 [ main::$5 main::$4 main::$2 ] 77: zp ZP_BYTE:6 [ main::$11 main::$10 main::$8 ] 22.37: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 22: zp ZP_BYTE:7 [ main::$0 ] 22: zp ZP_BYTE:10 [ main::$6 ] 12.05: zp ZP_WORD:3 [ main::screen#3 main::screen#2 ] 4.71: zp ZP_WORD:8 [ main::screen#1 ]
Uplift Scope []
Uplifting [main] best 1443 combination reg byte a [ main::$5 main::$4 main::$2 ] reg byte a [ main::$11 main::$10 main::$8 ] reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::$0 ] zp ZP_BYTE:10 [ main::$6 ] zp ZP_WORD:3 [ main::screen#3 main::screen#2 ] zp ZP_WORD:8 [ main::screen#1 ]
Limited combination testing to 100 combinations of 512 possible.
Uplifting [] best 1443 combination
Attempting to uplift remaining variables inzp ZP_BYTE:10 [ main::$6 ]
Uplifting [main] best 1403 combination reg byte a [ main::$6 ]
Coalescing zero page register with common assignment [ zp ZP_WORD:3 [ main::screen#3 main::screen#2 ] ] with [ zp ZP_WORD:8 [ main::screen#1 ] ] - score: 2
Allocated (was zp ZP_WORD:3) zp ZP_WORD:2 [ main::screen#3 main::screen#2 main::screen#1 ]
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Tests optimization of identical sub-expressions
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//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: {
.label screen = 2
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
//SEG12 [5] phi (byte*) main::screen#3 = (byte*) 1024 [phi:main->main::@1#0] -- pbuz1=pbuc1
lda #<$400
sta screen
lda #>$400
sta screen+1
//SEG13 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1
ldx #0
jmp b1
//SEG14 [5] phi from main::@7 to main::@1 [phi:main::@7->main::@1]
b1_from_b7:
//SEG15 [5] phi (byte*) main::screen#3 = (byte*) main::screen#2 [phi:main::@7->main::@1#0] -- register_copy
//SEG16 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@7->main::@1#1] -- register_copy
jmp b1
//SEG17 main::@1
b1:
//SEG18 [6] (byte~) main::$0 ← (byte) main::i#2 & (byte) 1 -- vbuaa=vbuxx_band_vbuc1
txa
and #1
//SEG19 [7] if((byte) 0!=(byte~) main::$0) goto main::@2 -- vbuc1_neq_vbuaa_then_la1
cmp #0
bne b2
jmp b3
//SEG20 main::@3
b3:
//SEG21 [8] (byte~) main::$2 ← (byte) main::i#2 << (byte) 2 -- vbuaa=vbuxx_rol_2
txa
asl
asl
//SEG22 [9] phi from main::@2 main::@3 to main::@4 [phi:main::@2/main::@3->main::@4]
b4_from_b2:
b4_from_b3:
//SEG23 [9] phi (byte~) main::$5 = (byte~) main::$4 [phi:main::@2/main::@3->main::@4#0] -- register_copy
jmp b4
//SEG24 main::@4
b4:
//SEG25 [10] *((byte*) main::screen#3) ← (byte~) main::$5 -- _deref_pbuz1=vbuaa
ldy #0
sta (screen),y
//SEG26 [11] (byte*) main::screen#1 ← ++ (byte*) main::screen#3 -- pbuz1=_inc_pbuz1
inc screen
bne !+
inc screen+1
!:
//SEG27 [12] (byte~) main::$6 ← (byte) main::i#2 & (byte) 1 -- vbuaa=vbuxx_band_vbuc1
txa
and #1
//SEG28 [13] if((byte) 0!=(byte~) main::$6) goto main::@5 -- vbuc1_neq_vbuaa_then_la1
cmp #0
bne b5
jmp b6
//SEG29 main::@6
b6:
//SEG30 [14] (byte~) main::$8 ← (byte) main::i#2 << (byte) 2 -- vbuaa=vbuxx_rol_2
txa
asl
asl
//SEG31 [15] phi from main::@5 main::@6 to main::@7 [phi:main::@5/main::@6->main::@7]
b7_from_b5:
b7_from_b6:
//SEG32 [15] phi (byte~) main::$11 = (byte~) main::$10 [phi:main::@5/main::@6->main::@7#0] -- register_copy
jmp b7
//SEG33 main::@7
b7:
//SEG34 [16] *((byte*) main::screen#1) ← (byte~) main::$11 -- _deref_pbuz1=vbuaa
ldy #0
sta (screen),y
//SEG35 [17] (byte*) main::screen#2 ← ++ (byte*) main::screen#1 -- pbuz1=_inc_pbuz1
inc screen
bne !+
inc screen+1
!:
//SEG36 [18] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
//SEG37 [19] if((byte) main::i#1!=(byte) 3) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #3
bne b1_from_b7
jmp breturn
//SEG38 main::@return
breturn:
//SEG39 [20] return
rts
//SEG40 main::@5
b5:
//SEG41 [21] (byte~) main::$10 ← (byte) main::i#2 + (byte) 3 -- vbuaa=vbuxx_plus_vbuc1
txa
clc
adc #3
jmp b7_from_b5
//SEG42 main::@2
b2:
//SEG43 [22] (byte~) main::$4 ← (byte) main::i#2 + (byte) 3 -- vbuaa=vbuxx_plus_vbuc1
txa
clc
adc #3
jmp b4_from_b2
}
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp b1
Removing instruction jmp b3
Removing instruction jmp b4
Removing instruction jmp b6
Removing instruction jmp b7
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing label b1_from_b7 with b1
Replacing label b7_from_b5 with b7
Replacing label b4_from_b2 with b4
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction main_from_b1:
Removing instruction bend_from_b1:
Removing instruction b1_from_b7:
Removing instruction b4_from_b2:
Removing instruction b4_from_b3:
Removing instruction b7_from_b5:
Removing instruction b7_from_b6:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction b1_from_main:
Removing instruction b3:
Removing instruction b6:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction jmp b1
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(void()) main()
(byte~) main::$0 reg byte a 22.0
(byte~) main::$10 reg byte a 22.0
(byte~) main::$11 reg byte a 33.0
(byte~) main::$2 reg byte a 22.0
(byte~) main::$4 reg byte a 22.0
(byte~) main::$5 reg byte a 33.0
(byte~) main::$6 reg byte a 22.0
(byte~) main::$8 reg byte a 22.0
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@4
(label) main::@5
(label) main::@6
(label) main::@7
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte x 16.5
(byte) main::i#2 reg byte x 5.866666666666666
(byte*) main::screen
(byte*) main::screen#1 screen zp ZP_WORD:2 4.714285714285714
(byte*) main::screen#2 screen zp ZP_WORD:2 7.333333333333333
(byte*) main::screen#3 screen zp ZP_WORD:2 4.714285714285714
reg byte x [ main::i#2 main::i#1 ]
zp ZP_WORD:2 [ main::screen#3 main::screen#2 main::screen#1 ]
reg byte a [ main::$5 main::$4 main::$2 ]
reg byte a [ main::$11 main::$10 main::$8 ]
reg byte a [ main::$0 ]
reg byte a [ main::$6 ]
FINAL ASSEMBLER
Score: 1071
//SEG0 File Comments
// Tests optimization of identical sub-expressions
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//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: {
.label screen = 2
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
//SEG12 [5] phi (byte*) main::screen#3 = (byte*) 1024 [phi:main->main::@1#0] -- pbuz1=pbuc1
lda #<$400
sta screen
lda #>$400
sta screen+1
//SEG13 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1
ldx #0
//SEG14 [5] phi from main::@7 to main::@1 [phi:main::@7->main::@1]
//SEG15 [5] phi (byte*) main::screen#3 = (byte*) main::screen#2 [phi:main::@7->main::@1#0] -- register_copy
//SEG16 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@7->main::@1#1] -- register_copy
//SEG17 main::@1
b1:
//SEG18 [6] (byte~) main::$0 ← (byte) main::i#2 & (byte) 1 -- vbuaa=vbuxx_band_vbuc1
txa
and #1
//SEG19 [7] if((byte) 0!=(byte~) main::$0) goto main::@2 -- vbuc1_neq_vbuaa_then_la1
cmp #0
bne b2
//SEG20 main::@3
//SEG21 [8] (byte~) main::$2 ← (byte) main::i#2 << (byte) 2 -- vbuaa=vbuxx_rol_2
txa
asl
asl
//SEG22 [9] phi from main::@2 main::@3 to main::@4 [phi:main::@2/main::@3->main::@4]
//SEG23 [9] phi (byte~) main::$5 = (byte~) main::$4 [phi:main::@2/main::@3->main::@4#0] -- register_copy
//SEG24 main::@4
b4:
//SEG25 [10] *((byte*) main::screen#3) ← (byte~) main::$5 -- _deref_pbuz1=vbuaa
ldy #0
sta (screen),y
//SEG26 [11] (byte*) main::screen#1 ← ++ (byte*) main::screen#3 -- pbuz1=_inc_pbuz1
inc screen
bne !+
inc screen+1
!:
//SEG27 [12] (byte~) main::$6 ← (byte) main::i#2 & (byte) 1 -- vbuaa=vbuxx_band_vbuc1
txa
and #1
//SEG28 [13] if((byte) 0!=(byte~) main::$6) goto main::@5 -- vbuc1_neq_vbuaa_then_la1
cmp #0
bne b5
//SEG29 main::@6
//SEG30 [14] (byte~) main::$8 ← (byte) main::i#2 << (byte) 2 -- vbuaa=vbuxx_rol_2
txa
asl
asl
//SEG31 [15] phi from main::@5 main::@6 to main::@7 [phi:main::@5/main::@6->main::@7]
//SEG32 [15] phi (byte~) main::$11 = (byte~) main::$10 [phi:main::@5/main::@6->main::@7#0] -- register_copy
//SEG33 main::@7
b7:
//SEG34 [16] *((byte*) main::screen#1) ← (byte~) main::$11 -- _deref_pbuz1=vbuaa
ldy #0
sta (screen),y
//SEG35 [17] (byte*) main::screen#2 ← ++ (byte*) main::screen#1 -- pbuz1=_inc_pbuz1
inc screen
bne !+
inc screen+1
!:
//SEG36 [18] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
//SEG37 [19] if((byte) main::i#1!=(byte) 3) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #3
bne b1
//SEG38 main::@return
//SEG39 [20] return
rts
//SEG40 main::@5
b5:
//SEG41 [21] (byte~) main::$10 ← (byte) main::i#2 + (byte) 3 -- vbuaa=vbuxx_plus_vbuc1
txa
clc
adc #3
jmp b7
//SEG42 main::@2
b2:
//SEG43 [22] (byte~) main::$4 ← (byte) main::i#2 + (byte) 3 -- vbuaa=vbuxx_plus_vbuc1
txa
clc
adc #3
jmp b4
}

View File

@ -0,0 +1 @@
program