1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-04-07 22:37:23 +00:00

Added tests for improving array iteration performance for different types of arrays.

This commit is contained in:
Jesper Gravgaard 2020-10-01 22:30:04 +02:00
parent 5c2d1c48d9
commit 1df52a8c5b
57 changed files with 7117 additions and 1142 deletions

View File

@ -1,4 +1,4 @@
//KICKC FRAGMENT CACHE 12011d8c00 12011da5a7
//KICKC FRAGMENT CACHE 11cb56b840 11cb56d1f2
//FRAGMENT vbuz1=vbuc1
lda #{c1}
sta {z1}

View File

@ -1,4 +1,4 @@
//KICKC FRAGMENT CACHE 12011d8c00 12011da5a7
//KICKC FRAGMENT CACHE 11cb56b840 11cb56d1f2
//FRAGMENT _deref_pbuc1=vbuc2
lda #{c2}
sta {c1}

View File

@ -1,4 +1,4 @@
//KICKC FRAGMENT CACHE 12011d8c00 12011da5a7
//KICKC FRAGMENT CACHE 11cb56b840 11cb56d1f2
//FRAGMENT vbuz1=vbuc1
lda #{c1}
sta {z1}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
//KICKC FRAGMENT CACHE 12011d8c00 12011da5a7
//KICKC FRAGMENT CACHE 11cb56b840 11cb56d1f2
//FRAGMENT vbuz1=_deref_pbuc1
lda {c1}
sta {z1}

View File

@ -0,0 +1,12 @@
ldy #0
clc
lda ({z1}),y
adc ({z2}),y
pha
iny
lda ({z1}),y
adc ({z2}),y
sta ({z1}),y
dey
pla
sta ({z1}),y

View File

@ -64,6 +64,56 @@ public class TestPrograms {
compileAndCompare("index-sizeof-reuse-2.c");
}
@Test
public void testIndexPointerRewrite0() throws IOException, URISyntaxException {
compileAndCompare("index-pointer-rewrite-0.c");
}
@Test
public void testIndexPointerRewrite1() throws IOException, URISyntaxException {
compileAndCompare("index-pointer-rewrite-1.c");
}
@Test
public void testIndexPointerRewrite2() throws IOException, URISyntaxException {
compileAndCompare("index-pointer-rewrite-2.c");
}
@Test
public void testIndexPointerRewrite3() throws IOException, URISyntaxException {
compileAndCompare("index-pointer-rewrite-3.c");
}
@Test
public void testIndexPointerRewrite4() throws IOException, URISyntaxException {
compileAndCompare("index-pointer-rewrite-4.c");
}
@Test
public void testIndexPointerRewrite5() throws IOException, URISyntaxException {
compileAndCompare("index-pointer-rewrite-5.c");
}
@Test
public void testIndexPointerRewrite6() throws IOException, URISyntaxException {
compileAndCompare("index-pointer-rewrite-6.c");
}
@Test
public void testIndexPointerRewrite7() throws IOException, URISyntaxException {
compileAndCompare("index-pointer-rewrite-7.c");
}
@Test
public void testIndexPointerRewrite8() throws IOException, URISyntaxException {
compileAndCompare("index-pointer-rewrite-8.c");
}
@Test
public void testIndexPointerRewrite9() throws IOException, URISyntaxException {
compileAndCompare("index-pointer-rewrite-9.c");
}
@Test
public void testPragmaNoParenthesis() throws IOException, URISyntaxException {
compileAndCompare("pragma-noparenthesis.c");

View File

@ -0,0 +1,12 @@
// Test array index pointer rewriting
// 8bit array with 8bit index
#define NUM_ENTITIES 25
char entities[NUM_ENTITIES];
void main() {
for(char i=0;i<NUM_ENTITIES;i++)
entities[i] = 7;
}

View File

@ -0,0 +1,12 @@
// Test array index pointer rewriting
// 16bit array with 8bit index
#define NUM_ENTITIES 25
unsigned short entities[NUM_ENTITIES];
void main() {
for(char i=0;i<NUM_ENTITIES;i++)
entities[i] = 7;
}

View File

@ -0,0 +1,12 @@
// Test array index pointer rewriting
// 8bit array with 16bit index
#define NUM_ENTITIES 25
char entities[NUM_ENTITIES];
void main() {
for(unsigned short i=0;i<NUM_ENTITIES;i++)
entities[i] = 7;
}

View File

@ -0,0 +1,12 @@
// Test array index pointer rewriting
// 16bit array with 16bit index
#define NUM_ENTITIES 25
unsigned short entities[NUM_ENTITIES];
void main() {
for(unsigned short i=0;i<NUM_ENTITIES;i++)
entities[i] = 7;
}

View File

@ -0,0 +1,14 @@
// Test array index pointer rewriting
// 8bit array with 8bit index
// Fibonacci calculation uses adjacent indices inside the loop
#define NUM_FIBS 25
char fibs[NUM_FIBS];
void main() {
fibs[0] = 0;
fibs[1] = 1;
for(char i=0;i<NUM_FIBS-2;i++)
fibs[i+2] = fibs[i]+fibs[i+1];
}

View File

@ -0,0 +1,14 @@
// Test array index pointer rewriting
// 16bit array with 8bit index
// Fibonacci calculation uses adjacent indices inside the loop
#define NUM_FIBS 25
unsigned short fibs[NUM_FIBS];
void main() {
fibs[0] = 0;
fibs[1] = 1;
for(char i=0;i<NUM_FIBS-2;i++)
fibs[i+2] = fibs[i]+fibs[i+1];
}

View File

@ -0,0 +1,14 @@
// Test array index pointer rewriting
// 8bit array with 16bit index
// Fibonacci calculation uses adjacent indices inside the loop
#define NUM_FIBS 25
char fibs[NUM_FIBS];
void main() {
fibs[0] = 0;
fibs[1] = 1;
for(unsigned short i=0;i<NUM_FIBS-2;i++)
fibs[i+2] = fibs[i]+fibs[i+1];
}

View File

@ -0,0 +1,14 @@
// Test array index pointer rewriting
// 16bit array with 16bit index
// Fibonacci calculation uses adjacent indices inside the loop
#define NUM_FIBS 25
unsigned short fibs[NUM_FIBS];
void main() {
fibs[0] = 0;
fibs[1] = 1;
for(unsigned short i=0;i<NUM_FIBS-2;i++)
fibs[i+2] = fibs[i]+fibs[i+1];
}

View File

@ -0,0 +1,20 @@
// Test array index pointer rewriting
// struct array with 8bit index
#define NUM_BALLS 25
struct Ball {
char pos;
char vel;
char sym;
};
struct Ball balls[NUM_BALLS];
void main() {
for(char i=0;i<NUM_BALLS;i++) {
balls[i].pos += balls[i].vel;
balls[i].vel += 10;
balls[i].sym ='*';
}
}

View File

@ -0,0 +1,20 @@
// Test array index pointer rewriting
// struct array with 16bit index
#define NUM_BALLS 25
struct Ball {
char pos;
char vel;
char sym;
};
struct Ball balls[NUM_BALLS];
void main() {
for(unsigned short i=0;i<NUM_BALLS;i++) {
balls[i].pos += balls[i].vel;
balls[i].vel += 10;
balls[i].sym ='*';
}
}

View File

@ -0,0 +1,22 @@
// Test array index pointer rewriting
// 8bit array with 8bit index
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
main: {
ldx #0
__b1:
// for(char i=0;i<NUM_ENTITIES;i++)
cpx #$19
bcc __b2
// }
rts
__b2:
// entities[i] = 7
lda #7
sta entities,x
// for(char i=0;i<NUM_ENTITIES;i++)
inx
jmp __b1
}
entities: .fill $19, 0

View File

@ -0,0 +1,16 @@
(void()) main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[1] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
[2] if((byte) main::i#2<(byte) $19) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[3] return
to:@return
main::@2: scope:[main] from main::@1
[4] *((const byte*) entities + (byte) main::i#2) ← (byte) 7
[5] (byte) main::i#1 ← ++ (byte) main::i#2
to:main::@1

View File

@ -0,0 +1,275 @@
CONTROL FLOW GRAPH SSA
(void()) main()
main: scope:[main] from __start
(byte) main::i#0 ← (byte) 0
to:main::@1
main::@1: scope:[main] from main main::@2
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 )
(bool~) main::$0 ← (byte) main::i#2 < (number) $19
if((bool~) main::$0) goto main::@2
to:main::@return
main::@2: scope:[main] from main::@1
(byte) main::i#3 ← phi( main::@1/(byte) main::i#2 )
*((const byte*) entities + (byte) main::i#3) ← (number) 7
(byte) main::i#1 ← ++ (byte) main::i#3
to:main::@1
main::@return: scope:[main] from main::@1
return
to:@return
(void()) __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
(void()) __start()
(label) __start::@1
(label) __start::@return
(const byte*) entities[(number) $19] = { fill( $19, 0) }
(void()) main()
(bool~) main::$0
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
(byte) main::i#3
Adding number conversion cast (unumber) $19 in (bool~) main::$0 ← (byte) main::i#2 < (number) $19
Adding number conversion cast (unumber) 7 in *((const byte*) entities + (byte) main::i#3) ← (number) 7
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast *((const byte*) entities + (byte) main::i#3) ← (unumber)(number) 7
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast $19
Simplifying constant integer cast 7
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) $19
Finalized unsigned number type (byte) 7
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias main::i#2 = main::i#3
Successful SSA optimization Pass2AliasElimination
Simple Condition (bool~) main::$0 [3] if((byte) main::i#2<(byte) $19) goto main::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const byte) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Inlining constant with var siblings (const byte) main::i#0
Constant inlined main::i#0 = (byte) 0
Successful SSA optimization Pass2ConstantInlining
Adding NOP phi() at start of main
CALL GRAPH
Created 1 initial phi equivalence classes
Coalesced [6] main::i#4 ← main::i#1
Coalesced down to 1 phi equivalence classes
Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH
(void()) main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[1] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
[2] if((byte) main::i#2<(byte) $19) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[3] return
to:@return
main::@2: scope:[main] from main::@1
[4] *((const byte*) entities + (byte) main::i#2) ← (byte) 7
[5] (byte) main::i#1 ← ++ (byte) main::i#2
to:main::@1
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte) main::i
(byte) main::i#1 22.0
(byte) main::i#2 14.666666666666666
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
Allocated zp[1]:2 [ main::i#2 main::i#1 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Test array index pointer rewriting
// 8bit array with 8bit index
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
.label i = 2
// [1] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [1] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z i
jmp __b1
// main::@1
__b1:
// [2] if((byte) main::i#2<(byte) $19) goto main::@2 -- vbuz1_lt_vbuc1_then_la1
lda.z i
cmp #$19
bcc __b2
jmp __breturn
// main::@return
__breturn:
// [3] return
rts
// main::@2
__b2:
// [4] *((const byte*) entities + (byte) main::i#2) ← (byte) 7 -- pbuc1_derefidx_vbuz1=vbuc2
lda #7
ldy.z i
sta entities,y
// [5] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc.z i
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [1] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
entities: .fill $19, 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] *((const byte*) entities + (byte) main::i#2) ← (byte) 7 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::i#2 main::i#1 ]
Statement [4] *((const byte*) entities + (byte) main::i#2) ← (byte) 7 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
Potential registers zp[1]:2 [ main::i#2 main::i#1 ] : zp[1]:2 , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 36.67: zp[1]:2 [ main::i#2 main::i#1 ]
Uplift Scope []
Uplifting [main] best 251 combination reg byte x [ main::i#2 main::i#1 ]
Uplifting [] best 251 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test array index pointer rewriting
// 8bit array with 8bit index
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
// [1] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [1] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
jmp __b1
// main::@1
__b1:
// [2] if((byte) main::i#2<(byte) $19) goto main::@2 -- vbuxx_lt_vbuc1_then_la1
cpx #$19
bcc __b2
jmp __breturn
// main::@return
__breturn:
// [3] return
rts
// main::@2
__b2:
// [4] *((const byte*) entities + (byte) main::i#2) ← (byte) 7 -- pbuc1_derefidx_vbuxx=vbuc2
lda #7
sta entities,x
// [5] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [1] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
entities: .fill $19, 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __b1_from_main:
Removing instruction __breturn:
Removing instruction __b1_from___b2:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(const byte*) entities[(number) $19] = { fill( $19, 0) }
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte x 22.0
(byte) main::i#2 reg byte x 14.666666666666666
reg byte x [ main::i#2 main::i#1 ]
FINAL ASSEMBLER
Score: 191
// File Comments
// Test array index pointer rewriting
// 8bit array with 8bit index
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
// [1] phi from main to main::@1 [phi:main->main::@1]
// [1] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
// main::@1
__b1:
// for(char i=0;i<NUM_ENTITIES;i++)
// [2] if((byte) main::i#2<(byte) $19) goto main::@2 -- vbuxx_lt_vbuc1_then_la1
cpx #$19
bcc __b2
// main::@return
// }
// [3] return
rts
// main::@2
__b2:
// entities[i] = 7
// [4] *((const byte*) entities + (byte) main::i#2) ← (byte) 7 -- pbuc1_derefidx_vbuxx=vbuc2
lda #7
sta entities,x
// for(char i=0;i<NUM_ENTITIES;i++)
// [5] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
// [1] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
entities: .fill $19, 0

View File

@ -0,0 +1,10 @@
(const byte*) entities[(number) $19] = { fill( $19, 0) }
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte x 22.0
(byte) main::i#2 reg byte x 14.666666666666666
reg byte x [ main::i#2 main::i#1 ]

View File

@ -0,0 +1,27 @@
// Test array index pointer rewriting
// 16bit array with 8bit index
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
main: {
ldx #0
__b1:
// for(char i=0;i<NUM_ENTITIES;i++)
cpx #$19
bcc __b2
// }
rts
__b2:
// entities[i] = 7
txa
asl
tay
lda #7
sta entities,y
lda #0
sta entities+1,y
// for(char i=0;i<NUM_ENTITIES;i++)
inx
jmp __b1
}
entities: .fill 2*$19, 0

View File

@ -0,0 +1,17 @@
(void()) main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[1] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
[2] if((byte) main::i#2<(byte) $19) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[3] return
to:@return
main::@2: scope:[main] from main::@1
[4] (byte~) main::$1 ← (byte) main::i#2 << (byte) 1
[5] *((const word*) entities + (byte~) main::$1) ← (byte) 7
[6] (byte) main::i#1 ← ++ (byte) main::i#2
to:main::@1

View File

@ -0,0 +1,311 @@
CONTROL FLOW GRAPH SSA
(void()) main()
main: scope:[main] from __start
(byte) main::i#0 ← (byte) 0
to:main::@1
main::@1: scope:[main] from main main::@2
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 )
(bool~) main::$0 ← (byte) main::i#2 < (number) $19
if((bool~) main::$0) goto main::@2
to:main::@return
main::@2: scope:[main] from main::@1
(byte) main::i#3 ← phi( main::@1/(byte) main::i#2 )
(byte~) main::$1 ← (byte) main::i#3 * (const byte) SIZEOF_WORD
*((const word*) entities + (byte~) main::$1) ← (number) 7
(byte) main::i#1 ← ++ (byte) main::i#3
to:main::@1
main::@return: scope:[main] from main::@1
return
to:@return
(void()) __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
(const byte) SIZEOF_WORD = (byte) 2
(void()) __start()
(label) __start::@1
(label) __start::@return
(const word*) entities[(number) $19] = { fill( $19, 0) }
(void()) main()
(bool~) main::$0
(byte~) main::$1
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
(byte) main::i#3
Adding number conversion cast (unumber) $19 in (bool~) main::$0 ← (byte) main::i#2 < (number) $19
Adding number conversion cast (unumber) 7 in *((const word*) entities + (byte~) main::$1) ← (number) 7
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast *((const word*) entities + (byte~) main::$1) ← (unumber)(number) 7
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast $19
Simplifying constant integer cast 7
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) $19
Finalized unsigned number type (byte) 7
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias main::i#2 = main::i#3
Successful SSA optimization Pass2AliasElimination
Simple Condition (bool~) main::$0 [3] if((byte) main::i#2<(byte) $19) goto main::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const byte) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Rewriting multiplication to use shift [2] (byte~) main::$1 ← (byte) main::i#2 * (const byte) SIZEOF_WORD
Successful SSA optimization Pass2MultiplyToShiftRewriting
Inlining constant with var siblings (const byte) main::i#0
Constant inlined main::i#0 = (byte) 0
Successful SSA optimization Pass2ConstantInlining
Eliminating unused constant (const byte) SIZEOF_WORD
Successful SSA optimization PassNEliminateUnusedVars
Adding NOP phi() at start of main
CALL GRAPH
Created 1 initial phi equivalence classes
Coalesced [7] main::i#4 ← main::i#1
Coalesced down to 1 phi equivalence classes
Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH
(void()) main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[1] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
[2] if((byte) main::i#2<(byte) $19) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[3] return
to:@return
main::@2: scope:[main] from main::@1
[4] (byte~) main::$1 ← (byte) main::i#2 << (byte) 1
[5] *((const word*) entities + (byte~) main::$1) ← (byte) 7
[6] (byte) main::i#1 ← ++ (byte) main::i#2
to:main::@1
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte~) main::$1 22.0
(byte) main::i
(byte) main::i#1 22.0
(byte) main::i#2 11.0
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
Added variable main::$1 to live range equivalence class [ main::$1 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ main::$1 ]
Allocated zp[1]:2 [ main::i#2 main::i#1 ]
Allocated zp[1]:3 [ main::$1 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Test array index pointer rewriting
// 16bit array with 8bit index
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
.label __1 = 3
.label i = 2
// [1] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [1] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z i
jmp __b1
// main::@1
__b1:
// [2] if((byte) main::i#2<(byte) $19) goto main::@2 -- vbuz1_lt_vbuc1_then_la1
lda.z i
cmp #$19
bcc __b2
jmp __breturn
// main::@return
__breturn:
// [3] return
rts
// main::@2
__b2:
// [4] (byte~) main::$1 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuz2_rol_1
lda.z i
asl
sta.z __1
// [5] *((const word*) entities + (byte~) main::$1) ← (byte) 7 -- pwuc1_derefidx_vbuz1=vbuc2
lda #7
ldy.z __1
sta entities,y
lda #0
sta entities+1,y
// [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc.z i
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [1] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
entities: .fill 2*$19, 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] (byte~) main::$1 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$1 ] ( [ main::i#2 main::$1 ] { } ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::i#2 main::i#1 ]
Statement [5] *((const word*) entities + (byte~) main::$1) ← (byte) 7 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
Statement [4] (byte~) main::$1 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$1 ] ( [ main::i#2 main::$1 ] { } ) always clobbers reg byte a
Statement [5] *((const word*) entities + (byte~) main::$1) ← (byte) 7 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
Potential registers zp[1]:2 [ main::i#2 main::i#1 ] : zp[1]:2 , reg byte x , reg byte y ,
Potential registers zp[1]:3 [ main::$1 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 33: zp[1]:2 [ main::i#2 main::i#1 ] 22: zp[1]:3 [ main::$1 ]
Uplift Scope []
Uplifting [main] best 381 combination reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::$1 ]
Uplifting [] best 381 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test array index pointer rewriting
// 16bit array with 8bit index
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
// [1] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [1] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
jmp __b1
// main::@1
__b1:
// [2] if((byte) main::i#2<(byte) $19) goto main::@2 -- vbuxx_lt_vbuc1_then_la1
cpx #$19
bcc __b2
jmp __breturn
// main::@return
__breturn:
// [3] return
rts
// main::@2
__b2:
// [4] (byte~) main::$1 ← (byte) main::i#2 << (byte) 1 -- vbuaa=vbuxx_rol_1
txa
asl
// [5] *((const word*) entities + (byte~) main::$1) ← (byte) 7 -- pwuc1_derefidx_vbuaa=vbuc2
tay
lda #7
sta entities,y
lda #0
sta entities+1,y
// [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [1] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
entities: .fill 2*$19, 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __b1_from_main:
Removing instruction __breturn:
Removing instruction __b1_from___b2:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(const word*) entities[(number) $19] = { fill( $19, 0) }
(void()) main()
(byte~) main::$1 reg byte a 22.0
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte x 22.0
(byte) main::i#2 reg byte x 11.0
reg byte x [ main::i#2 main::i#1 ]
reg byte a [ main::$1 ]
FINAL ASSEMBLER
Score: 321
// File Comments
// Test array index pointer rewriting
// 16bit array with 8bit index
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
// [1] phi from main to main::@1 [phi:main->main::@1]
// [1] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
// main::@1
__b1:
// for(char i=0;i<NUM_ENTITIES;i++)
// [2] if((byte) main::i#2<(byte) $19) goto main::@2 -- vbuxx_lt_vbuc1_then_la1
cpx #$19
bcc __b2
// main::@return
// }
// [3] return
rts
// main::@2
__b2:
// entities[i] = 7
// [4] (byte~) main::$1 ← (byte) main::i#2 << (byte) 1 -- vbuaa=vbuxx_rol_1
txa
asl
// [5] *((const word*) entities + (byte~) main::$1) ← (byte) 7 -- pwuc1_derefidx_vbuaa=vbuc2
tay
lda #7
sta entities,y
lda #0
sta entities+1,y
// for(char i=0;i<NUM_ENTITIES;i++)
// [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
// [1] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
entities: .fill 2*$19, 0

View File

@ -0,0 +1,12 @@
(const word*) entities[(number) $19] = { fill( $19, 0) }
(void()) main()
(byte~) main::$1 reg byte a 22.0
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte x 22.0
(byte) main::i#2 reg byte x 11.0
reg byte x [ main::i#2 main::i#1 ]
reg byte a [ main::$1 ]

View File

@ -0,0 +1,41 @@
// Test array index pointer rewriting
// 8bit array with 16bit index
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
main: {
.label i = 2
.label __1 = 4
lda #<0
sta.z i
sta.z i+1
__b1:
// for(unsigned short i=0;i<NUM_ENTITIES;i++)
lda.z i+1
bne !+
lda.z i
cmp #$19
bcc __b2
!:
// }
rts
__b2:
// entities[i] = 7
lda.z i
clc
adc #<entities
sta.z __1
lda.z i+1
adc #>entities
sta.z __1+1
lda #7
ldy #0
sta (__1),y
// for(unsigned short i=0;i<NUM_ENTITIES;i++)
inc.z i
bne !+
inc.z i+1
!:
jmp __b1
}
entities: .fill $19, 0

View File

@ -0,0 +1,17 @@
(void()) main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[1] (word) main::i#2 ← phi( main/(word) 0 main::@2/(word) main::i#1 )
[2] if((word) main::i#2<(byte) $19) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[3] return
to:@return
main::@2: scope:[main] from main::@1
[4] (byte*~) main::$1 ← (const byte*) entities + (word) main::i#2
[5] *((byte*~) main::$1) ← (byte) 7
[6] (word) main::i#1 ← ++ (word) main::i#2
to:main::@1

View File

@ -0,0 +1,345 @@
CONTROL FLOW GRAPH SSA
(void()) main()
main: scope:[main] from __start
(word) main::i#0 ← (word) 0
to:main::@1
main::@1: scope:[main] from main main::@2
(word) main::i#2 ← phi( main/(word) main::i#0 main::@2/(word) main::i#1 )
(bool~) main::$0 ← (word) main::i#2 < (number) $19
if((bool~) main::$0) goto main::@2
to:main::@return
main::@2: scope:[main] from main::@1
(word) main::i#3 ← phi( main::@1/(word) main::i#2 )
*((const byte*) entities + (word) main::i#3) ← (number) 7
(word) main::i#1 ← ++ (word) main::i#3
to:main::@1
main::@return: scope:[main] from main::@1
return
to:@return
(void()) __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
(void()) __start()
(label) __start::@1
(label) __start::@return
(const byte*) entities[(number) $19] = { fill( $19, 0) }
(void()) main()
(bool~) main::$0
(label) main::@1
(label) main::@2
(label) main::@return
(word) main::i
(word) main::i#0
(word) main::i#1
(word) main::i#2
(word) main::i#3
Adding number conversion cast (unumber) $19 in (bool~) main::$0 ← (word) main::i#2 < (number) $19
Adding number conversion cast (unumber) 7 in *((const byte*) entities + (word) main::i#3) ← (number) 7
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast *((const byte*) entities + (word) main::i#3) ← (unumber)(number) 7
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast $19
Simplifying constant integer cast 7
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) $19
Finalized unsigned number type (byte) 7
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias main::i#2 = main::i#3
Successful SSA optimization Pass2AliasElimination
Simple Condition (bool~) main::$0 [3] if((word) main::i#2<(byte) $19) goto main::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const word) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
De-inlining pointer[w] to *(pointer+w) [4] *((const byte*) entities + (word) main::i#2) ← (byte) 7
Successful SSA optimization Pass2DeInlineWordDerefIdx
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Inlining constant with var siblings (const word) main::i#0
Constant inlined main::i#0 = (word) 0
Successful SSA optimization Pass2ConstantInlining
Adding NOP phi() at start of main
CALL GRAPH
Created 1 initial phi equivalence classes
Coalesced [7] main::i#4 ← main::i#1
Coalesced down to 1 phi equivalence classes
Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH
(void()) main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[1] (word) main::i#2 ← phi( main/(word) 0 main::@2/(word) main::i#1 )
[2] if((word) main::i#2<(byte) $19) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[3] return
to:@return
main::@2: scope:[main] from main::@1
[4] (byte*~) main::$1 ← (const byte*) entities + (word) main::i#2
[5] *((byte*~) main::$1) ← (byte) 7
[6] (word) main::i#1 ← ++ (word) main::i#2
to:main::@1
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte*~) main::$1 22.0
(word) main::i
(word) main::i#1 22.0
(word) main::i#2 11.0
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
Added variable main::$1 to live range equivalence class [ main::$1 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ main::$1 ]
Allocated zp[2]:2 [ main::i#2 main::i#1 ]
Allocated zp[2]:4 [ main::$1 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Test array index pointer rewriting
// 8bit array with 16bit index
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
.label i = 2
.label __1 = 4
// [1] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [1] phi (word) main::i#2 = (word) 0 [phi:main->main::@1#0] -- vwuz1=vwuc1
lda #<0
sta.z i
lda #>0
sta.z i+1
jmp __b1
// main::@1
__b1:
// [2] if((word) main::i#2<(byte) $19) goto main::@2 -- vwuz1_lt_vbuc1_then_la1
lda.z i+1
bne !+
lda.z i
cmp #$19
bcc __b2
!:
jmp __breturn
// main::@return
__breturn:
// [3] return
rts
// main::@2
__b2:
// [4] (byte*~) main::$1 ← (const byte*) entities + (word) main::i#2 -- pbuz1=pbuc1_plus_vwuz2
lda.z i
clc
adc #<entities
sta.z __1
lda.z i+1
adc #>entities
sta.z __1+1
// [5] *((byte*~) main::$1) ← (byte) 7 -- _deref_pbuz1=vbuc1
lda #7
ldy #0
sta (__1),y
// [6] (word) main::i#1 ← ++ (word) main::i#2 -- vwuz1=_inc_vwuz1
inc.z i
bne !+
inc.z i+1
!:
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [1] phi (word) main::i#2 = (word) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
entities: .fill $19, 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [2] if((word) main::i#2<(byte) $19) goto main::@2 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
Statement [4] (byte*~) main::$1 ← (const byte*) entities + (word) main::i#2 [ main::i#2 main::$1 ] ( [ main::i#2 main::$1 ] { } ) always clobbers reg byte a
Statement [5] *((byte*~) main::$1) ← (byte) 7 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a reg byte y
Potential registers zp[2]:2 [ main::i#2 main::i#1 ] : zp[2]:2 ,
Potential registers zp[2]:4 [ main::$1 ] : zp[2]:4 ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 33: zp[2]:2 [ main::i#2 main::i#1 ] 22: zp[2]:4 [ main::$1 ]
Uplift Scope []
Uplifting [main] best 731 combination zp[2]:2 [ main::i#2 main::i#1 ] zp[2]:4 [ main::$1 ]
Uplifting [] best 731 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test array index pointer rewriting
// 8bit array with 16bit index
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
.label i = 2
.label __1 = 4
// [1] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [1] phi (word) main::i#2 = (word) 0 [phi:main->main::@1#0] -- vwuz1=vwuc1
lda #<0
sta.z i
lda #>0
sta.z i+1
jmp __b1
// main::@1
__b1:
// [2] if((word) main::i#2<(byte) $19) goto main::@2 -- vwuz1_lt_vbuc1_then_la1
lda.z i+1
bne !+
lda.z i
cmp #$19
bcc __b2
!:
jmp __breturn
// main::@return
__breturn:
// [3] return
rts
// main::@2
__b2:
// [4] (byte*~) main::$1 ← (const byte*) entities + (word) main::i#2 -- pbuz1=pbuc1_plus_vwuz2
lda.z i
clc
adc #<entities
sta.z __1
lda.z i+1
adc #>entities
sta.z __1+1
// [5] *((byte*~) main::$1) ← (byte) 7 -- _deref_pbuz1=vbuc1
lda #7
ldy #0
sta (__1),y
// [6] (word) main::i#1 ← ++ (word) main::i#2 -- vwuz1=_inc_vwuz1
inc.z i
bne !+
inc.z i+1
!:
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [1] phi (word) main::i#2 = (word) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
entities: .fill $19, 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction lda #>0
Succesful ASM optimization Pass5UnnecesaryLoadElimination
Removing instruction __b1_from_main:
Removing instruction __breturn:
Removing instruction __b1_from___b2:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(const byte*) entities[(number) $19] = { fill( $19, 0) }
(void()) main()
(byte*~) main::$1 zp[2]:4 22.0
(label) main::@1
(label) main::@2
(label) main::@return
(word) main::i
(word) main::i#1 i zp[2]:2 22.0
(word) main::i#2 i zp[2]:2 11.0
zp[2]:2 [ main::i#2 main::i#1 ]
zp[2]:4 [ main::$1 ]
FINAL ASSEMBLER
Score: 651
// File Comments
// Test array index pointer rewriting
// 8bit array with 16bit index
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
.label i = 2
.label __1 = 4
// [1] phi from main to main::@1 [phi:main->main::@1]
// [1] phi (word) main::i#2 = (word) 0 [phi:main->main::@1#0] -- vwuz1=vwuc1
lda #<0
sta.z i
sta.z i+1
// main::@1
__b1:
// for(unsigned short i=0;i<NUM_ENTITIES;i++)
// [2] if((word) main::i#2<(byte) $19) goto main::@2 -- vwuz1_lt_vbuc1_then_la1
lda.z i+1
bne !+
lda.z i
cmp #$19
bcc __b2
!:
// main::@return
// }
// [3] return
rts
// main::@2
__b2:
// entities[i] = 7
// [4] (byte*~) main::$1 ← (const byte*) entities + (word) main::i#2 -- pbuz1=pbuc1_plus_vwuz2
lda.z i
clc
adc #<entities
sta.z __1
lda.z i+1
adc #>entities
sta.z __1+1
// [5] *((byte*~) main::$1) ← (byte) 7 -- _deref_pbuz1=vbuc1
lda #7
ldy #0
sta (__1),y
// for(unsigned short i=0;i<NUM_ENTITIES;i++)
// [6] (word) main::i#1 ← ++ (word) main::i#2 -- vwuz1=_inc_vwuz1
inc.z i
bne !+
inc.z i+1
!:
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
// [1] phi (word) main::i#2 = (word) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
entities: .fill $19, 0

View File

@ -0,0 +1,12 @@
(const byte*) entities[(number) $19] = { fill( $19, 0) }
(void()) main()
(byte*~) main::$1 zp[2]:4 22.0
(label) main::@1
(label) main::@2
(label) main::@return
(word) main::i
(word) main::i#1 i zp[2]:2 22.0
(word) main::i#2 i zp[2]:2 11.0
zp[2]:2 [ main::i#2 main::i#1 ]
zp[2]:4 [ main::$1 ]

View File

@ -0,0 +1,51 @@
// Test array index pointer rewriting
// 16bit array with 16bit index
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
main: {
.label __1 = 4
.label i = 2
.label __2 = 4
lda #<0
sta.z i
sta.z i+1
__b1:
// for(unsigned short i=0;i<NUM_ENTITIES;i++)
lda.z i+1
bne !+
lda.z i
cmp #$19
bcc __b2
!:
// }
rts
__b2:
// entities[i] = 7
lda.z i
asl
sta.z __1
lda.z i+1
rol
sta.z __1+1
clc
lda.z __2
adc #<entities
sta.z __2
lda.z __2+1
adc #>entities
sta.z __2+1
lda #7
ldy #0
sta (__2),y
tya
iny
sta (__2),y
// for(unsigned short i=0;i<NUM_ENTITIES;i++)
inc.z i
bne !+
inc.z i+1
!:
jmp __b1
}
entities: .fill 2*$19, 0

View File

@ -0,0 +1,18 @@
(void()) main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[1] (word) main::i#2 ← phi( main/(word) 0 main::@2/(word) main::i#1 )
[2] if((word) main::i#2<(byte) $19) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[3] return
to:@return
main::@2: scope:[main] from main::@1
[4] (word~) main::$1 ← (word) main::i#2 << (byte) 1
[5] (word*~) main::$2 ← (const word*) entities + (word~) main::$1
[6] *((word*~) main::$2) ← (byte) 7
[7] (word) main::i#1 ← ++ (word) main::i#2
to:main::@1

View File

@ -0,0 +1,394 @@
CONTROL FLOW GRAPH SSA
(void()) main()
main: scope:[main] from __start
(word) main::i#0 ← (word) 0
to:main::@1
main::@1: scope:[main] from main main::@2
(word) main::i#2 ← phi( main/(word) main::i#0 main::@2/(word) main::i#1 )
(bool~) main::$0 ← (word) main::i#2 < (number) $19
if((bool~) main::$0) goto main::@2
to:main::@return
main::@2: scope:[main] from main::@1
(word) main::i#3 ← phi( main::@1/(word) main::i#2 )
(word~) main::$1 ← (word) main::i#3 * (const byte) SIZEOF_WORD
*((const word*) entities + (word~) main::$1) ← (number) 7
(word) main::i#1 ← ++ (word) main::i#3
to:main::@1
main::@return: scope:[main] from main::@1
return
to:@return
(void()) __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
(const byte) SIZEOF_WORD = (byte) 2
(void()) __start()
(label) __start::@1
(label) __start::@return
(const word*) entities[(number) $19] = { fill( $19, 0) }
(void()) main()
(bool~) main::$0
(word~) main::$1
(label) main::@1
(label) main::@2
(label) main::@return
(word) main::i
(word) main::i#0
(word) main::i#1
(word) main::i#2
(word) main::i#3
Adding number conversion cast (unumber) $19 in (bool~) main::$0 ← (word) main::i#2 < (number) $19
Adding number conversion cast (unumber) 7 in *((const word*) entities + (word~) main::$1) ← (number) 7
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast *((const word*) entities + (word~) main::$1) ← (unumber)(number) 7
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast $19
Simplifying constant integer cast 7
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) $19
Finalized unsigned number type (byte) 7
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias main::i#2 = main::i#3
Successful SSA optimization Pass2AliasElimination
Simple Condition (bool~) main::$0 [3] if((word) main::i#2<(byte) $19) goto main::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const word) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
De-inlining pointer[w] to *(pointer+w) [5] *((const word*) entities + (word~) main::$1) ← (byte) 7
Successful SSA optimization Pass2DeInlineWordDerefIdx
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Rewriting multiplication to use shift [2] (word~) main::$1 ← (word) main::i#2 * (const byte) SIZEOF_WORD
Successful SSA optimization Pass2MultiplyToShiftRewriting
Inlining constant with var siblings (const word) main::i#0
Constant inlined main::i#0 = (word) 0
Successful SSA optimization Pass2ConstantInlining
Eliminating unused constant (const byte) SIZEOF_WORD
Successful SSA optimization PassNEliminateUnusedVars
Adding NOP phi() at start of main
CALL GRAPH
Created 1 initial phi equivalence classes
Coalesced [8] main::i#4 ← main::i#1
Coalesced down to 1 phi equivalence classes
Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH
(void()) main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[1] (word) main::i#2 ← phi( main/(word) 0 main::@2/(word) main::i#1 )
[2] if((word) main::i#2<(byte) $19) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[3] return
to:@return
main::@2: scope:[main] from main::@1
[4] (word~) main::$1 ← (word) main::i#2 << (byte) 1
[5] (word*~) main::$2 ← (const word*) entities + (word~) main::$1
[6] *((word*~) main::$2) ← (byte) 7
[7] (word) main::i#1 ← ++ (word) main::i#2
to:main::@1
VARIABLE REGISTER WEIGHTS
(void()) main()
(word~) main::$1 22.0
(word*~) main::$2 22.0
(word) main::i
(word) main::i#1 22.0
(word) main::i#2 8.8
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
Added variable main::$1 to live range equivalence class [ main::$1 ]
Added variable main::$2 to live range equivalence class [ main::$2 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ main::$1 ]
[ main::$2 ]
Allocated zp[2]:2 [ main::i#2 main::i#1 ]
Allocated zp[2]:4 [ main::$1 ]
Allocated zp[2]:6 [ main::$2 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Test array index pointer rewriting
// 16bit array with 16bit index
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
.label __1 = 4
.label i = 2
.label __2 = 6
// [1] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [1] phi (word) main::i#2 = (word) 0 [phi:main->main::@1#0] -- vwuz1=vwuc1
lda #<0
sta.z i
lda #>0
sta.z i+1
jmp __b1
// main::@1
__b1:
// [2] if((word) main::i#2<(byte) $19) goto main::@2 -- vwuz1_lt_vbuc1_then_la1
lda.z i+1
bne !+
lda.z i
cmp #$19
bcc __b2
!:
jmp __breturn
// main::@return
__breturn:
// [3] return
rts
// main::@2
__b2:
// [4] (word~) main::$1 ← (word) main::i#2 << (byte) 1 -- vwuz1=vwuz2_rol_1
lda.z i
asl
sta.z __1
lda.z i+1
rol
sta.z __1+1
// [5] (word*~) main::$2 ← (const word*) entities + (word~) main::$1 -- pwuz1=pwuc1_plus_vwuz2
lda.z __1
clc
adc #<entities
sta.z __2
lda.z __1+1
adc #>entities
sta.z __2+1
// [6] *((word*~) main::$2) ← (byte) 7 -- _deref_pwuz1=vbuc1
lda #7
ldy #0
sta (__2),y
tya
iny
sta (__2),y
// [7] (word) main::i#1 ← ++ (word) main::i#2 -- vwuz1=_inc_vwuz1
inc.z i
bne !+
inc.z i+1
!:
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [1] phi (word) main::i#2 = (word) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
entities: .fill 2*$19, 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [2] if((word) main::i#2<(byte) $19) goto main::@2 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
Statement [4] (word~) main::$1 ← (word) main::i#2 << (byte) 1 [ main::i#2 main::$1 ] ( [ main::i#2 main::$1 ] { } ) always clobbers reg byte a
Statement [5] (word*~) main::$2 ← (const word*) entities + (word~) main::$1 [ main::i#2 main::$2 ] ( [ main::i#2 main::$2 ] { } ) always clobbers reg byte a
Statement [6] *((word*~) main::$2) ← (byte) 7 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a reg byte y
Potential registers zp[2]:2 [ main::i#2 main::i#1 ] : zp[2]:2 ,
Potential registers zp[2]:4 [ main::$1 ] : zp[2]:4 ,
Potential registers zp[2]:6 [ main::$2 ] : zp[2]:6 ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 30.8: zp[2]:2 [ main::i#2 main::i#1 ] 22: zp[2]:4 [ main::$1 ] 22: zp[2]:6 [ main::$2 ]
Uplift Scope []
Uplifting [main] best 991 combination zp[2]:2 [ main::i#2 main::i#1 ] zp[2]:4 [ main::$1 ] zp[2]:6 [ main::$2 ]
Uplifting [] best 991 combination
Coalescing zero page register [ zp[2]:4 [ main::$1 ] ] with [ zp[2]:6 [ main::$2 ] ] - score: 1
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test array index pointer rewriting
// 16bit array with 16bit index
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
.label __1 = 4
.label i = 2
.label __2 = 4
// [1] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [1] phi (word) main::i#2 = (word) 0 [phi:main->main::@1#0] -- vwuz1=vwuc1
lda #<0
sta.z i
lda #>0
sta.z i+1
jmp __b1
// main::@1
__b1:
// [2] if((word) main::i#2<(byte) $19) goto main::@2 -- vwuz1_lt_vbuc1_then_la1
lda.z i+1
bne !+
lda.z i
cmp #$19
bcc __b2
!:
jmp __breturn
// main::@return
__breturn:
// [3] return
rts
// main::@2
__b2:
// [4] (word~) main::$1 ← (word) main::i#2 << (byte) 1 -- vwuz1=vwuz2_rol_1
lda.z i
asl
sta.z __1
lda.z i+1
rol
sta.z __1+1
// [5] (word*~) main::$2 ← (const word*) entities + (word~) main::$1 -- pwuz1=pwuc1_plus_vwuz1
clc
lda.z __2
adc #<entities
sta.z __2
lda.z __2+1
adc #>entities
sta.z __2+1
// [6] *((word*~) main::$2) ← (byte) 7 -- _deref_pwuz1=vbuc1
lda #7
ldy #0
sta (__2),y
tya
iny
sta (__2),y
// [7] (word) main::i#1 ← ++ (word) main::i#2 -- vwuz1=_inc_vwuz1
inc.z i
bne !+
inc.z i+1
!:
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [1] phi (word) main::i#2 = (word) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
entities: .fill 2*$19, 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction lda #>0
Succesful ASM optimization Pass5UnnecesaryLoadElimination
Removing instruction __b1_from_main:
Removing instruction __breturn:
Removing instruction __b1_from___b2:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(const word*) entities[(number) $19] = { fill( $19, 0) }
(void()) main()
(word~) main::$1 zp[2]:4 22.0
(word*~) main::$2 zp[2]:4 22.0
(label) main::@1
(label) main::@2
(label) main::@return
(word) main::i
(word) main::i#1 i zp[2]:2 22.0
(word) main::i#2 i zp[2]:2 8.8
zp[2]:2 [ main::i#2 main::i#1 ]
zp[2]:4 [ main::$1 main::$2 ]
FINAL ASSEMBLER
Score: 911
// File Comments
// Test array index pointer rewriting
// 16bit array with 16bit index
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
.label __1 = 4
.label i = 2
.label __2 = 4
// [1] phi from main to main::@1 [phi:main->main::@1]
// [1] phi (word) main::i#2 = (word) 0 [phi:main->main::@1#0] -- vwuz1=vwuc1
lda #<0
sta.z i
sta.z i+1
// main::@1
__b1:
// for(unsigned short i=0;i<NUM_ENTITIES;i++)
// [2] if((word) main::i#2<(byte) $19) goto main::@2 -- vwuz1_lt_vbuc1_then_la1
lda.z i+1
bne !+
lda.z i
cmp #$19
bcc __b2
!:
// main::@return
// }
// [3] return
rts
// main::@2
__b2:
// entities[i] = 7
// [4] (word~) main::$1 ← (word) main::i#2 << (byte) 1 -- vwuz1=vwuz2_rol_1
lda.z i
asl
sta.z __1
lda.z i+1
rol
sta.z __1+1
// [5] (word*~) main::$2 ← (const word*) entities + (word~) main::$1 -- pwuz1=pwuc1_plus_vwuz1
clc
lda.z __2
adc #<entities
sta.z __2
lda.z __2+1
adc #>entities
sta.z __2+1
// [6] *((word*~) main::$2) ← (byte) 7 -- _deref_pwuz1=vbuc1
lda #7
ldy #0
sta (__2),y
tya
iny
sta (__2),y
// for(unsigned short i=0;i<NUM_ENTITIES;i++)
// [7] (word) main::i#1 ← ++ (word) main::i#2 -- vwuz1=_inc_vwuz1
inc.z i
bne !+
inc.z i+1
!:
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
// [1] phi (word) main::i#2 = (word) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
entities: .fill 2*$19, 0

View File

@ -0,0 +1,13 @@
(const word*) entities[(number) $19] = { fill( $19, 0) }
(void()) main()
(word~) main::$1 zp[2]:4 22.0
(word*~) main::$2 zp[2]:4 22.0
(label) main::@1
(label) main::@2
(label) main::@return
(word) main::i
(word) main::i#1 i zp[2]:2 22.0
(word) main::i#2 i zp[2]:2 8.8
zp[2]:2 [ main::i#2 main::i#1 ]
zp[2]:4 [ main::$1 main::$2 ]

View File

@ -0,0 +1,32 @@
// Test array index pointer rewriting
// 8bit array with 8bit index
// Fibonacci calculation uses adjacent indices inside the loop
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
main: {
// fibs[0] = 0
lda #0
sta fibs
// fibs[1] = 1
lda #1
sta fibs+1
ldx #0
__b1:
// for(char i=0;i<NUM_FIBS-2;i++)
cpx #$19-2
bcc __b2
// }
rts
__b2:
// fibs[i]+fibs[i+1]
lda fibs,x
clc
adc fibs+1,x
// fibs[i+2] = fibs[i]+fibs[i+1]
sta fibs+2,x
// for(char i=0;i<NUM_FIBS-2;i++)
inx
jmp __b1
}
fibs: .fill $19, 0

View File

@ -0,0 +1,18 @@
(void()) main()
main: scope:[main] from
[0] *((const byte*) fibs) ← (byte) 0
[1] *((const byte*) fibs+(byte) 1) ← (byte) 1
to:main::@1
main::@1: scope:[main] from main main::@2
[2] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
[3] if((byte) main::i#2<(byte)(number) $19-(number) 2) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[4] return
to:@return
main::@2: scope:[main] from main::@1
[5] (byte~) main::$3 ← *((const byte*) fibs + (byte) main::i#2) + *((const byte*) fibs+(byte) 1 + (byte) main::i#2)
[6] *((const byte*) fibs+(byte) 2 + (byte) main::i#2) ← (byte~) main::$3
[7] (byte) main::i#1 ← ++ (byte) main::i#2
to:main::@1

View File

@ -0,0 +1,357 @@
CONTROL FLOW GRAPH SSA
(void()) main()
main: scope:[main] from __start
*((const byte*) fibs + (number) 0) ← (number) 0
*((const byte*) fibs + (number) 1) ← (number) 1
(byte) main::i#0 ← (byte) 0
to:main::@1
main::@1: scope:[main] from main main::@2
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 )
(bool~) main::$0 ← (byte) main::i#2 < (number) $19-(number) 2
if((bool~) main::$0) goto main::@2
to:main::@return
main::@2: scope:[main] from main::@1
(byte) main::i#3 ← phi( main::@1/(byte) main::i#2 )
(number~) main::$1 ← (byte) main::i#3 + (number) 2
(number~) main::$2 ← (byte) main::i#3 + (number) 1
(byte~) main::$3 ← *((const byte*) fibs + (byte) main::i#3) + *((const byte*) fibs + (number~) main::$2)
*((const byte*) fibs + (number~) main::$1) ← (byte~) main::$3
(byte) main::i#1 ← ++ (byte) main::i#3
to:main::@1
main::@return: scope:[main] from main::@1
return
to:@return
(void()) __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
(void()) __start()
(label) __start::@1
(label) __start::@return
(const byte*) fibs[(number) $19] = { fill( $19, 0) }
(void()) main()
(bool~) main::$0
(number~) main::$1
(number~) main::$2
(byte~) main::$3
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
(byte) main::i#3
Adding number conversion cast (unumber) 0 in *((const byte*) fibs + (number) 0) ← (number) 0
Adding number conversion cast (unumber) 0 in *((const byte*) fibs + (number) 0) ← ((unumber)) (number) 0
Adding number conversion cast (unumber) 1 in *((const byte*) fibs + (number) 1) ← (number) 1
Adding number conversion cast (unumber) 1 in *((const byte*) fibs + (number) 1) ← ((unumber)) (number) 1
Adding number conversion cast (unumber) $19-2 in (bool~) main::$0 ← (byte) main::i#2 < (number) $19-(number) 2
Adding number conversion cast (unumber) 2 in (number~) main::$1 ← (byte) main::i#3 + (number) 2
Adding number conversion cast (unumber) main::$1 in (number~) main::$1 ← (byte) main::i#3 + (unumber)(number) 2
Adding number conversion cast (unumber) 1 in (number~) main::$2 ← (byte) main::i#3 + (number) 1
Adding number conversion cast (unumber) main::$2 in (number~) main::$2 ← (byte) main::i#3 + (unumber)(number) 1
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast *((const byte*) fibs + (unumber)(number) 0) ← (unumber)(number) 0
Inlining cast *((const byte*) fibs + (unumber)(number) 1) ← (unumber)(number) 1
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast 0
Simplifying constant integer cast 0
Simplifying constant integer cast 1
Simplifying constant integer cast 1
Simplifying constant integer cast 2
Simplifying constant integer cast 1
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 2
Finalized unsigned number type (byte) 1
Successful SSA optimization PassNFinalizeNumberTypeConversions
Inferred type updated to byte in (unumber~) main::$1 ← (byte) main::i#3 + (byte) 2
Inferred type updated to byte in (unumber~) main::$2 ← (byte) main::i#3 + (byte) 1
Alias main::i#2 = main::i#3
Successful SSA optimization Pass2AliasElimination
Simple Condition (bool~) main::$0 [5] if((byte) main::i#2<(byte)(number) $19-(number) 2) goto main::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const byte) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Simplifying expression containing zero fibs in [0] *((const byte*) fibs + (byte) 0) ← (byte) 0
Successful SSA optimization PassNSimplifyExpressionWithZero
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Inlining constant with var siblings (const byte) main::i#0
Constant inlined main::i#0 = (byte) 0
Successful SSA optimization Pass2ConstantInlining
Consolidated array index constant in *(fibs+1)
Consolidated array index constant in assignment *(fibs+1 + main::$2)
Consolidated array index constant in assignment *(fibs+2 + main::$1)
Successful SSA optimization Pass2ConstantAdditionElimination
Alias main::i#2 = main::$1 main::$2
Successful SSA optimization Pass2AliasElimination
CALL GRAPH
Created 1 initial phi equivalence classes
Coalesced [8] main::i#4 ← main::i#1
Coalesced down to 1 phi equivalence classes
FINAL CONTROL FLOW GRAPH
(void()) main()
main: scope:[main] from
[0] *((const byte*) fibs) ← (byte) 0
[1] *((const byte*) fibs+(byte) 1) ← (byte) 1
to:main::@1
main::@1: scope:[main] from main main::@2
[2] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
[3] if((byte) main::i#2<(byte)(number) $19-(number) 2) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[4] return
to:@return
main::@2: scope:[main] from main::@1
[5] (byte~) main::$3 ← *((const byte*) fibs + (byte) main::i#2) + *((const byte*) fibs+(byte) 1 + (byte) main::i#2)
[6] *((const byte*) fibs+(byte) 2 + (byte) main::i#2) ← (byte~) main::$3
[7] (byte) main::i#1 ← ++ (byte) main::i#2
to:main::@1
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte~) main::$3 22.0
(byte) main::i
(byte) main::i#1 22.0
(byte) main::i#2 16.5
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
Added variable main::$3 to live range equivalence class [ main::$3 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ main::$3 ]
Allocated zp[1]:2 [ main::i#2 main::i#1 ]
Allocated zp[1]:3 [ main::$3 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Test array index pointer rewriting
// 8bit array with 8bit index
// Fibonacci calculation uses adjacent indices inside the loop
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
.label __3 = 3
.label i = 2
// [0] *((const byte*) fibs) ← (byte) 0 -- _deref_pbuc1=vbuc2
lda #0
sta fibs
// [1] *((const byte*) fibs+(byte) 1) ← (byte) 1 -- _deref_pbuc1=vbuc2
lda #1
sta fibs+1
// [2] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [2] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z i
jmp __b1
// main::@1
__b1:
// [3] if((byte) main::i#2<(byte)(number) $19-(number) 2) goto main::@2 -- vbuz1_lt_vbuc1_then_la1
lda.z i
cmp #$19-2
bcc __b2
jmp __breturn
// main::@return
__breturn:
// [4] return
rts
// main::@2
__b2:
// [5] (byte~) main::$3 ← *((const byte*) fibs + (byte) main::i#2) + *((const byte*) fibs+(byte) 1 + (byte) main::i#2) -- vbuz1=pbuc1_derefidx_vbuz2_plus_pbuc2_derefidx_vbuz2
ldy.z i
lda fibs,y
clc
adc fibs+1,y
sta.z __3
// [6] *((const byte*) fibs+(byte) 2 + (byte) main::i#2) ← (byte~) main::$3 -- pbuc1_derefidx_vbuz1=vbuz2
lda.z __3
ldy.z i
sta fibs+2,y
// [7] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc.z i
// [2] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [2] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
fibs: .fill $19, 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] *((const byte*) fibs) ← (byte) 0 [ ] ( [ ] { } ) always clobbers reg byte a
Statement [1] *((const byte*) fibs+(byte) 1) ← (byte) 1 [ ] ( [ ] { } ) always clobbers reg byte a
Statement [5] (byte~) main::$3 ← *((const byte*) fibs + (byte) main::i#2) + *((const byte*) fibs+(byte) 1 + (byte) main::i#2) [ main::i#2 main::$3 ] ( [ main::i#2 main::$3 ] { } ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::i#2 main::i#1 ]
Statement [0] *((const byte*) fibs) ← (byte) 0 [ ] ( [ ] { } ) always clobbers reg byte a
Statement [1] *((const byte*) fibs+(byte) 1) ← (byte) 1 [ ] ( [ ] { } ) always clobbers reg byte a
Statement [5] (byte~) main::$3 ← *((const byte*) fibs + (byte) main::i#2) + *((const byte*) fibs+(byte) 1 + (byte) main::i#2) [ main::i#2 main::$3 ] ( [ main::i#2 main::$3 ] { } ) always clobbers reg byte a
Potential registers zp[1]:2 [ main::i#2 main::i#1 ] : zp[1]:2 , reg byte x , reg byte y ,
Potential registers zp[1]:3 [ main::$3 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 38.5: zp[1]:2 [ main::i#2 main::i#1 ] 22: zp[1]:3 [ main::$3 ]
Uplift Scope []
Uplifting [main] best 353 combination reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::$3 ]
Uplifting [] best 353 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test array index pointer rewriting
// 8bit array with 8bit index
// Fibonacci calculation uses adjacent indices inside the loop
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
// [0] *((const byte*) fibs) ← (byte) 0 -- _deref_pbuc1=vbuc2
lda #0
sta fibs
// [1] *((const byte*) fibs+(byte) 1) ← (byte) 1 -- _deref_pbuc1=vbuc2
lda #1
sta fibs+1
// [2] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [2] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
jmp __b1
// main::@1
__b1:
// [3] if((byte) main::i#2<(byte)(number) $19-(number) 2) goto main::@2 -- vbuxx_lt_vbuc1_then_la1
cpx #$19-2
bcc __b2
jmp __breturn
// main::@return
__breturn:
// [4] return
rts
// main::@2
__b2:
// [5] (byte~) main::$3 ← *((const byte*) fibs + (byte) main::i#2) + *((const byte*) fibs+(byte) 1 + (byte) main::i#2) -- vbuaa=pbuc1_derefidx_vbuxx_plus_pbuc2_derefidx_vbuxx
lda fibs,x
clc
adc fibs+1,x
// [6] *((const byte*) fibs+(byte) 2 + (byte) main::i#2) ← (byte~) main::$3 -- pbuc1_derefidx_vbuxx=vbuaa
sta fibs+2,x
// [7] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
// [2] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [2] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
fibs: .fill $19, 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __b1_from_main:
Removing instruction __breturn:
Removing instruction __b1_from___b2:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(const byte*) fibs[(number) $19] = { fill( $19, 0) }
(void()) main()
(byte~) main::$3 reg byte a 22.0
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte x 22.0
(byte) main::i#2 reg byte x 16.5
reg byte x [ main::i#2 main::i#1 ]
reg byte a [ main::$3 ]
FINAL ASSEMBLER
Score: 293
// File Comments
// Test array index pointer rewriting
// 8bit array with 8bit index
// Fibonacci calculation uses adjacent indices inside the loop
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
// fibs[0] = 0
// [0] *((const byte*) fibs) ← (byte) 0 -- _deref_pbuc1=vbuc2
lda #0
sta fibs
// fibs[1] = 1
// [1] *((const byte*) fibs+(byte) 1) ← (byte) 1 -- _deref_pbuc1=vbuc2
lda #1
sta fibs+1
// [2] phi from main to main::@1 [phi:main->main::@1]
// [2] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
// main::@1
__b1:
// for(char i=0;i<NUM_FIBS-2;i++)
// [3] if((byte) main::i#2<(byte)(number) $19-(number) 2) goto main::@2 -- vbuxx_lt_vbuc1_then_la1
cpx #$19-2
bcc __b2
// main::@return
// }
// [4] return
rts
// main::@2
__b2:
// fibs[i]+fibs[i+1]
// [5] (byte~) main::$3 ← *((const byte*) fibs + (byte) main::i#2) + *((const byte*) fibs+(byte) 1 + (byte) main::i#2) -- vbuaa=pbuc1_derefidx_vbuxx_plus_pbuc2_derefidx_vbuxx
lda fibs,x
clc
adc fibs+1,x
// fibs[i+2] = fibs[i]+fibs[i+1]
// [6] *((const byte*) fibs+(byte) 2 + (byte) main::i#2) ← (byte~) main::$3 -- pbuc1_derefidx_vbuxx=vbuaa
sta fibs+2,x
// for(char i=0;i<NUM_FIBS-2;i++)
// [7] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
// [2] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
// [2] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
fibs: .fill $19, 0

View File

@ -0,0 +1,12 @@
(const byte*) fibs[(number) $19] = { fill( $19, 0) }
(void()) main()
(byte~) main::$3 reg byte a 22.0
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte x 22.0
(byte) main::i#2 reg byte x 16.5
reg byte x [ main::i#2 main::i#1 ]
reg byte a [ main::$3 ]

View File

@ -0,0 +1,64 @@
// Test array index pointer rewriting
// 16bit array with 8bit index
// Fibonacci calculation uses adjacent indices inside the loop
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const SIZEOF_WORD = 2
main: {
.label __1 = 3
.label __3 = 4
.label i = 2
// fibs[0] = 0
lda #0
sta fibs+1
sta fibs
// fibs[1] = 1
sta fibs+1*SIZEOF_WORD+1
lda #<1
sta fibs+1*SIZEOF_WORD
lda #0
sta.z i
__b1:
// for(char i=0;i<NUM_FIBS-2;i++)
lda.z i
cmp #$19-2
bcc __b2
// }
rts
__b2:
// i+2
lda.z i
clc
adc #2
sta.z __1
// i+1
ldx.z i
inx
// fibs[i]+fibs[i+1]
lda.z i
asl
tay
txa
asl
tax
lda fibs,x
clc
adc fibs,y
sta.z __3
lda fibs+1,x
adc fibs+1,y
sta.z __3+1
// fibs[i+2] = fibs[i]+fibs[i+1]
lda.z __1
asl
tay
lda.z __3
sta fibs,y
lda.z __3+1
sta fibs+1,y
// for(char i=0;i<NUM_FIBS-2;i++)
inc.z i
jmp __b1
}
fibs: .fill 2*$19, 0

View File

@ -0,0 +1,23 @@
(void()) main()
main: scope:[main] from
[0] *((const word*) fibs) ← (byte) 0
[1] *((const word*) fibs+(byte) 1*(const byte) SIZEOF_WORD) ← (byte) 1
to:main::@1
main::@1: scope:[main] from main main::@2
[2] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
[3] if((byte) main::i#2<(byte)(number) $19-(number) 2) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[4] return
to:@return
main::@2: scope:[main] from main::@1
[5] (byte~) main::$1 ← (byte) main::i#2 + (byte) 2
[6] (byte~) main::$2 ← (byte) main::i#2 + (byte) 1
[7] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1
[8] (byte~) main::$7 ← (byte~) main::$2 << (byte) 1
[9] (word~) main::$3 ← *((const word*) fibs + (byte~) main::$6) + *((const word*) fibs + (byte~) main::$7)
[10] (byte~) main::$8 ← (byte~) main::$1 << (byte) 1
[11] *((const word*) fibs + (byte~) main::$8) ← (word~) main::$3
[12] (byte) main::i#1 ← ++ (byte) main::i#2
to:main::@1

View File

@ -0,0 +1,560 @@
CONTROL FLOW GRAPH SSA
(void()) main()
main: scope:[main] from __start
(number~) main::$4 ← (number) 0 * (const byte) SIZEOF_WORD
*((const word*) fibs + (number~) main::$4) ← (number) 0
(number~) main::$5 ← (number) 1 * (const byte) SIZEOF_WORD
*((const word*) fibs + (number~) main::$5) ← (number) 1
(byte) main::i#0 ← (byte) 0
to:main::@1
main::@1: scope:[main] from main main::@2
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 )
(bool~) main::$0 ← (byte) main::i#2 < (number) $19-(number) 2
if((bool~) main::$0) goto main::@2
to:main::@return
main::@2: scope:[main] from main::@1
(byte) main::i#3 ← phi( main::@1/(byte) main::i#2 )
(number~) main::$1 ← (byte) main::i#3 + (number) 2
(number~) main::$2 ← (byte) main::i#3 + (number) 1
(byte~) main::$6 ← (byte) main::i#3 * (const byte) SIZEOF_WORD
(number~) main::$7 ← (number~) main::$2 * (const byte) SIZEOF_WORD
(word~) main::$3 ← *((const word*) fibs + (byte~) main::$6) + *((const word*) fibs + (number~) main::$7)
(number~) main::$8 ← (number~) main::$1 * (const byte) SIZEOF_WORD
*((const word*) fibs + (number~) main::$8) ← (word~) main::$3
(byte) main::i#1 ← ++ (byte) main::i#3
to:main::@1
main::@return: scope:[main] from main::@1
return
to:@return
(void()) __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
(const byte) SIZEOF_WORD = (byte) 2
(void()) __start()
(label) __start::@1
(label) __start::@return
(const word*) fibs[(number) $19] = { fill( $19, 0) }
(void()) main()
(bool~) main::$0
(number~) main::$1
(number~) main::$2
(word~) main::$3
(number~) main::$4
(number~) main::$5
(byte~) main::$6
(number~) main::$7
(number~) main::$8
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
(byte) main::i#3
Adding number conversion cast (unumber) 0 in (number~) main::$4 ← (number) 0 * (const byte) SIZEOF_WORD
Adding number conversion cast (unumber) main::$4 in (number~) main::$4 ← (unumber)(number) 0 * (const byte) SIZEOF_WORD
Adding number conversion cast (unumber) 0 in *((const word*) fibs + (unumber~) main::$4) ← (number) 0
Adding number conversion cast (unumber) 1 in (number~) main::$5 ← (number) 1 * (const byte) SIZEOF_WORD
Adding number conversion cast (unumber) main::$5 in (number~) main::$5 ← (unumber)(number) 1 * (const byte) SIZEOF_WORD
Adding number conversion cast (unumber) 1 in *((const word*) fibs + (unumber~) main::$5) ← (number) 1
Adding number conversion cast (unumber) $19-2 in (bool~) main::$0 ← (byte) main::i#2 < (number) $19-(number) 2
Adding number conversion cast (unumber) 2 in (number~) main::$1 ← (byte) main::i#3 + (number) 2
Adding number conversion cast (unumber) main::$1 in (number~) main::$1 ← (byte) main::i#3 + (unumber)(number) 2
Adding number conversion cast (unumber) 1 in (number~) main::$2 ← (byte) main::i#3 + (number) 1
Adding number conversion cast (unumber) main::$2 in (number~) main::$2 ← (byte) main::i#3 + (unumber)(number) 1
Adding number conversion cast (unumber) main::$7 in (number~) main::$7 ← (unumber~) main::$2 * (const byte) SIZEOF_WORD
Adding number conversion cast (unumber) main::$8 in (number~) main::$8 ← (unumber~) main::$1 * (const byte) SIZEOF_WORD
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast *((const word*) fibs + (unumber~) main::$4) ← (unumber)(number) 0
Inlining cast *((const word*) fibs + (unumber~) main::$5) ← (unumber)(number) 1
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast 0
Simplifying constant integer cast 0
Simplifying constant integer cast 1
Simplifying constant integer cast 1
Simplifying constant integer cast 2
Simplifying constant integer cast 1
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 2
Finalized unsigned number type (byte) 1
Successful SSA optimization PassNFinalizeNumberTypeConversions
Inferred type updated to byte in (unumber~) main::$4 ← (byte) 0 * (const byte) SIZEOF_WORD
Inferred type updated to byte in (unumber~) main::$5 ← (byte) 1 * (const byte) SIZEOF_WORD
Inferred type updated to byte in (unumber~) main::$1 ← (byte) main::i#3 + (byte) 2
Inferred type updated to byte in (unumber~) main::$2 ← (byte) main::i#3 + (byte) 1
Inferred type updated to byte in (unumber~) main::$7 ← (byte~) main::$2 * (const byte) SIZEOF_WORD
Inferred type updated to byte in (unumber~) main::$8 ← (byte~) main::$1 * (const byte) SIZEOF_WORD
Alias main::i#2 = main::i#3
Successful SSA optimization Pass2AliasElimination
Simple Condition (bool~) main::$0 [7] if((byte) main::i#2<(byte)(number) $19-(number) 2) goto main::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant right-side identified [0] (byte~) main::$4 ← (byte) 0 * (const byte) SIZEOF_WORD
Constant right-side identified [2] (byte~) main::$5 ← (byte) 1 * (const byte) SIZEOF_WORD
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte) main::$4 = 0*SIZEOF_WORD
Constant (const byte) main::$5 = 1*SIZEOF_WORD
Constant (const byte) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Simplifying constant evaluating to zero (byte) 0*(const byte) SIZEOF_WORD in
Successful SSA optimization PassNSimplifyConstantZero
Simplifying expression containing zero fibs in [1] *((const word*) fibs + (const byte) main::$4) ← (byte) 0
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused constant (const byte) main::$4
Successful SSA optimization PassNEliminateUnusedVars
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Rewriting multiplication to use shift [6] (byte~) main::$6 ← (byte) main::i#2 * (const byte) SIZEOF_WORD
Rewriting multiplication to use shift [7] (byte~) main::$7 ← (byte~) main::$2 * (const byte) SIZEOF_WORD
Rewriting multiplication to use shift [9] (byte~) main::$8 ← (byte~) main::$1 * (const byte) SIZEOF_WORD
Successful SSA optimization Pass2MultiplyToShiftRewriting
Inlining constant with var siblings (const byte) main::i#0
Constant inlined main::$5 = (byte) 1*(const byte) SIZEOF_WORD
Constant inlined main::i#0 = (byte) 0
Successful SSA optimization Pass2ConstantInlining
Consolidated array index constant in *(fibs+1*SIZEOF_WORD)
Successful SSA optimization Pass2ConstantAdditionElimination
CALL GRAPH
Created 1 initial phi equivalence classes
Coalesced [13] main::i#4 ← main::i#1
Coalesced down to 1 phi equivalence classes
FINAL CONTROL FLOW GRAPH
(void()) main()
main: scope:[main] from
[0] *((const word*) fibs) ← (byte) 0
[1] *((const word*) fibs+(byte) 1*(const byte) SIZEOF_WORD) ← (byte) 1
to:main::@1
main::@1: scope:[main] from main main::@2
[2] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
[3] if((byte) main::i#2<(byte)(number) $19-(number) 2) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[4] return
to:@return
main::@2: scope:[main] from main::@1
[5] (byte~) main::$1 ← (byte) main::i#2 + (byte) 2
[6] (byte~) main::$2 ← (byte) main::i#2 + (byte) 1
[7] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1
[8] (byte~) main::$7 ← (byte~) main::$2 << (byte) 1
[9] (word~) main::$3 ← *((const word*) fibs + (byte~) main::$6) + *((const word*) fibs + (byte~) main::$7)
[10] (byte~) main::$8 ← (byte~) main::$1 << (byte) 1
[11] *((const word*) fibs + (byte~) main::$8) ← (word~) main::$3
[12] (byte) main::i#1 ← ++ (byte) main::i#2
to:main::@1
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte~) main::$1 4.4
(byte~) main::$2 11.0
(word~) main::$3 11.0
(byte~) main::$6 11.0
(byte~) main::$7 22.0
(byte~) main::$8 22.0
(byte) main::i
(byte) main::i#1 22.0
(byte) main::i#2 7.333333333333334
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
Added variable main::$1 to live range equivalence class [ main::$1 ]
Added variable main::$2 to live range equivalence class [ main::$2 ]
Added variable main::$6 to live range equivalence class [ main::$6 ]
Added variable main::$7 to live range equivalence class [ main::$7 ]
Added variable main::$3 to live range equivalence class [ main::$3 ]
Added variable main::$8 to live range equivalence class [ main::$8 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ main::$1 ]
[ main::$2 ]
[ main::$6 ]
[ main::$7 ]
[ main::$3 ]
[ main::$8 ]
Allocated zp[1]:2 [ main::i#2 main::i#1 ]
Allocated zp[1]:3 [ main::$1 ]
Allocated zp[1]:4 [ main::$2 ]
Allocated zp[1]:5 [ main::$6 ]
Allocated zp[1]:6 [ main::$7 ]
Allocated zp[2]:7 [ main::$3 ]
Allocated zp[1]:9 [ main::$8 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Test array index pointer rewriting
// 16bit array with 8bit index
// Fibonacci calculation uses adjacent indices inside the loop
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_WORD = 2
// main
main: {
.label __1 = 3
.label __2 = 4
.label __3 = 7
.label __6 = 5
.label __7 = 6
.label __8 = 9
.label i = 2
// [0] *((const word*) fibs) ← (byte) 0 -- _deref_pwuc1=vbuc2
lda #0
sta fibs+1
lda #<0
sta fibs
// [1] *((const word*) fibs+(byte) 1*(const byte) SIZEOF_WORD) ← (byte) 1 -- _deref_pwuc1=vbuc2
lda #0
sta fibs+1*SIZEOF_WORD+1
lda #<1
sta fibs+1*SIZEOF_WORD
// [2] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [2] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z i
jmp __b1
// main::@1
__b1:
// [3] if((byte) main::i#2<(byte)(number) $19-(number) 2) goto main::@2 -- vbuz1_lt_vbuc1_then_la1
lda.z i
cmp #$19-2
bcc __b2
jmp __breturn
// main::@return
__breturn:
// [4] return
rts
// main::@2
__b2:
// [5] (byte~) main::$1 ← (byte) main::i#2 + (byte) 2 -- vbuz1=vbuz2_plus_2
lda.z i
clc
adc #2
sta.z __1
// [6] (byte~) main::$2 ← (byte) main::i#2 + (byte) 1 -- vbuz1=vbuz2_plus_1
ldy.z i
iny
sty.z __2
// [7] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuz2_rol_1
lda.z i
asl
sta.z __6
// [8] (byte~) main::$7 ← (byte~) main::$2 << (byte) 1 -- vbuz1=vbuz2_rol_1
lda.z __2
asl
sta.z __7
// [9] (word~) main::$3 ← *((const word*) fibs + (byte~) main::$6) + *((const word*) fibs + (byte~) main::$7) -- vwuz1=pwuc1_derefidx_vbuz2_plus_pwuc1_derefidx_vbuz3
ldx.z __6
ldy.z __7
lda fibs,x
clc
adc fibs,y
sta.z __3
lda fibs+1,x
adc fibs+1,y
sta.z __3+1
// [10] (byte~) main::$8 ← (byte~) main::$1 << (byte) 1 -- vbuz1=vbuz2_rol_1
lda.z __1
asl
sta.z __8
// [11] *((const word*) fibs + (byte~) main::$8) ← (word~) main::$3 -- pwuc1_derefidx_vbuz1=vwuz2
ldy.z __8
lda.z __3
sta fibs,y
lda.z __3+1
sta fibs+1,y
// [12] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc.z i
// [2] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [2] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
fibs: .fill 2*$19, 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] *((const word*) fibs) ← (byte) 0 [ ] ( [ ] { } ) always clobbers reg byte a
Statement [1] *((const word*) fibs+(byte) 1*(const byte) SIZEOF_WORD) ← (byte) 1 [ ] ( [ ] { } ) always clobbers reg byte a
Statement [7] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$1 main::$2 main::$6 ] ( [ main::i#2 main::$1 main::$2 main::$6 ] { } ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::i#2 main::i#1 ]
Removing always clobbered register reg byte a as potential for zp[1]:3 [ main::$1 ]
Removing always clobbered register reg byte a as potential for zp[1]:4 [ main::$2 ]
Statement [8] (byte~) main::$7 ← (byte~) main::$2 << (byte) 1 [ main::i#2 main::$1 main::$6 main::$7 ] ( [ main::i#2 main::$1 main::$6 main::$7 ] { } ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp[1]:5 [ main::$6 ]
Statement [9] (word~) main::$3 ← *((const word*) fibs + (byte~) main::$6) + *((const word*) fibs + (byte~) main::$7) [ main::i#2 main::$1 main::$3 ] ( [ main::i#2 main::$1 main::$3 ] { } ) always clobbers reg byte a
Statement [10] (byte~) main::$8 ← (byte~) main::$1 << (byte) 1 [ main::i#2 main::$3 main::$8 ] ( [ main::i#2 main::$3 main::$8 ] { } ) always clobbers reg byte a
Statement [11] *((const word*) fibs + (byte~) main::$8) ← (word~) main::$3 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
Statement [0] *((const word*) fibs) ← (byte) 0 [ ] ( [ ] { } ) always clobbers reg byte a
Statement [1] *((const word*) fibs+(byte) 1*(const byte) SIZEOF_WORD) ← (byte) 1 [ ] ( [ ] { } ) always clobbers reg byte a
Statement [7] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$1 main::$2 main::$6 ] ( [ main::i#2 main::$1 main::$2 main::$6 ] { } ) always clobbers reg byte a
Statement [8] (byte~) main::$7 ← (byte~) main::$2 << (byte) 1 [ main::i#2 main::$1 main::$6 main::$7 ] ( [ main::i#2 main::$1 main::$6 main::$7 ] { } ) always clobbers reg byte a
Statement [9] (word~) main::$3 ← *((const word*) fibs + (byte~) main::$6) + *((const word*) fibs + (byte~) main::$7) [ main::i#2 main::$1 main::$3 ] ( [ main::i#2 main::$1 main::$3 ] { } ) always clobbers reg byte a
Statement [10] (byte~) main::$8 ← (byte~) main::$1 << (byte) 1 [ main::i#2 main::$3 main::$8 ] ( [ main::i#2 main::$3 main::$8 ] { } ) always clobbers reg byte a
Statement [11] *((const word*) fibs + (byte~) main::$8) ← (word~) main::$3 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
Potential registers zp[1]:2 [ main::i#2 main::i#1 ] : zp[1]:2 , reg byte x , reg byte y ,
Potential registers zp[1]:3 [ main::$1 ] : zp[1]:3 , reg byte x , reg byte y ,
Potential registers zp[1]:4 [ main::$2 ] : zp[1]:4 , reg byte x , reg byte y ,
Potential registers zp[1]:5 [ main::$6 ] : zp[1]:5 , reg byte x , reg byte y ,
Potential registers zp[1]:6 [ main::$7 ] : zp[1]:6 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[2]:7 [ main::$3 ] : zp[2]:7 ,
Potential registers zp[1]:9 [ main::$8 ] : zp[1]:9 , reg byte a , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 29.33: zp[1]:2 [ main::i#2 main::i#1 ] 22: zp[1]:6 [ main::$7 ] 22: zp[1]:9 [ main::$8 ] 11: zp[1]:4 [ main::$2 ] 11: zp[1]:5 [ main::$6 ] 11: zp[2]:7 [ main::$3 ] 4.4: zp[1]:3 [ main::$1 ]
Uplift Scope []
Uplifting [main] best 1105 combination zp[1]:2 [ main::i#2 main::i#1 ] reg byte a [ main::$7 ] reg byte a [ main::$8 ] reg byte x [ main::$2 ] zp[1]:5 [ main::$6 ] zp[2]:7 [ main::$3 ] zp[1]:3 [ main::$1 ]
Limited combination testing to 100 combinations of 1296 possible.
Uplifting [] best 1105 combination
Attempting to uplift remaining variables inzp[1]:2 [ main::i#2 main::i#1 ]
Uplifting [main] best 1105 combination zp[1]:2 [ main::i#2 main::i#1 ]
Attempting to uplift remaining variables inzp[1]:5 [ main::$6 ]
Uplifting [main] best 1065 combination reg byte y [ main::$6 ]
Attempting to uplift remaining variables inzp[1]:3 [ main::$1 ]
Uplifting [main] best 1065 combination zp[1]:3 [ main::$1 ]
Allocated (was zp[2]:7) zp[2]:4 [ main::$3 ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test array index pointer rewriting
// 16bit array with 8bit index
// Fibonacci calculation uses adjacent indices inside the loop
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_WORD = 2
// main
main: {
.label __1 = 3
.label __3 = 4
.label i = 2
// [0] *((const word*) fibs) ← (byte) 0 -- _deref_pwuc1=vbuc2
lda #0
sta fibs+1
lda #<0
sta fibs
// [1] *((const word*) fibs+(byte) 1*(const byte) SIZEOF_WORD) ← (byte) 1 -- _deref_pwuc1=vbuc2
lda #0
sta fibs+1*SIZEOF_WORD+1
lda #<1
sta fibs+1*SIZEOF_WORD
// [2] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [2] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z i
jmp __b1
// main::@1
__b1:
// [3] if((byte) main::i#2<(byte)(number) $19-(number) 2) goto main::@2 -- vbuz1_lt_vbuc1_then_la1
lda.z i
cmp #$19-2
bcc __b2
jmp __breturn
// main::@return
__breturn:
// [4] return
rts
// main::@2
__b2:
// [5] (byte~) main::$1 ← (byte) main::i#2 + (byte) 2 -- vbuz1=vbuz2_plus_2
lda.z i
clc
adc #2
sta.z __1
// [6] (byte~) main::$2 ← (byte) main::i#2 + (byte) 1 -- vbuxx=vbuz1_plus_1
ldx.z i
inx
// [7] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1 -- vbuyy=vbuz1_rol_1
lda.z i
asl
tay
// [8] (byte~) main::$7 ← (byte~) main::$2 << (byte) 1 -- vbuaa=vbuxx_rol_1
txa
asl
// [9] (word~) main::$3 ← *((const word*) fibs + (byte~) main::$6) + *((const word*) fibs + (byte~) main::$7) -- vwuz1=pwuc1_derefidx_vbuyy_plus_pwuc1_derefidx_vbuaa
tax
lda fibs,x
clc
adc fibs,y
sta.z __3
lda fibs+1,x
adc fibs+1,y
sta.z __3+1
// [10] (byte~) main::$8 ← (byte~) main::$1 << (byte) 1 -- vbuaa=vbuz1_rol_1
lda.z __1
asl
// [11] *((const word*) fibs + (byte~) main::$8) ← (word~) main::$3 -- pwuc1_derefidx_vbuaa=vwuz1
tay
lda.z __3
sta fibs,y
lda.z __3+1
sta fibs+1,y
// [12] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc.z i
// [2] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [2] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
fibs: .fill 2*$19, 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction lda #<0
Removing instruction lda #0
Succesful ASM optimization Pass5UnnecesaryLoadElimination
Removing instruction __b1_from_main:
Removing instruction __breturn:
Removing instruction __b1_from___b2:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(const byte) SIZEOF_WORD = (byte) 2
(const word*) fibs[(number) $19] = { fill( $19, 0) }
(void()) main()
(byte~) main::$1 zp[1]:3 4.4
(byte~) main::$2 reg byte x 11.0
(word~) main::$3 zp[2]:4 11.0
(byte~) main::$6 reg byte y 11.0
(byte~) main::$7 reg byte a 22.0
(byte~) main::$8 reg byte a 22.0
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#1 i zp[1]:2 22.0
(byte) main::i#2 i zp[1]:2 7.333333333333334
zp[1]:2 [ main::i#2 main::i#1 ]
zp[1]:3 [ main::$1 ]
reg byte x [ main::$2 ]
reg byte y [ main::$6 ]
reg byte a [ main::$7 ]
zp[2]:4 [ main::$3 ]
reg byte a [ main::$8 ]
FINAL ASSEMBLER
Score: 1001
// File Comments
// Test array index pointer rewriting
// 16bit array with 8bit index
// Fibonacci calculation uses adjacent indices inside the loop
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_WORD = 2
// main
main: {
.label __1 = 3
.label __3 = 4
.label i = 2
// fibs[0] = 0
// [0] *((const word*) fibs) ← (byte) 0 -- _deref_pwuc1=vbuc2
lda #0
sta fibs+1
sta fibs
// fibs[1] = 1
// [1] *((const word*) fibs+(byte) 1*(const byte) SIZEOF_WORD) ← (byte) 1 -- _deref_pwuc1=vbuc2
sta fibs+1*SIZEOF_WORD+1
lda #<1
sta fibs+1*SIZEOF_WORD
// [2] phi from main to main::@1 [phi:main->main::@1]
// [2] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z i
// main::@1
__b1:
// for(char i=0;i<NUM_FIBS-2;i++)
// [3] if((byte) main::i#2<(byte)(number) $19-(number) 2) goto main::@2 -- vbuz1_lt_vbuc1_then_la1
lda.z i
cmp #$19-2
bcc __b2
// main::@return
// }
// [4] return
rts
// main::@2
__b2:
// i+2
// [5] (byte~) main::$1 ← (byte) main::i#2 + (byte) 2 -- vbuz1=vbuz2_plus_2
lda.z i
clc
adc #2
sta.z __1
// i+1
// [6] (byte~) main::$2 ← (byte) main::i#2 + (byte) 1 -- vbuxx=vbuz1_plus_1
ldx.z i
inx
// fibs[i]+fibs[i+1]
// [7] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1 -- vbuyy=vbuz1_rol_1
lda.z i
asl
tay
// [8] (byte~) main::$7 ← (byte~) main::$2 << (byte) 1 -- vbuaa=vbuxx_rol_1
txa
asl
// [9] (word~) main::$3 ← *((const word*) fibs + (byte~) main::$6) + *((const word*) fibs + (byte~) main::$7) -- vwuz1=pwuc1_derefidx_vbuyy_plus_pwuc1_derefidx_vbuaa
tax
lda fibs,x
clc
adc fibs,y
sta.z __3
lda fibs+1,x
adc fibs+1,y
sta.z __3+1
// fibs[i+2] = fibs[i]+fibs[i+1]
// [10] (byte~) main::$8 ← (byte~) main::$1 << (byte) 1 -- vbuaa=vbuz1_rol_1
lda.z __1
asl
// [11] *((const word*) fibs + (byte~) main::$8) ← (word~) main::$3 -- pwuc1_derefidx_vbuaa=vwuz1
tay
lda.z __3
sta fibs,y
lda.z __3+1
sta fibs+1,y
// for(char i=0;i<NUM_FIBS-2;i++)
// [12] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc.z i
// [2] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
// [2] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
fibs: .fill 2*$19, 0

View File

@ -0,0 +1,23 @@
(const byte) SIZEOF_WORD = (byte) 2
(const word*) fibs[(number) $19] = { fill( $19, 0) }
(void()) main()
(byte~) main::$1 zp[1]:3 4.4
(byte~) main::$2 reg byte x 11.0
(word~) main::$3 zp[2]:4 11.0
(byte~) main::$6 reg byte y 11.0
(byte~) main::$7 reg byte a 22.0
(byte~) main::$8 reg byte a 22.0
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#1 i zp[1]:2 22.0
(byte) main::i#2 i zp[1]:2 7.333333333333334
zp[1]:2 [ main::i#2 main::i#1 ]
zp[1]:3 [ main::$1 ]
reg byte x [ main::$2 ]
reg byte y [ main::$6 ]
reg byte a [ main::$7 ]
zp[2]:4 [ main::$3 ]
reg byte a [ main::$8 ]

View File

@ -0,0 +1,69 @@
// Test array index pointer rewriting
// 8bit array with 16bit index
// Fibonacci calculation uses adjacent indices inside the loop
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
main: {
.label i = 2
.label __4 = 4
.label __5 = 6
.label __6 = 8
// fibs[0] = 0
lda #0
sta fibs
// fibs[1] = 1
lda #1
sta fibs+1
lda #<0
sta.z i
sta.z i+1
__b1:
// for(unsigned short i=0;i<NUM_FIBS-2;i++)
lda.z i+1
bne !+
lda.z i
cmp #$19-2
bcc __b2
!:
// }
rts
__b2:
// fibs[i]+fibs[i+1]
lda.z i
clc
adc #<fibs
sta.z __4
lda.z i+1
adc #>fibs
sta.z __4+1
lda.z i
clc
adc #<fibs+1
sta.z __5
lda.z i+1
adc #>fibs+1
sta.z __5+1
ldy #0
lda (__4),y
clc
adc (__5),y
tax
// fibs[i+2] = fibs[i]+fibs[i+1]
lda.z i
clc
adc #<fibs+2
sta.z __6
lda.z i+1
adc #>fibs+2
sta.z __6+1
txa
sta (__6),y
// for(unsigned short i=0;i<NUM_FIBS-2;i++)
inc.z i
bne !+
inc.z i+1
!:
jmp __b1
}
fibs: .fill $19, 0

View File

@ -0,0 +1,21 @@
(void()) main()
main: scope:[main] from
[0] *((const byte*) fibs) ← (byte) 0
[1] *((const byte*) fibs+(byte) 1) ← (byte) 1
to:main::@1
main::@1: scope:[main] from main main::@2
[2] (word) main::i#2 ← phi( main/(word) 0 main::@2/(word) main::i#1 )
[3] if((word) main::i#2<(byte)(number) $19-(number) 2) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[4] return
to:@return
main::@2: scope:[main] from main::@1
[5] (byte*~) main::$4 ← (const byte*) fibs + (word) main::i#2
[6] (byte*~) main::$5 ← (const byte*) fibs+(byte) 1 + (word) main::i#2
[7] (byte~) main::$3 ← *((byte*~) main::$4) + *((byte*~) main::$5)
[8] (byte*~) main::$6 ← (const byte*) fibs+(byte) 2 + (word) main::i#2
[9] *((byte*~) main::$6) ← (byte~) main::$3
[10] (word) main::i#1 ← ++ (word) main::i#2
to:main::@1

View File

@ -0,0 +1,519 @@
CONTROL FLOW GRAPH SSA
(void()) main()
main: scope:[main] from __start
*((const byte*) fibs + (number) 0) ← (number) 0
*((const byte*) fibs + (number) 1) ← (number) 1
(word) main::i#0 ← (word) 0
to:main::@1
main::@1: scope:[main] from main main::@2
(word) main::i#2 ← phi( main/(word) main::i#0 main::@2/(word) main::i#1 )
(bool~) main::$0 ← (word) main::i#2 < (number) $19-(number) 2
if((bool~) main::$0) goto main::@2
to:main::@return
main::@2: scope:[main] from main::@1
(word) main::i#3 ← phi( main::@1/(word) main::i#2 )
(number~) main::$1 ← (word) main::i#3 + (number) 2
(number~) main::$2 ← (word) main::i#3 + (number) 1
(byte~) main::$3 ← *((const byte*) fibs + (word) main::i#3) + *((const byte*) fibs + (number~) main::$2)
*((const byte*) fibs + (number~) main::$1) ← (byte~) main::$3
(word) main::i#1 ← ++ (word) main::i#3
to:main::@1
main::@return: scope:[main] from main::@1
return
to:@return
(void()) __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
(void()) __start()
(label) __start::@1
(label) __start::@return
(const byte*) fibs[(number) $19] = { fill( $19, 0) }
(void()) main()
(bool~) main::$0
(number~) main::$1
(number~) main::$2
(byte~) main::$3
(label) main::@1
(label) main::@2
(label) main::@return
(word) main::i
(word) main::i#0
(word) main::i#1
(word) main::i#2
(word) main::i#3
Adding number conversion cast (unumber) 0 in *((const byte*) fibs + (number) 0) ← (number) 0
Adding number conversion cast (unumber) 0 in *((const byte*) fibs + (number) 0) ← ((unumber)) (number) 0
Adding number conversion cast (unumber) 1 in *((const byte*) fibs + (number) 1) ← (number) 1
Adding number conversion cast (unumber) 1 in *((const byte*) fibs + (number) 1) ← ((unumber)) (number) 1
Adding number conversion cast (unumber) $19-2 in (bool~) main::$0 ← (word) main::i#2 < (number) $19-(number) 2
Adding number conversion cast (unumber) 2 in (number~) main::$1 ← (word) main::i#3 + (number) 2
Adding number conversion cast (unumber) main::$1 in (number~) main::$1 ← (word) main::i#3 + (unumber)(number) 2
Adding number conversion cast (unumber) 1 in (number~) main::$2 ← (word) main::i#3 + (number) 1
Adding number conversion cast (unumber) main::$2 in (number~) main::$2 ← (word) main::i#3 + (unumber)(number) 1
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast *((const byte*) fibs + (unumber)(number) 0) ← (unumber)(number) 0
Inlining cast *((const byte*) fibs + (unumber)(number) 1) ← (unumber)(number) 1
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast 0
Simplifying constant integer cast 0
Simplifying constant integer cast 1
Simplifying constant integer cast 1
Simplifying constant integer cast 2
Simplifying constant integer cast 1
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 2
Finalized unsigned number type (byte) 1
Successful SSA optimization PassNFinalizeNumberTypeConversions
Inferred type updated to word in (unumber~) main::$1 ← (word) main::i#3 + (byte) 2
Inferred type updated to word in (unumber~) main::$2 ← (word) main::i#3 + (byte) 1
Alias main::i#2 = main::i#3
Successful SSA optimization Pass2AliasElimination
Simple Condition (bool~) main::$0 [5] if((word) main::i#2<(byte)(number) $19-(number) 2) goto main::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const word) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
De-inlining pointer[w] to *(pointer+w) [8] (byte~) main::$3 ← *((const byte*) fibs + (word) main::i#2) + *((const byte*) fibs + (word~) main::$2)
De-inlining pointer[w] to *(pointer+w) [8] (byte~) main::$3 ← *((byte*~) main::$4) + *((const byte*) fibs + (word~) main::$2)
De-inlining pointer[w] to *(pointer+w) [9] *((const byte*) fibs + (word~) main::$1) ← (byte~) main::$3
Successful SSA optimization Pass2DeInlineWordDerefIdx
Simplifying expression containing zero fibs in [0] *((const byte*) fibs + (byte) 0) ← (byte) 0
Successful SSA optimization PassNSimplifyExpressionWithZero
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Inlining constant with var siblings (const word) main::i#0
Constant inlined main::i#0 = (word) 0
Successful SSA optimization Pass2ConstantInlining
Consolidated array index constant in *(fibs+1)
Consolidated constant in assignment main::$5
Consolidated constant in assignment main::$6
Successful SSA optimization Pass2ConstantAdditionElimination
Alias main::i#2 = main::$1 main::$2
Successful SSA optimization Pass2AliasElimination
CALL GRAPH
Created 1 initial phi equivalence classes
Coalesced [11] main::i#4 ← main::i#1
Coalesced down to 1 phi equivalence classes
FINAL CONTROL FLOW GRAPH
(void()) main()
main: scope:[main] from
[0] *((const byte*) fibs) ← (byte) 0
[1] *((const byte*) fibs+(byte) 1) ← (byte) 1
to:main::@1
main::@1: scope:[main] from main main::@2
[2] (word) main::i#2 ← phi( main/(word) 0 main::@2/(word) main::i#1 )
[3] if((word) main::i#2<(byte)(number) $19-(number) 2) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[4] return
to:@return
main::@2: scope:[main] from main::@1
[5] (byte*~) main::$4 ← (const byte*) fibs + (word) main::i#2
[6] (byte*~) main::$5 ← (const byte*) fibs+(byte) 1 + (word) main::i#2
[7] (byte~) main::$3 ← *((byte*~) main::$4) + *((byte*~) main::$5)
[8] (byte*~) main::$6 ← (const byte*) fibs+(byte) 2 + (word) main::i#2
[9] *((byte*~) main::$6) ← (byte~) main::$3
[10] (word) main::i#1 ← ++ (word) main::i#2
to:main::@1
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte~) main::$3 11.0
(byte*~) main::$4 11.0
(byte*~) main::$5 22.0
(byte*~) main::$6 22.0
(word) main::i
(word) main::i#1 22.0
(word) main::i#2 9.428571428571429
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
Added variable main::$4 to live range equivalence class [ main::$4 ]
Added variable main::$5 to live range equivalence class [ main::$5 ]
Added variable main::$3 to live range equivalence class [ main::$3 ]
Added variable main::$6 to live range equivalence class [ main::$6 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ main::$4 ]
[ main::$5 ]
[ main::$3 ]
[ main::$6 ]
Allocated zp[2]:2 [ main::i#2 main::i#1 ]
Allocated zp[2]:4 [ main::$4 ]
Allocated zp[2]:6 [ main::$5 ]
Allocated zp[1]:8 [ main::$3 ]
Allocated zp[2]:9 [ main::$6 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Test array index pointer rewriting
// 8bit array with 16bit index
// Fibonacci calculation uses adjacent indices inside the loop
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
.label __3 = 8
.label i = 2
.label __4 = 4
.label __5 = 6
.label __6 = 9
// [0] *((const byte*) fibs) ← (byte) 0 -- _deref_pbuc1=vbuc2
lda #0
sta fibs
// [1] *((const byte*) fibs+(byte) 1) ← (byte) 1 -- _deref_pbuc1=vbuc2
lda #1
sta fibs+1
// [2] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [2] phi (word) main::i#2 = (word) 0 [phi:main->main::@1#0] -- vwuz1=vwuc1
lda #<0
sta.z i
lda #>0
sta.z i+1
jmp __b1
// main::@1
__b1:
// [3] if((word) main::i#2<(byte)(number) $19-(number) 2) goto main::@2 -- vwuz1_lt_vbuc1_then_la1
lda.z i+1
bne !+
lda.z i
cmp #$19-2
bcc __b2
!:
jmp __breturn
// main::@return
__breturn:
// [4] return
rts
// main::@2
__b2:
// [5] (byte*~) main::$4 ← (const byte*) fibs + (word) main::i#2 -- pbuz1=pbuc1_plus_vwuz2
lda.z i
clc
adc #<fibs
sta.z __4
lda.z i+1
adc #>fibs
sta.z __4+1
// [6] (byte*~) main::$5 ← (const byte*) fibs+(byte) 1 + (word) main::i#2 -- pbuz1=pbuc1_plus_vwuz2
lda.z i
clc
adc #<fibs+1
sta.z __5
lda.z i+1
adc #>fibs+1
sta.z __5+1
// [7] (byte~) main::$3 ← *((byte*~) main::$4) + *((byte*~) main::$5) -- vbuz1=_deref_pbuz2_plus__deref_pbuz3
ldy #0
lda (__4),y
clc
ldy #0
adc (__5),y
sta.z __3
// [8] (byte*~) main::$6 ← (const byte*) fibs+(byte) 2 + (word) main::i#2 -- pbuz1=pbuc1_plus_vwuz2
lda.z i
clc
adc #<fibs+2
sta.z __6
lda.z i+1
adc #>fibs+2
sta.z __6+1
// [9] *((byte*~) main::$6) ← (byte~) main::$3 -- _deref_pbuz1=vbuz2
lda.z __3
ldy #0
sta (__6),y
// [10] (word) main::i#1 ← ++ (word) main::i#2 -- vwuz1=_inc_vwuz1
inc.z i
bne !+
inc.z i+1
!:
// [2] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [2] phi (word) main::i#2 = (word) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
fibs: .fill $19, 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] *((const byte*) fibs) ← (byte) 0 [ ] ( [ ] { } ) always clobbers reg byte a
Statement [1] *((const byte*) fibs+(byte) 1) ← (byte) 1 [ ] ( [ ] { } ) always clobbers reg byte a
Statement [3] if((word) main::i#2<(byte)(number) $19-(number) 2) goto main::@2 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
Statement [5] (byte*~) main::$4 ← (const byte*) fibs + (word) main::i#2 [ main::i#2 main::$4 ] ( [ main::i#2 main::$4 ] { } ) always clobbers reg byte a
Statement [6] (byte*~) main::$5 ← (const byte*) fibs+(byte) 1 + (word) main::i#2 [ main::i#2 main::$4 main::$5 ] ( [ main::i#2 main::$4 main::$5 ] { } ) always clobbers reg byte a
Statement [7] (byte~) main::$3 ← *((byte*~) main::$4) + *((byte*~) main::$5) [ main::i#2 main::$3 ] ( [ main::i#2 main::$3 ] { } ) always clobbers reg byte a reg byte y
Statement [8] (byte*~) main::$6 ← (const byte*) fibs+(byte) 2 + (word) main::i#2 [ main::i#2 main::$3 main::$6 ] ( [ main::i#2 main::$3 main::$6 ] { } ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp[1]:8 [ main::$3 ]
Statement [9] *((byte*~) main::$6) ← (byte~) main::$3 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a reg byte y
Statement [0] *((const byte*) fibs) ← (byte) 0 [ ] ( [ ] { } ) always clobbers reg byte a
Statement [1] *((const byte*) fibs+(byte) 1) ← (byte) 1 [ ] ( [ ] { } ) always clobbers reg byte a
Statement [3] if((word) main::i#2<(byte)(number) $19-(number) 2) goto main::@2 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
Statement [5] (byte*~) main::$4 ← (const byte*) fibs + (word) main::i#2 [ main::i#2 main::$4 ] ( [ main::i#2 main::$4 ] { } ) always clobbers reg byte a
Statement [6] (byte*~) main::$5 ← (const byte*) fibs+(byte) 1 + (word) main::i#2 [ main::i#2 main::$4 main::$5 ] ( [ main::i#2 main::$4 main::$5 ] { } ) always clobbers reg byte a
Statement [7] (byte~) main::$3 ← *((byte*~) main::$4) + *((byte*~) main::$5) [ main::i#2 main::$3 ] ( [ main::i#2 main::$3 ] { } ) always clobbers reg byte a reg byte y
Statement [8] (byte*~) main::$6 ← (const byte*) fibs+(byte) 2 + (word) main::i#2 [ main::i#2 main::$3 main::$6 ] ( [ main::i#2 main::$3 main::$6 ] { } ) always clobbers reg byte a
Statement [9] *((byte*~) main::$6) ← (byte~) main::$3 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a reg byte y
Potential registers zp[2]:2 [ main::i#2 main::i#1 ] : zp[2]:2 ,
Potential registers zp[2]:4 [ main::$4 ] : zp[2]:4 ,
Potential registers zp[2]:6 [ main::$5 ] : zp[2]:6 ,
Potential registers zp[1]:8 [ main::$3 ] : zp[1]:8 , reg byte x , reg byte y ,
Potential registers zp[2]:9 [ main::$6 ] : zp[2]:9 ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 31.43: zp[2]:2 [ main::i#2 main::i#1 ] 22: zp[2]:6 [ main::$5 ] 22: zp[2]:9 [ main::$6 ] 11: zp[2]:4 [ main::$4 ] 11: zp[1]:8 [ main::$3 ]
Uplift Scope []
Uplifting [main] best 1293 combination zp[2]:2 [ main::i#2 main::i#1 ] zp[2]:6 [ main::$5 ] zp[2]:9 [ main::$6 ] zp[2]:4 [ main::$4 ] reg byte x [ main::$3 ]
Uplifting [] best 1293 combination
Allocated (was zp[2]:9) zp[2]:8 [ main::$6 ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test array index pointer rewriting
// 8bit array with 16bit index
// Fibonacci calculation uses adjacent indices inside the loop
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
.label i = 2
.label __4 = 4
.label __5 = 6
.label __6 = 8
// [0] *((const byte*) fibs) ← (byte) 0 -- _deref_pbuc1=vbuc2
lda #0
sta fibs
// [1] *((const byte*) fibs+(byte) 1) ← (byte) 1 -- _deref_pbuc1=vbuc2
lda #1
sta fibs+1
// [2] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [2] phi (word) main::i#2 = (word) 0 [phi:main->main::@1#0] -- vwuz1=vwuc1
lda #<0
sta.z i
lda #>0
sta.z i+1
jmp __b1
// main::@1
__b1:
// [3] if((word) main::i#2<(byte)(number) $19-(number) 2) goto main::@2 -- vwuz1_lt_vbuc1_then_la1
lda.z i+1
bne !+
lda.z i
cmp #$19-2
bcc __b2
!:
jmp __breturn
// main::@return
__breturn:
// [4] return
rts
// main::@2
__b2:
// [5] (byte*~) main::$4 ← (const byte*) fibs + (word) main::i#2 -- pbuz1=pbuc1_plus_vwuz2
lda.z i
clc
adc #<fibs
sta.z __4
lda.z i+1
adc #>fibs
sta.z __4+1
// [6] (byte*~) main::$5 ← (const byte*) fibs+(byte) 1 + (word) main::i#2 -- pbuz1=pbuc1_plus_vwuz2
lda.z i
clc
adc #<fibs+1
sta.z __5
lda.z i+1
adc #>fibs+1
sta.z __5+1
// [7] (byte~) main::$3 ← *((byte*~) main::$4) + *((byte*~) main::$5) -- vbuxx=_deref_pbuz1_plus__deref_pbuz2
ldy #0
lda (__4),y
clc
ldy #0
adc (__5),y
tax
// [8] (byte*~) main::$6 ← (const byte*) fibs+(byte) 2 + (word) main::i#2 -- pbuz1=pbuc1_plus_vwuz2
lda.z i
clc
adc #<fibs+2
sta.z __6
lda.z i+1
adc #>fibs+2
sta.z __6+1
// [9] *((byte*~) main::$6) ← (byte~) main::$3 -- _deref_pbuz1=vbuxx
txa
ldy #0
sta (__6),y
// [10] (word) main::i#1 ← ++ (word) main::i#2 -- vwuz1=_inc_vwuz1
inc.z i
bne !+
inc.z i+1
!:
// [2] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [2] phi (word) main::i#2 = (word) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
fibs: .fill $19, 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction lda #>0
Removing instruction ldy #0
Removing instruction ldy #0
Succesful ASM optimization Pass5UnnecesaryLoadElimination
Removing instruction __b1_from_main:
Removing instruction __breturn:
Removing instruction __b1_from___b2:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(const byte*) fibs[(number) $19] = { fill( $19, 0) }
(void()) main()
(byte~) main::$3 reg byte x 11.0
(byte*~) main::$4 zp[2]:4 11.0
(byte*~) main::$5 zp[2]:6 22.0
(byte*~) main::$6 zp[2]:8 22.0
(label) main::@1
(label) main::@2
(label) main::@return
(word) main::i
(word) main::i#1 i zp[2]:2 22.0
(word) main::i#2 i zp[2]:2 9.428571428571429
zp[2]:2 [ main::i#2 main::i#1 ]
zp[2]:4 [ main::$4 ]
zp[2]:6 [ main::$5 ]
reg byte x [ main::$3 ]
zp[2]:8 [ main::$6 ]
FINAL ASSEMBLER
Score: 1173
// File Comments
// Test array index pointer rewriting
// 8bit array with 16bit index
// Fibonacci calculation uses adjacent indices inside the loop
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
.label i = 2
.label __4 = 4
.label __5 = 6
.label __6 = 8
// fibs[0] = 0
// [0] *((const byte*) fibs) ← (byte) 0 -- _deref_pbuc1=vbuc2
lda #0
sta fibs
// fibs[1] = 1
// [1] *((const byte*) fibs+(byte) 1) ← (byte) 1 -- _deref_pbuc1=vbuc2
lda #1
sta fibs+1
// [2] phi from main to main::@1 [phi:main->main::@1]
// [2] phi (word) main::i#2 = (word) 0 [phi:main->main::@1#0] -- vwuz1=vwuc1
lda #<0
sta.z i
sta.z i+1
// main::@1
__b1:
// for(unsigned short i=0;i<NUM_FIBS-2;i++)
// [3] if((word) main::i#2<(byte)(number) $19-(number) 2) goto main::@2 -- vwuz1_lt_vbuc1_then_la1
lda.z i+1
bne !+
lda.z i
cmp #$19-2
bcc __b2
!:
// main::@return
// }
// [4] return
rts
// main::@2
__b2:
// fibs[i]+fibs[i+1]
// [5] (byte*~) main::$4 ← (const byte*) fibs + (word) main::i#2 -- pbuz1=pbuc1_plus_vwuz2
lda.z i
clc
adc #<fibs
sta.z __4
lda.z i+1
adc #>fibs
sta.z __4+1
// [6] (byte*~) main::$5 ← (const byte*) fibs+(byte) 1 + (word) main::i#2 -- pbuz1=pbuc1_plus_vwuz2
lda.z i
clc
adc #<fibs+1
sta.z __5
lda.z i+1
adc #>fibs+1
sta.z __5+1
// [7] (byte~) main::$3 ← *((byte*~) main::$4) + *((byte*~) main::$5) -- vbuxx=_deref_pbuz1_plus__deref_pbuz2
ldy #0
lda (__4),y
clc
adc (__5),y
tax
// fibs[i+2] = fibs[i]+fibs[i+1]
// [8] (byte*~) main::$6 ← (const byte*) fibs+(byte) 2 + (word) main::i#2 -- pbuz1=pbuc1_plus_vwuz2
lda.z i
clc
adc #<fibs+2
sta.z __6
lda.z i+1
adc #>fibs+2
sta.z __6+1
// [9] *((byte*~) main::$6) ← (byte~) main::$3 -- _deref_pbuz1=vbuxx
txa
sta (__6),y
// for(unsigned short i=0;i<NUM_FIBS-2;i++)
// [10] (word) main::i#1 ← ++ (word) main::i#2 -- vwuz1=_inc_vwuz1
inc.z i
bne !+
inc.z i+1
!:
// [2] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
// [2] phi (word) main::i#2 = (word) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
fibs: .fill $19, 0

View File

@ -0,0 +1,18 @@
(const byte*) fibs[(number) $19] = { fill( $19, 0) }
(void()) main()
(byte~) main::$3 reg byte x 11.0
(byte*~) main::$4 zp[2]:4 11.0
(byte*~) main::$5 zp[2]:6 22.0
(byte*~) main::$6 zp[2]:8 22.0
(label) main::@1
(label) main::@2
(label) main::@return
(word) main::i
(word) main::i#1 i zp[2]:2 22.0
(word) main::i#2 i zp[2]:2 9.428571428571429
zp[2]:2 [ main::i#2 main::i#1 ]
zp[2]:4 [ main::$4 ]
zp[2]:6 [ main::$5 ]
reg byte x [ main::$3 ]
zp[2]:8 [ main::$6 ]

View File

@ -0,0 +1,115 @@
// Test array index pointer rewriting
// 16bit array with 16bit index
// Fibonacci calculation uses adjacent indices inside the loop
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const SIZEOF_WORD = 2
main: {
.label __1 = 4
.label __2 = 6
.label __3 = 6
.label __6 = 8
.label __7 = 6
.label __8 = 4
.label i = 2
.label __9 = 8
.label __10 = 6
.label __11 = 4
// fibs[0] = 0
lda #0
sta fibs+1
sta fibs
// fibs[1] = 1
sta fibs+1*SIZEOF_WORD+1
lda #<1
sta fibs+1*SIZEOF_WORD
lda #<0
sta.z i
sta.z i+1
__b1:
// for(unsigned short i=0;i<NUM_FIBS-2;i++)
lda.z i+1
bne !+
lda.z i
cmp #$19-2
bcc __b2
!:
// }
rts
__b2:
// i+2
lda #2
clc
adc.z i
sta.z __1
lda #0
adc.z i+1
sta.z __1+1
// i+1
lda.z i
clc
adc #1
sta.z __2
lda.z i+1
adc #0
sta.z __2+1
// fibs[i]+fibs[i+1]
lda.z i
asl
sta.z __6
lda.z i+1
rol
sta.z __6+1
asl.z __7
rol.z __7+1
clc
lda.z __9
adc #<fibs
sta.z __9
lda.z __9+1
adc #>fibs
sta.z __9+1
clc
lda.z __10
adc #<fibs
sta.z __10
lda.z __10+1
adc #>fibs
sta.z __10+1
ldy #0
clc
lda (__3),y
adc (__9),y
pha
iny
lda (__3),y
adc (__9),y
sta (__3),y
dey
pla
sta (__3),y
// fibs[i+2] = fibs[i]+fibs[i+1]
asl.z __8
rol.z __8+1
clc
lda.z __11
adc #<fibs
sta.z __11
lda.z __11+1
adc #>fibs
sta.z __11+1
ldy #0
lda.z __3
sta (__11),y
iny
lda.z __3+1
sta (__11),y
// for(unsigned short i=0;i<NUM_FIBS-2;i++)
inc.z i
bne !+
inc.z i+1
!:
jmp __b1
}
fibs: .fill 2*$19, 0

View File

@ -0,0 +1,26 @@
(void()) main()
main: scope:[main] from
[0] *((const word*) fibs) ← (byte) 0
[1] *((const word*) fibs+(byte) 1*(const byte) SIZEOF_WORD) ← (byte) 1
to:main::@1
main::@1: scope:[main] from main main::@2
[2] (word) main::i#2 ← phi( main/(word) 0 main::@2/(word) main::i#1 )
[3] if((word) main::i#2<(byte)(number) $19-(number) 2) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[4] return
to:@return
main::@2: scope:[main] from main::@1
[5] (word~) main::$1 ← (word) main::i#2 + (byte) 2
[6] (word~) main::$2 ← (word) main::i#2 + (byte) 1
[7] (word~) main::$6 ← (word) main::i#2 << (byte) 1
[8] (word~) main::$7 ← (word~) main::$2 << (byte) 1
[9] (word*~) main::$9 ← (const word*) fibs + (word~) main::$6
[10] (word*~) main::$10 ← (const word*) fibs + (word~) main::$7
[11] (word~) main::$3 ← *((word*~) main::$9) + *((word*~) main::$10)
[12] (word~) main::$8 ← (word~) main::$1 << (byte) 1
[13] (word*~) main::$11 ← (const word*) fibs + (word~) main::$8
[14] *((word*~) main::$11) ← (word~) main::$3
[15] (word) main::i#1 ← ++ (word) main::i#2
to:main::@1

View File

@ -0,0 +1,762 @@
CONTROL FLOW GRAPH SSA
(void()) main()
main: scope:[main] from __start
(number~) main::$4 ← (number) 0 * (const byte) SIZEOF_WORD
*((const word*) fibs + (number~) main::$4) ← (number) 0
(number~) main::$5 ← (number) 1 * (const byte) SIZEOF_WORD
*((const word*) fibs + (number~) main::$5) ← (number) 1
(word) main::i#0 ← (word) 0
to:main::@1
main::@1: scope:[main] from main main::@2
(word) main::i#2 ← phi( main/(word) main::i#0 main::@2/(word) main::i#1 )
(bool~) main::$0 ← (word) main::i#2 < (number) $19-(number) 2
if((bool~) main::$0) goto main::@2
to:main::@return
main::@2: scope:[main] from main::@1
(word) main::i#3 ← phi( main::@1/(word) main::i#2 )
(number~) main::$1 ← (word) main::i#3 + (number) 2
(number~) main::$2 ← (word) main::i#3 + (number) 1
(word~) main::$6 ← (word) main::i#3 * (const byte) SIZEOF_WORD
(number~) main::$7 ← (number~) main::$2 * (const byte) SIZEOF_WORD
(word~) main::$3 ← *((const word*) fibs + (word~) main::$6) + *((const word*) fibs + (number~) main::$7)
(number~) main::$8 ← (number~) main::$1 * (const byte) SIZEOF_WORD
*((const word*) fibs + (number~) main::$8) ← (word~) main::$3
(word) main::i#1 ← ++ (word) main::i#3
to:main::@1
main::@return: scope:[main] from main::@1
return
to:@return
(void()) __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
(const byte) SIZEOF_WORD = (byte) 2
(void()) __start()
(label) __start::@1
(label) __start::@return
(const word*) fibs[(number) $19] = { fill( $19, 0) }
(void()) main()
(bool~) main::$0
(number~) main::$1
(number~) main::$2
(word~) main::$3
(number~) main::$4
(number~) main::$5
(word~) main::$6
(number~) main::$7
(number~) main::$8
(label) main::@1
(label) main::@2
(label) main::@return
(word) main::i
(word) main::i#0
(word) main::i#1
(word) main::i#2
(word) main::i#3
Adding number conversion cast (unumber) 0 in (number~) main::$4 ← (number) 0 * (const byte) SIZEOF_WORD
Adding number conversion cast (unumber) main::$4 in (number~) main::$4 ← (unumber)(number) 0 * (const byte) SIZEOF_WORD
Adding number conversion cast (unumber) 0 in *((const word*) fibs + (unumber~) main::$4) ← (number) 0
Adding number conversion cast (unumber) 1 in (number~) main::$5 ← (number) 1 * (const byte) SIZEOF_WORD
Adding number conversion cast (unumber) main::$5 in (number~) main::$5 ← (unumber)(number) 1 * (const byte) SIZEOF_WORD
Adding number conversion cast (unumber) 1 in *((const word*) fibs + (unumber~) main::$5) ← (number) 1
Adding number conversion cast (unumber) $19-2 in (bool~) main::$0 ← (word) main::i#2 < (number) $19-(number) 2
Adding number conversion cast (unumber) 2 in (number~) main::$1 ← (word) main::i#3 + (number) 2
Adding number conversion cast (unumber) main::$1 in (number~) main::$1 ← (word) main::i#3 + (unumber)(number) 2
Adding number conversion cast (unumber) 1 in (number~) main::$2 ← (word) main::i#3 + (number) 1
Adding number conversion cast (unumber) main::$2 in (number~) main::$2 ← (word) main::i#3 + (unumber)(number) 1
Adding number conversion cast (unumber) main::$7 in (number~) main::$7 ← (unumber~) main::$2 * (const byte) SIZEOF_WORD
Adding number conversion cast (unumber) main::$8 in (number~) main::$8 ← (unumber~) main::$1 * (const byte) SIZEOF_WORD
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast *((const word*) fibs + (unumber~) main::$4) ← (unumber)(number) 0
Inlining cast *((const word*) fibs + (unumber~) main::$5) ← (unumber)(number) 1
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast 0
Simplifying constant integer cast 0
Simplifying constant integer cast 1
Simplifying constant integer cast 1
Simplifying constant integer cast 2
Simplifying constant integer cast 1
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 2
Finalized unsigned number type (byte) 1
Successful SSA optimization PassNFinalizeNumberTypeConversions
Inferred type updated to byte in (unumber~) main::$4 ← (byte) 0 * (const byte) SIZEOF_WORD
Inferred type updated to byte in (unumber~) main::$5 ← (byte) 1 * (const byte) SIZEOF_WORD
Inferred type updated to word in (unumber~) main::$1 ← (word) main::i#3 + (byte) 2
Inferred type updated to word in (unumber~) main::$2 ← (word) main::i#3 + (byte) 1
Inferred type updated to word in (unumber~) main::$7 ← (word~) main::$2 * (const byte) SIZEOF_WORD
Inferred type updated to word in (unumber~) main::$8 ← (word~) main::$1 * (const byte) SIZEOF_WORD
Alias main::i#2 = main::i#3
Successful SSA optimization Pass2AliasElimination
Simple Condition (bool~) main::$0 [7] if((word) main::i#2<(byte)(number) $19-(number) 2) goto main::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant right-side identified [0] (byte~) main::$4 ← (byte) 0 * (const byte) SIZEOF_WORD
Constant right-side identified [2] (byte~) main::$5 ← (byte) 1 * (const byte) SIZEOF_WORD
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte) main::$4 = 0*SIZEOF_WORD
Constant (const byte) main::$5 = 1*SIZEOF_WORD
Constant (const word) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
De-inlining pointer[w] to *(pointer+w) [12] (word~) main::$3 ← *((const word*) fibs + (word~) main::$6) + *((const word*) fibs + (word~) main::$7)
De-inlining pointer[w] to *(pointer+w) [12] (word~) main::$3 ← *((word*~) main::$9) + *((const word*) fibs + (word~) main::$7)
De-inlining pointer[w] to *(pointer+w) [14] *((const word*) fibs + (word~) main::$8) ← (word~) main::$3
Successful SSA optimization Pass2DeInlineWordDerefIdx
Simplifying constant evaluating to zero (byte) 0*(const byte) SIZEOF_WORD in
Successful SSA optimization PassNSimplifyConstantZero
Simplifying expression containing zero fibs in [1] *((const word*) fibs + (const byte) main::$4) ← (byte) 0
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused constant (const byte) main::$4
Successful SSA optimization PassNEliminateUnusedVars
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Rewriting multiplication to use shift [6] (word~) main::$6 ← (word) main::i#2 * (const byte) SIZEOF_WORD
Rewriting multiplication to use shift [7] (word~) main::$7 ← (word~) main::$2 * (const byte) SIZEOF_WORD
Rewriting multiplication to use shift [11] (word~) main::$8 ← (word~) main::$1 * (const byte) SIZEOF_WORD
Successful SSA optimization Pass2MultiplyToShiftRewriting
Inlining constant with var siblings (const word) main::i#0
Constant inlined main::$5 = (byte) 1*(const byte) SIZEOF_WORD
Constant inlined main::i#0 = (word) 0
Successful SSA optimization Pass2ConstantInlining
Consolidated array index constant in *(fibs+1*SIZEOF_WORD)
Successful SSA optimization Pass2ConstantAdditionElimination
CALL GRAPH
Created 1 initial phi equivalence classes
Coalesced [16] main::i#4 ← main::i#1
Coalesced down to 1 phi equivalence classes
FINAL CONTROL FLOW GRAPH
(void()) main()
main: scope:[main] from
[0] *((const word*) fibs) ← (byte) 0
[1] *((const word*) fibs+(byte) 1*(const byte) SIZEOF_WORD) ← (byte) 1
to:main::@1
main::@1: scope:[main] from main main::@2
[2] (word) main::i#2 ← phi( main/(word) 0 main::@2/(word) main::i#1 )
[3] if((word) main::i#2<(byte)(number) $19-(number) 2) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[4] return
to:@return
main::@2: scope:[main] from main::@1
[5] (word~) main::$1 ← (word) main::i#2 + (byte) 2
[6] (word~) main::$2 ← (word) main::i#2 + (byte) 1
[7] (word~) main::$6 ← (word) main::i#2 << (byte) 1
[8] (word~) main::$7 ← (word~) main::$2 << (byte) 1
[9] (word*~) main::$9 ← (const word*) fibs + (word~) main::$6
[10] (word*~) main::$10 ← (const word*) fibs + (word~) main::$7
[11] (word~) main::$3 ← *((word*~) main::$9) + *((word*~) main::$10)
[12] (word~) main::$8 ← (word~) main::$1 << (byte) 1
[13] (word*~) main::$11 ← (const word*) fibs + (word~) main::$8
[14] *((word*~) main::$11) ← (word~) main::$3
[15] (word) main::i#1 ← ++ (word) main::i#2
to:main::@1
VARIABLE REGISTER WEIGHTS
(void()) main()
(word~) main::$1 3.142857142857143
(word*~) main::$10 22.0
(word*~) main::$11 22.0
(word~) main::$2 11.0
(word~) main::$3 7.333333333333333
(word~) main::$6 11.0
(word~) main::$7 11.0
(word~) main::$8 22.0
(word*~) main::$9 11.0
(word) main::i
(word) main::i#1 22.0
(word) main::i#2 5.5
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
Added variable main::$1 to live range equivalence class [ main::$1 ]
Added variable main::$2 to live range equivalence class [ main::$2 ]
Added variable main::$6 to live range equivalence class [ main::$6 ]
Added variable main::$7 to live range equivalence class [ main::$7 ]
Added variable main::$9 to live range equivalence class [ main::$9 ]
Added variable main::$10 to live range equivalence class [ main::$10 ]
Added variable main::$3 to live range equivalence class [ main::$3 ]
Added variable main::$8 to live range equivalence class [ main::$8 ]
Added variable main::$11 to live range equivalence class [ main::$11 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ main::$1 ]
[ main::$2 ]
[ main::$6 ]
[ main::$7 ]
[ main::$9 ]
[ main::$10 ]
[ main::$3 ]
[ main::$8 ]
[ main::$11 ]
Allocated zp[2]:2 [ main::i#2 main::i#1 ]
Allocated zp[2]:4 [ main::$1 ]
Allocated zp[2]:6 [ main::$2 ]
Allocated zp[2]:8 [ main::$6 ]
Allocated zp[2]:10 [ main::$7 ]
Allocated zp[2]:12 [ main::$9 ]
Allocated zp[2]:14 [ main::$10 ]
Allocated zp[2]:16 [ main::$3 ]
Allocated zp[2]:18 [ main::$8 ]
Allocated zp[2]:20 [ main::$11 ]
Warning! Unknown fragment for statement [11] (word~) main::$3 ← *((word*~) main::$9) + *((word*~) main::$10)
Missing ASM fragment Fragment not found vwuz1=_deref_pwuz2_plus__deref_pwuz3. Attempted variations vwuz1=_deref_pwuz2_plus__deref_pwuz3
File C:\c64\kickc\src\test\kc\index-pointer-rewrite-7.c
Line 13
fibs[i]+fibs[i+1]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Test array index pointer rewriting
// 16bit array with 16bit index
// Fibonacci calculation uses adjacent indices inside the loop
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_WORD = 2
// main
main: {
.label __1 = 4
.label __2 = 6
.label __3 = $10
.label __6 = 8
.label __7 = $a
.label __8 = $12
.label i = 2
.label __9 = $c
.label __10 = $e
.label __11 = $14
// [0] *((const word*) fibs) ← (byte) 0 -- _deref_pwuc1=vbuc2
lda #0
sta fibs+1
lda #<0
sta fibs
// [1] *((const word*) fibs+(byte) 1*(const byte) SIZEOF_WORD) ← (byte) 1 -- _deref_pwuc1=vbuc2
lda #0
sta fibs+1*SIZEOF_WORD+1
lda #<1
sta fibs+1*SIZEOF_WORD
// [2] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [2] phi (word) main::i#2 = (word) 0 [phi:main->main::@1#0] -- vwuz1=vwuc1
lda #<0
sta.z i
lda #>0
sta.z i+1
jmp __b1
// main::@1
__b1:
// [3] if((word) main::i#2<(byte)(number) $19-(number) 2) goto main::@2 -- vwuz1_lt_vbuc1_then_la1
lda.z i+1
bne !+
lda.z i
cmp #$19-2
bcc __b2
!:
jmp __breturn
// main::@return
__breturn:
// [4] return
rts
// main::@2
__b2:
// [5] (word~) main::$1 ← (word) main::i#2 + (byte) 2 -- vwuz1=vwuz2_plus_vbuc1
lda #2
clc
adc.z i
sta.z __1
lda #0
adc.z i+1
sta.z __1+1
// [6] (word~) main::$2 ← (word) main::i#2 + (byte) 1 -- vwuz1=vwuz2_plus_1
lda.z i
clc
adc #1
sta.z __2
lda.z i+1
adc #0
sta.z __2+1
// [7] (word~) main::$6 ← (word) main::i#2 << (byte) 1 -- vwuz1=vwuz2_rol_1
lda.z i
asl
sta.z __6
lda.z i+1
rol
sta.z __6+1
// [8] (word~) main::$7 ← (word~) main::$2 << (byte) 1 -- vwuz1=vwuz2_rol_1
lda.z __2
asl
sta.z __7
lda.z __2+1
rol
sta.z __7+1
// [9] (word*~) main::$9 ← (const word*) fibs + (word~) main::$6 -- pwuz1=pwuc1_plus_vwuz2
lda.z __6
clc
adc #<fibs
sta.z __9
lda.z __6+1
adc #>fibs
sta.z __9+1
// [10] (word*~) main::$10 ← (const word*) fibs + (word~) main::$7 -- pwuz1=pwuc1_plus_vwuz2
lda.z __7
clc
adc #<fibs
sta.z __10
lda.z __7+1
adc #>fibs
sta.z __10+1
// [11] (word~) main::$3 ← *((word*~) main::$9) + *((word*~) main::$10)
.assert "Missing ASM fragment Fragment not found vwuz1=_deref_pwuz2_plus__deref_pwuz3. Attempted variations vwuz1=_deref_pwuz2_plus__deref_pwuz3 ", 0, 1
// [12] (word~) main::$8 ← (word~) main::$1 << (byte) 1 -- vwuz1=vwuz2_rol_1
lda.z __1
asl
sta.z __8
lda.z __1+1
rol
sta.z __8+1
// [13] (word*~) main::$11 ← (const word*) fibs + (word~) main::$8 -- pwuz1=pwuc1_plus_vwuz2
lda.z __8
clc
adc #<fibs
sta.z __11
lda.z __8+1
adc #>fibs
sta.z __11+1
// [14] *((word*~) main::$11) ← (word~) main::$3 -- _deref_pwuz1=vwuz2
ldy #0
lda.z __3
sta (__11),y
iny
lda.z __3+1
sta (__11),y
// [15] (word) main::i#1 ← ++ (word) main::i#2 -- vwuz1=_inc_vwuz1
inc.z i
bne !+
inc.z i+1
!:
// [2] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [2] phi (word) main::i#2 = (word) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
fibs: .fill 2*$19, 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] *((const word*) fibs) ← (byte) 0 [ ] ( [ ] { } ) always clobbers reg byte a
Statement [1] *((const word*) fibs+(byte) 1*(const byte) SIZEOF_WORD) ← (byte) 1 [ ] ( [ ] { } ) always clobbers reg byte a
Statement [3] if((word) main::i#2<(byte)(number) $19-(number) 2) goto main::@2 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
Statement [5] (word~) main::$1 ← (word) main::i#2 + (byte) 2 [ main::i#2 main::$1 ] ( [ main::i#2 main::$1 ] { } ) always clobbers reg byte a
Statement [6] (word~) main::$2 ← (word) main::i#2 + (byte) 1 [ main::i#2 main::$1 main::$2 ] ( [ main::i#2 main::$1 main::$2 ] { } ) always clobbers reg byte a
Statement [7] (word~) main::$6 ← (word) main::i#2 << (byte) 1 [ main::i#2 main::$1 main::$2 main::$6 ] ( [ main::i#2 main::$1 main::$2 main::$6 ] { } ) always clobbers reg byte a
Statement [8] (word~) main::$7 ← (word~) main::$2 << (byte) 1 [ main::i#2 main::$1 main::$6 main::$7 ] ( [ main::i#2 main::$1 main::$6 main::$7 ] { } ) always clobbers reg byte a
Statement [9] (word*~) main::$9 ← (const word*) fibs + (word~) main::$6 [ main::i#2 main::$1 main::$7 main::$9 ] ( [ main::i#2 main::$1 main::$7 main::$9 ] { } ) always clobbers reg byte a
Statement [10] (word*~) main::$10 ← (const word*) fibs + (word~) main::$7 [ main::i#2 main::$1 main::$9 main::$10 ] ( [ main::i#2 main::$1 main::$9 main::$10 ] { } ) always clobbers reg byte a
Potential register analysis [11] main::$3 ← *(main::$9) + *(main::$10) missing fragment Fragment not found vwuz1=_deref_pwuz2_plus__deref_pwuz3. Attempted variations vwuz1=_deref_pwuz2_plus__deref_pwuz3 allocation: zp[2]:16 [ main::$3 ] zp[2]:12 [ main::$9 ] zp[2]:14 [ main::$10 ]
MISSING FRAGMENTS
Fragment not found vwuz1=_deref_pwuz2_plus__deref_pwuz3. Attempted variations vwuz1=_deref_pwuz2_plus__deref_pwuz3
Statement [11] (word~) main::$3 ← *((word*~) main::$9) + *((word*~) main::$10) [ main::i#2 main::$1 main::$3 ] ( [ main::i#2 main::$1 main::$3 ] { } ) always clobbers reg byte a reg byte x reg byte y
Statement [12] (word~) main::$8 ← (word~) main::$1 << (byte) 1 [ main::i#2 main::$3 main::$8 ] ( [ main::i#2 main::$3 main::$8 ] { } ) always clobbers reg byte a
Statement [13] (word*~) main::$11 ← (const word*) fibs + (word~) main::$8 [ main::i#2 main::$3 main::$11 ] ( [ main::i#2 main::$3 main::$11 ] { } ) always clobbers reg byte a
Statement [14] *((word*~) main::$11) ← (word~) main::$3 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a reg byte y
Potential registers zp[2]:2 [ main::i#2 main::i#1 ] : zp[2]:2 ,
Potential registers zp[2]:4 [ main::$1 ] : zp[2]:4 ,
Potential registers zp[2]:6 [ main::$2 ] : zp[2]:6 ,
Potential registers zp[2]:8 [ main::$6 ] : zp[2]:8 ,
Potential registers zp[2]:10 [ main::$7 ] : zp[2]:10 ,
Potential registers zp[2]:12 [ main::$9 ] : zp[2]:12 ,
Potential registers zp[2]:14 [ main::$10 ] : zp[2]:14 ,
Potential registers zp[2]:16 [ main::$3 ] : zp[2]:16 ,
Potential registers zp[2]:18 [ main::$8 ] : zp[2]:18 ,
Potential registers zp[2]:20 [ main::$11 ] : zp[2]:20 ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 27.5: zp[2]:2 [ main::i#2 main::i#1 ] 22: zp[2]:14 [ main::$10 ] 22: zp[2]:18 [ main::$8 ] 22: zp[2]:20 [ main::$11 ] 11: zp[2]:6 [ main::$2 ] 11: zp[2]:8 [ main::$6 ] 11: zp[2]:10 [ main::$7 ] 11: zp[2]:12 [ main::$9 ] 7.33: zp[2]:16 [ main::$3 ] 3.14: zp[2]:4 [ main::$1 ]
Uplift Scope []
Warning! Unknown fragment for statement [11] (word~) main::$3 ← *((word*~) main::$9) + *((word*~) main::$10)
Missing ASM fragment Fragment not found vwuz1=_deref_pwuz2_plus__deref_pwuz3. Attempted variations vwuz1=_deref_pwuz2_plus__deref_pwuz3
File C:\c64\kickc\src\test\kc\index-pointer-rewrite-7.c
Line 13
fibs[i]+fibs[i+1]
Uplifting [main] best 2075 combination zp[2]:2 [ main::i#2 main::i#1 ] zp[2]:14 [ main::$10 ] zp[2]:18 [ main::$8 ] zp[2]:20 [ main::$11 ] zp[2]:6 [ main::$2 ] zp[2]:8 [ main::$6 ] zp[2]:10 [ main::$7 ] zp[2]:12 [ main::$9 ] zp[2]:16 [ main::$3 ] zp[2]:4 [ main::$1 ]
Warning! Unknown fragment for statement [11] (word~) main::$3 ← *((word*~) main::$9) + *((word*~) main::$10)
Missing ASM fragment Fragment not found vwuz1=_deref_pwuz2_plus__deref_pwuz3. Attempted variations vwuz1=_deref_pwuz2_plus__deref_pwuz3
File C:\c64\kickc\src\test\kc\index-pointer-rewrite-7.c
Line 13
fibs[i]+fibs[i+1]
Uplifting [] best 2075 combination
Warning! Unknown fragment for statement [11] (word~) main::$3 ← *((word*~) main::$9) + *((word*~) main::$10)
Missing ASM fragment Fragment not found vwuz1=_deref_pwuz2_plus__deref_pwuz3. Attempted variations vwuz1=_deref_pwuz2_plus__deref_pwuz3
File C:\c64\kickc\src\test\kc\index-pointer-rewrite-7.c
Line 13
fibs[i]+fibs[i+1]
Coalescing zero page register [ zp[2]:4 [ main::$1 ] ] with [ zp[2]:18 [ main::$8 ] ] - score: 1
Warning! Unknown fragment for statement [11] (word~) main::$3 ← *((word*~) main::$9) + *((word*~) main::$10)
Missing ASM fragment Fragment not found vwuz1=_deref_pwuz2_plus__deref_pwuz3. Attempted variations vwuz1=_deref_pwuz2_plus__deref_pwuz3
File C:\c64\kickc\src\test\kc\index-pointer-rewrite-7.c
Line 13
fibs[i]+fibs[i+1]
Coalescing zero page register [ zp[2]:6 [ main::$2 ] ] with [ zp[2]:10 [ main::$7 ] ] - score: 1
Warning! Unknown fragment for statement [11] (word~) main::$3 ← *((word*~) main::$9) + *((word*~) main::$10)
Missing ASM fragment Fragment not found vwuz1=_deref_pwuz2_plus__deref_pwuz3. Attempted variations vwuz1=_deref_pwuz2_plus__deref_pwuz3
File C:\c64\kickc\src\test\kc\index-pointer-rewrite-7.c
Line 13
fibs[i]+fibs[i+1]
Coalescing zero page register [ zp[2]:8 [ main::$6 ] ] with [ zp[2]:12 [ main::$9 ] ] - score: 1
Coalescing zero page register [ zp[2]:14 [ main::$10 ] ] with [ zp[2]:16 [ main::$3 ] ] - score: 1
Coalescing zero page register [ zp[2]:4 [ main::$1 main::$8 ] ] with [ zp[2]:20 [ main::$11 ] ] - score: 1
Coalescing zero page register [ zp[2]:6 [ main::$2 main::$7 ] ] with [ zp[2]:14 [ main::$10 main::$3 ] ] - score: 1
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test array index pointer rewriting
// 16bit array with 16bit index
// Fibonacci calculation uses adjacent indices inside the loop
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_WORD = 2
// main
main: {
.label __1 = 4
.label __2 = 6
.label __3 = 6
.label __6 = 8
.label __7 = 6
.label __8 = 4
.label i = 2
.label __9 = 8
.label __10 = 6
.label __11 = 4
// [0] *((const word*) fibs) ← (byte) 0 -- _deref_pwuc1=vbuc2
lda #0
sta fibs+1
lda #<0
sta fibs
// [1] *((const word*) fibs+(byte) 1*(const byte) SIZEOF_WORD) ← (byte) 1 -- _deref_pwuc1=vbuc2
lda #0
sta fibs+1*SIZEOF_WORD+1
lda #<1
sta fibs+1*SIZEOF_WORD
// [2] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [2] phi (word) main::i#2 = (word) 0 [phi:main->main::@1#0] -- vwuz1=vwuc1
lda #<0
sta.z i
lda #>0
sta.z i+1
jmp __b1
// main::@1
__b1:
// [3] if((word) main::i#2<(byte)(number) $19-(number) 2) goto main::@2 -- vwuz1_lt_vbuc1_then_la1
lda.z i+1
bne !+
lda.z i
cmp #$19-2
bcc __b2
!:
jmp __breturn
// main::@return
__breturn:
// [4] return
rts
// main::@2
__b2:
// [5] (word~) main::$1 ← (word) main::i#2 + (byte) 2 -- vwuz1=vwuz2_plus_vbuc1
lda #2
clc
adc.z i
sta.z __1
lda #0
adc.z i+1
sta.z __1+1
// [6] (word~) main::$2 ← (word) main::i#2 + (byte) 1 -- vwuz1=vwuz2_plus_1
lda.z i
clc
adc #1
sta.z __2
lda.z i+1
adc #0
sta.z __2+1
// [7] (word~) main::$6 ← (word) main::i#2 << (byte) 1 -- vwuz1=vwuz2_rol_1
lda.z i
asl
sta.z __6
lda.z i+1
rol
sta.z __6+1
// [8] (word~) main::$7 ← (word~) main::$2 << (byte) 1 -- vwuz1=vwuz1_rol_1
asl.z __7
rol.z __7+1
// [9] (word*~) main::$9 ← (const word*) fibs + (word~) main::$6 -- pwuz1=pwuc1_plus_vwuz1
clc
lda.z __9
adc #<fibs
sta.z __9
lda.z __9+1
adc #>fibs
sta.z __9+1
// [10] (word*~) main::$10 ← (const word*) fibs + (word~) main::$7 -- pwuz1=pwuc1_plus_vwuz1
clc
lda.z __10
adc #<fibs
sta.z __10
lda.z __10+1
adc #>fibs
sta.z __10+1
// [11] (word~) main::$3 ← *((word*~) main::$9) + *((word*~) main::$10) -- vwuz1=_deref_pwuz2_plus__deref_pwuz1
ldy #0
clc
lda (__3),y
adc (__9),y
pha
iny
lda (__3),y
adc (__9),y
sta (__3),y
dey
pla
sta (__3),y
// [12] (word~) main::$8 ← (word~) main::$1 << (byte) 1 -- vwuz1=vwuz1_rol_1
asl.z __8
rol.z __8+1
// [13] (word*~) main::$11 ← (const word*) fibs + (word~) main::$8 -- pwuz1=pwuc1_plus_vwuz1
clc
lda.z __11
adc #<fibs
sta.z __11
lda.z __11+1
adc #>fibs
sta.z __11+1
// [14] *((word*~) main::$11) ← (word~) main::$3 -- _deref_pwuz1=vwuz2
ldy #0
lda.z __3
sta (__11),y
iny
lda.z __3+1
sta (__11),y
// [15] (word) main::i#1 ← ++ (word) main::i#2 -- vwuz1=_inc_vwuz1
inc.z i
bne !+
inc.z i+1
!:
// [2] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [2] phi (word) main::i#2 = (word) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
fibs: .fill 2*$19, 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction lda #<0
Removing instruction lda #0
Removing instruction lda #>0
Succesful ASM optimization Pass5UnnecesaryLoadElimination
Removing instruction __b1_from_main:
Removing instruction __breturn:
Removing instruction __b1_from___b2:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(const byte) SIZEOF_WORD = (byte) 2
(const word*) fibs[(number) $19] = { fill( $19, 0) }
(void()) main()
(word~) main::$1 zp[2]:4 3.142857142857143
(word*~) main::$10 zp[2]:6 22.0
(word*~) main::$11 zp[2]:4 22.0
(word~) main::$2 zp[2]:6 11.0
(word~) main::$3 zp[2]:6 7.333333333333333
(word~) main::$6 zp[2]:8 11.0
(word~) main::$7 zp[2]:6 11.0
(word~) main::$8 zp[2]:4 22.0
(word*~) main::$9 zp[2]:8 11.0
(label) main::@1
(label) main::@2
(label) main::@return
(word) main::i
(word) main::i#1 i zp[2]:2 22.0
(word) main::i#2 i zp[2]:2 5.5
zp[2]:2 [ main::i#2 main::i#1 ]
zp[2]:4 [ main::$1 main::$8 main::$11 ]
zp[2]:6 [ main::$2 main::$7 main::$10 main::$3 ]
zp[2]:8 [ main::$6 main::$9 ]
FINAL ASSEMBLER
Score: 2361
// File Comments
// Test array index pointer rewriting
// 16bit array with 16bit index
// Fibonacci calculation uses adjacent indices inside the loop
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_WORD = 2
// main
main: {
.label __1 = 4
.label __2 = 6
.label __3 = 6
.label __6 = 8
.label __7 = 6
.label __8 = 4
.label i = 2
.label __9 = 8
.label __10 = 6
.label __11 = 4
// fibs[0] = 0
// [0] *((const word*) fibs) ← (byte) 0 -- _deref_pwuc1=vbuc2
lda #0
sta fibs+1
sta fibs
// fibs[1] = 1
// [1] *((const word*) fibs+(byte) 1*(const byte) SIZEOF_WORD) ← (byte) 1 -- _deref_pwuc1=vbuc2
sta fibs+1*SIZEOF_WORD+1
lda #<1
sta fibs+1*SIZEOF_WORD
// [2] phi from main to main::@1 [phi:main->main::@1]
// [2] phi (word) main::i#2 = (word) 0 [phi:main->main::@1#0] -- vwuz1=vwuc1
lda #<0
sta.z i
sta.z i+1
// main::@1
__b1:
// for(unsigned short i=0;i<NUM_FIBS-2;i++)
// [3] if((word) main::i#2<(byte)(number) $19-(number) 2) goto main::@2 -- vwuz1_lt_vbuc1_then_la1
lda.z i+1
bne !+
lda.z i
cmp #$19-2
bcc __b2
!:
// main::@return
// }
// [4] return
rts
// main::@2
__b2:
// i+2
// [5] (word~) main::$1 ← (word) main::i#2 + (byte) 2 -- vwuz1=vwuz2_plus_vbuc1
lda #2
clc
adc.z i
sta.z __1
lda #0
adc.z i+1
sta.z __1+1
// i+1
// [6] (word~) main::$2 ← (word) main::i#2 + (byte) 1 -- vwuz1=vwuz2_plus_1
lda.z i
clc
adc #1
sta.z __2
lda.z i+1
adc #0
sta.z __2+1
// fibs[i]+fibs[i+1]
// [7] (word~) main::$6 ← (word) main::i#2 << (byte) 1 -- vwuz1=vwuz2_rol_1
lda.z i
asl
sta.z __6
lda.z i+1
rol
sta.z __6+1
// [8] (word~) main::$7 ← (word~) main::$2 << (byte) 1 -- vwuz1=vwuz1_rol_1
asl.z __7
rol.z __7+1
// [9] (word*~) main::$9 ← (const word*) fibs + (word~) main::$6 -- pwuz1=pwuc1_plus_vwuz1
clc
lda.z __9
adc #<fibs
sta.z __9
lda.z __9+1
adc #>fibs
sta.z __9+1
// [10] (word*~) main::$10 ← (const word*) fibs + (word~) main::$7 -- pwuz1=pwuc1_plus_vwuz1
clc
lda.z __10
adc #<fibs
sta.z __10
lda.z __10+1
adc #>fibs
sta.z __10+1
// [11] (word~) main::$3 ← *((word*~) main::$9) + *((word*~) main::$10) -- vwuz1=_deref_pwuz2_plus__deref_pwuz1
ldy #0
clc
lda (__3),y
adc (__9),y
pha
iny
lda (__3),y
adc (__9),y
sta (__3),y
dey
pla
sta (__3),y
// fibs[i+2] = fibs[i]+fibs[i+1]
// [12] (word~) main::$8 ← (word~) main::$1 << (byte) 1 -- vwuz1=vwuz1_rol_1
asl.z __8
rol.z __8+1
// [13] (word*~) main::$11 ← (const word*) fibs + (word~) main::$8 -- pwuz1=pwuc1_plus_vwuz1
clc
lda.z __11
adc #<fibs
sta.z __11
lda.z __11+1
adc #>fibs
sta.z __11+1
// [14] *((word*~) main::$11) ← (word~) main::$3 -- _deref_pwuz1=vwuz2
ldy #0
lda.z __3
sta (__11),y
iny
lda.z __3+1
sta (__11),y
// for(unsigned short i=0;i<NUM_FIBS-2;i++)
// [15] (word) main::i#1 ← ++ (word) main::i#2 -- vwuz1=_inc_vwuz1
inc.z i
bne !+
inc.z i+1
!:
// [2] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
// [2] phi (word) main::i#2 = (word) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
fibs: .fill 2*$19, 0

View File

@ -0,0 +1,23 @@
(const byte) SIZEOF_WORD = (byte) 2
(const word*) fibs[(number) $19] = { fill( $19, 0) }
(void()) main()
(word~) main::$1 zp[2]:4 3.142857142857143
(word*~) main::$10 zp[2]:6 22.0
(word*~) main::$11 zp[2]:4 22.0
(word~) main::$2 zp[2]:6 11.0
(word~) main::$3 zp[2]:6 7.333333333333333
(word~) main::$6 zp[2]:8 11.0
(word~) main::$7 zp[2]:6 11.0
(word~) main::$8 zp[2]:4 22.0
(word*~) main::$9 zp[2]:8 11.0
(label) main::@1
(label) main::@2
(label) main::@return
(word) main::i
(word) main::i#1 i zp[2]:2 22.0
(word) main::i#2 i zp[2]:2 5.5
zp[2]:2 [ main::i#2 main::i#1 ]
zp[2]:4 [ main::$1 main::$8 main::$11 ]
zp[2]:6 [ main::$2 main::$7 main::$10 main::$3 ]
zp[2]:8 [ main::$6 main::$9 ]

View File

@ -0,0 +1,40 @@
// Test array index pointer rewriting
// struct array with 8bit index
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const OFFSET_STRUCT_BALL_VEL = 1
.const OFFSET_STRUCT_BALL_SYM = 2
main: {
ldy #0
__b1:
// for(char i=0;i<NUM_BALLS;i++)
cpy #$19
bcc __b2
// }
rts
__b2:
// balls[i].pos += balls[i].vel
tya
asl
sty.z $ff
clc
adc.z $ff
tax
lda balls,x
clc
adc balls+OFFSET_STRUCT_BALL_VEL,x
sta balls,x
// balls[i].vel += 10
lda #$a
clc
adc balls+OFFSET_STRUCT_BALL_VEL,x
sta balls+OFFSET_STRUCT_BALL_VEL,x
// balls[i].sym ='*'
lda #'*'
sta balls+OFFSET_STRUCT_BALL_SYM,x
// for(char i=0;i<NUM_BALLS;i++)
iny
jmp __b1
}
balls: .fill 3*$19, 0

View File

@ -0,0 +1,20 @@
(void()) main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[1] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
[2] if((byte) main::i#2<(byte) $19) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[3] return
to:@return
main::@2: scope:[main] from main::@1
[4] (byte~) main::$4 ← (byte) main::i#2 << (byte) 1
[5] (byte~) main::$2 ← (byte~) main::$4 + (byte) main::i#2
[6] *((byte*)(const struct Ball*) balls + (byte~) main::$2) ← *((byte*)(const struct Ball*) balls + (byte~) main::$2) + *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2)
[7] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) ← *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) + (byte) $a
[8] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_SYM + (byte~) main::$2) ← (byte) '*'
[9] (byte) main::i#1 ← ++ (byte) main::i#2
to:main::@1

View File

@ -0,0 +1,407 @@
CONTROL FLOW GRAPH SSA
(void()) main()
main: scope:[main] from __start
(byte) main::i#0 ← (byte) 0
to:main::@1
main::@1: scope:[main] from main main::@2
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 )
(bool~) main::$0 ← (byte) main::i#2 < (number) $19
if((bool~) main::$0) goto main::@2
to:main::@return
main::@2: scope:[main] from main::@1
(byte) main::i#3 ← phi( main::@1/(byte) main::i#2 )
(byte~) main::$1 ← (byte) main::i#3 * (const byte) SIZEOF_STRUCT_BALL
*((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_POS + (byte~) main::$1) ← *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_POS + (byte~) main::$1) + *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$1)
(byte~) main::$2 ← (byte) main::i#3 * (const byte) SIZEOF_STRUCT_BALL
*((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) ← *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) + (number) $a
(byte~) main::$3 ← (byte) main::i#3 * (const byte) SIZEOF_STRUCT_BALL
*((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_SYM + (byte~) main::$3) ← (byte) '*'
(byte) main::i#1 ← ++ (byte) main::i#3
to:main::@1
main::@return: scope:[main] from main::@1
return
to:@return
(void()) __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
(byte) Ball::pos
(byte) Ball::sym
(byte) Ball::vel
(const byte) OFFSET_STRUCT_BALL_POS = (byte) 0
(const byte) OFFSET_STRUCT_BALL_SYM = (byte) 2
(const byte) OFFSET_STRUCT_BALL_VEL = (byte) 1
(const byte) SIZEOF_STRUCT_BALL = (byte) 3
(void()) __start()
(label) __start::@1
(label) __start::@return
(const struct Ball*) balls[(number) $19] = { fill( $19, 0) }
(void()) main()
(bool~) main::$0
(byte~) main::$1
(byte~) main::$2
(byte~) main::$3
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
(byte) main::i#3
Adding number conversion cast (unumber) $19 in (bool~) main::$0 ← (byte) main::i#2 < (number) $19
Adding number conversion cast (unumber) $a in *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) ← *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) + (number) $a
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant integer cast $19
Simplifying constant integer cast $a
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) $19
Finalized unsigned number type (byte) $a
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias main::i#2 = main::i#3
Successful SSA optimization Pass2AliasElimination
Identified duplicate assignment right side [7] (byte~) main::$2 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_BALL
Identified duplicate assignment right side [9] (byte~) main::$3 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_BALL
Successful SSA optimization Pass2DuplicateRValueIdentification
Simple Condition (bool~) main::$0 [3] if((byte) main::i#2<(byte) $19) goto main::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const byte) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Simplifying expression containing zero (byte*)balls in [5] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_POS + (byte~) main::$1) ← *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_POS + (byte~) main::$1) + *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$1)
Simplifying expression containing zero (byte*)balls in [5] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_POS + (byte~) main::$1) ← *((byte*)(const struct Ball*) balls + (byte~) main::$1) + *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$1)
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused constant (const byte) OFFSET_STRUCT_BALL_POS
Successful SSA optimization PassNEliminateUnusedVars
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Alias main::$2 = main::$1 main::$3
Successful SSA optimization Pass2AliasElimination
Rewriting multiplication to use shift and addition[2] (byte~) main::$2 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_BALL
Inlining constant with var siblings (const byte) main::i#0
Constant inlined main::i#0 = (byte) 0
Successful SSA optimization Pass2ConstantInlining
Alias main::$2 = main::$5
Successful SSA optimization Pass2AliasElimination
Eliminating unused constant (const byte) SIZEOF_STRUCT_BALL
Successful SSA optimization PassNEliminateUnusedVars
Adding NOP phi() at start of main
CALL GRAPH
Created 1 initial phi equivalence classes
Coalesced [10] main::i#4 ← main::i#1
Coalesced down to 1 phi equivalence classes
Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH
(void()) main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[1] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
[2] if((byte) main::i#2<(byte) $19) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[3] return
to:@return
main::@2: scope:[main] from main::@1
[4] (byte~) main::$4 ← (byte) main::i#2 << (byte) 1
[5] (byte~) main::$2 ← (byte~) main::$4 + (byte) main::i#2
[6] *((byte*)(const struct Ball*) balls + (byte~) main::$2) ← *((byte*)(const struct Ball*) balls + (byte~) main::$2) + *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2)
[7] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) ← *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) + (byte) $a
[8] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_SYM + (byte~) main::$2) ← (byte) '*'
[9] (byte) main::i#1 ← ++ (byte) main::i#2
to:main::@1
VARIABLE REGISTER WEIGHTS
(byte) Ball::pos
(byte) Ball::sym
(byte) Ball::vel
(void()) main()
(byte~) main::$2 25.666666666666668
(byte~) main::$4 22.0
(byte) main::i
(byte) main::i#1 22.0
(byte) main::i#2 7.857142857142857
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
Added variable main::$4 to live range equivalence class [ main::$4 ]
Added variable main::$2 to live range equivalence class [ main::$2 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ main::$4 ]
[ main::$2 ]
Allocated zp[1]:2 [ main::i#2 main::i#1 ]
Allocated zp[1]:3 [ main::$4 ]
Allocated zp[1]:4 [ main::$2 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Test array index pointer rewriting
// struct array with 8bit index
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_BALL_VEL = 1
.const OFFSET_STRUCT_BALL_SYM = 2
// main
main: {
.label __2 = 4
.label i = 2
.label __4 = 3
// [1] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [1] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z i
jmp __b1
// main::@1
__b1:
// [2] if((byte) main::i#2<(byte) $19) goto main::@2 -- vbuz1_lt_vbuc1_then_la1
lda.z i
cmp #$19
bcc __b2
jmp __breturn
// main::@return
__breturn:
// [3] return
rts
// main::@2
__b2:
// [4] (byte~) main::$4 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuz2_rol_1
lda.z i
asl
sta.z __4
// [5] (byte~) main::$2 ← (byte~) main::$4 + (byte) main::i#2 -- vbuz1=vbuz2_plus_vbuz3
lda.z __4
clc
adc.z i
sta.z __2
// [6] *((byte*)(const struct Ball*) balls + (byte~) main::$2) ← *((byte*)(const struct Ball*) balls + (byte~) main::$2) + *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) -- pbuc1_derefidx_vbuz1=pbuc1_derefidx_vbuz1_plus_pbuc2_derefidx_vbuz1
ldy.z __2
lda balls,y
clc
adc balls+OFFSET_STRUCT_BALL_VEL,y
sta balls,y
// [7] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) ← *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) + (byte) $a -- pbuc1_derefidx_vbuz1=pbuc1_derefidx_vbuz1_plus_vbuc2
lda #$a
ldy.z __2
clc
adc balls+OFFSET_STRUCT_BALL_VEL,y
sta balls+OFFSET_STRUCT_BALL_VEL,y
// [8] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_SYM + (byte~) main::$2) ← (byte) '*' -- pbuc1_derefidx_vbuz1=vbuc2
lda #'*'
ldy.z __2
sta balls+OFFSET_STRUCT_BALL_SYM,y
// [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc.z i
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [1] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
balls: .fill 3*$19, 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] (byte~) main::$4 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$4 ] ( [ main::i#2 main::$4 ] { } ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::i#2 main::i#1 ]
Statement [5] (byte~) main::$2 ← (byte~) main::$4 + (byte) main::i#2 [ main::i#2 main::$2 ] ( [ main::i#2 main::$2 ] { } ) always clobbers reg byte a
Statement [6] *((byte*)(const struct Ball*) balls + (byte~) main::$2) ← *((byte*)(const struct Ball*) balls + (byte~) main::$2) + *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) [ main::i#2 main::$2 ] ( [ main::i#2 main::$2 ] { } ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp[1]:4 [ main::$2 ]
Statement [7] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) ← *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) + (byte) $a [ main::i#2 main::$2 ] ( [ main::i#2 main::$2 ] { } ) always clobbers reg byte a
Statement [8] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_SYM + (byte~) main::$2) ← (byte) '*' [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
Statement [4] (byte~) main::$4 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$4 ] ( [ main::i#2 main::$4 ] { } ) always clobbers reg byte a
Statement [5] (byte~) main::$2 ← (byte~) main::$4 + (byte) main::i#2 [ main::i#2 main::$2 ] ( [ main::i#2 main::$2 ] { } ) always clobbers reg byte a
Statement [6] *((byte*)(const struct Ball*) balls + (byte~) main::$2) ← *((byte*)(const struct Ball*) balls + (byte~) main::$2) + *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) [ main::i#2 main::$2 ] ( [ main::i#2 main::$2 ] { } ) always clobbers reg byte a
Statement [7] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) ← *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) + (byte) $a [ main::i#2 main::$2 ] ( [ main::i#2 main::$2 ] { } ) always clobbers reg byte a
Statement [8] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_SYM + (byte~) main::$2) ← (byte) '*' [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
Potential registers zp[1]:2 [ main::i#2 main::i#1 ] : zp[1]:2 , reg byte x , reg byte y ,
Potential registers zp[1]:3 [ main::$4 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:4 [ main::$2 ] : zp[1]:4 , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 29.86: zp[1]:2 [ main::i#2 main::i#1 ] 25.67: zp[1]:4 [ main::$2 ] 22: zp[1]:3 [ main::$4 ]
Uplift Scope [Ball]
Uplift Scope []
Uplifting [main] best 686 combination reg byte y [ main::i#2 main::i#1 ] reg byte x [ main::$2 ] reg byte a [ main::$4 ]
Uplifting [Ball] best 686 combination
Uplifting [] best 686 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test array index pointer rewriting
// struct array with 8bit index
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_BALL_VEL = 1
.const OFFSET_STRUCT_BALL_SYM = 2
// main
main: {
// [1] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [1] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuyy=vbuc1
ldy #0
jmp __b1
// main::@1
__b1:
// [2] if((byte) main::i#2<(byte) $19) goto main::@2 -- vbuyy_lt_vbuc1_then_la1
cpy #$19
bcc __b2
jmp __breturn
// main::@return
__breturn:
// [3] return
rts
// main::@2
__b2:
// [4] (byte~) main::$4 ← (byte) main::i#2 << (byte) 1 -- vbuaa=vbuyy_rol_1
tya
asl
// [5] (byte~) main::$2 ← (byte~) main::$4 + (byte) main::i#2 -- vbuxx=vbuaa_plus_vbuyy
sty.z $ff
clc
adc.z $ff
tax
// [6] *((byte*)(const struct Ball*) balls + (byte~) main::$2) ← *((byte*)(const struct Ball*) balls + (byte~) main::$2) + *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) -- pbuc1_derefidx_vbuxx=pbuc1_derefidx_vbuxx_plus_pbuc2_derefidx_vbuxx
lda balls,x
clc
adc balls+OFFSET_STRUCT_BALL_VEL,x
sta balls,x
// [7] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) ← *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) + (byte) $a -- pbuc1_derefidx_vbuxx=pbuc1_derefidx_vbuxx_plus_vbuc2
lda #$a
clc
adc balls+OFFSET_STRUCT_BALL_VEL,x
sta balls+OFFSET_STRUCT_BALL_VEL,x
// [8] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_SYM + (byte~) main::$2) ← (byte) '*' -- pbuc1_derefidx_vbuxx=vbuc2
lda #'*'
sta balls+OFFSET_STRUCT_BALL_SYM,x
// [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuyy=_inc_vbuyy
iny
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [1] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
balls: .fill 3*$19, 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __b1_from_main:
Removing instruction __breturn:
Removing instruction __b1_from___b2:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(byte) Ball::pos
(byte) Ball::sym
(byte) Ball::vel
(const byte) OFFSET_STRUCT_BALL_SYM = (byte) 2
(const byte) OFFSET_STRUCT_BALL_VEL = (byte) 1
(const struct Ball*) balls[(number) $19] = { fill( $19, 0) }
(void()) main()
(byte~) main::$2 reg byte x 25.666666666666668
(byte~) main::$4 reg byte a 22.0
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte y 22.0
(byte) main::i#2 reg byte y 7.857142857142857
reg byte y [ main::i#2 main::i#1 ]
reg byte a [ main::$4 ]
reg byte x [ main::$2 ]
FINAL ASSEMBLER
Score: 626
// File Comments
// Test array index pointer rewriting
// struct array with 8bit index
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_BALL_VEL = 1
.const OFFSET_STRUCT_BALL_SYM = 2
// main
main: {
// [1] phi from main to main::@1 [phi:main->main::@1]
// [1] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuyy=vbuc1
ldy #0
// main::@1
__b1:
// for(char i=0;i<NUM_BALLS;i++)
// [2] if((byte) main::i#2<(byte) $19) goto main::@2 -- vbuyy_lt_vbuc1_then_la1
cpy #$19
bcc __b2
// main::@return
// }
// [3] return
rts
// main::@2
__b2:
// balls[i].pos += balls[i].vel
// [4] (byte~) main::$4 ← (byte) main::i#2 << (byte) 1 -- vbuaa=vbuyy_rol_1
tya
asl
// [5] (byte~) main::$2 ← (byte~) main::$4 + (byte) main::i#2 -- vbuxx=vbuaa_plus_vbuyy
sty.z $ff
clc
adc.z $ff
tax
// [6] *((byte*)(const struct Ball*) balls + (byte~) main::$2) ← *((byte*)(const struct Ball*) balls + (byte~) main::$2) + *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) -- pbuc1_derefidx_vbuxx=pbuc1_derefidx_vbuxx_plus_pbuc2_derefidx_vbuxx
lda balls,x
clc
adc balls+OFFSET_STRUCT_BALL_VEL,x
sta balls,x
// balls[i].vel += 10
// [7] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) ← *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (byte~) main::$2) + (byte) $a -- pbuc1_derefidx_vbuxx=pbuc1_derefidx_vbuxx_plus_vbuc2
lda #$a
clc
adc balls+OFFSET_STRUCT_BALL_VEL,x
sta balls+OFFSET_STRUCT_BALL_VEL,x
// balls[i].sym ='*'
// [8] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_SYM + (byte~) main::$2) ← (byte) '*' -- pbuc1_derefidx_vbuxx=vbuc2
lda #'*'
sta balls+OFFSET_STRUCT_BALL_SYM,x
// for(char i=0;i<NUM_BALLS;i++)
// [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuyy=_inc_vbuyy
iny
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
// [1] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
balls: .fill 3*$19, 0

View File

@ -0,0 +1,19 @@
(byte) Ball::pos
(byte) Ball::sym
(byte) Ball::vel
(const byte) OFFSET_STRUCT_BALL_SYM = (byte) 2
(const byte) OFFSET_STRUCT_BALL_VEL = (byte) 1
(const struct Ball*) balls[(number) $19] = { fill( $19, 0) }
(void()) main()
(byte~) main::$2 reg byte x 25.666666666666668
(byte~) main::$4 reg byte a 22.0
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte y 22.0
(byte) main::i#2 reg byte y 7.857142857142857
reg byte y [ main::i#2 main::i#1 ]
reg byte a [ main::$4 ]
reg byte x [ main::$2 ]

View File

@ -0,0 +1,108 @@
// Test array index pointer rewriting
// struct array with 16bit index
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const OFFSET_STRUCT_BALL_VEL = 1
.const OFFSET_STRUCT_BALL_SYM = 2
main: {
.label __2 = 4
.label i = 2
.label __4 = 6
.label __5 = 8
.label __6 = $a
.label __7 = $c
.label __8 = $e
.label __9 = 4
.label __10 = 4
lda #<0
sta.z i
sta.z i+1
__b1:
// for(unsigned short i=0;i<NUM_BALLS;i++)
lda.z i+1
bne !+
lda.z i
cmp #$19
bcc __b2
!:
// }
rts
__b2:
// balls[i].pos += balls[i].vel
lda.z i
asl
sta.z __10
lda.z i+1
rol
sta.z __10+1
lda.z __2
clc
adc.z i
sta.z __2
lda.z __2+1
adc.z i+1
sta.z __2+1
lda.z __2
clc
adc #<balls
sta.z __4
lda.z __2+1
adc #>balls
sta.z __4+1
lda.z __2
clc
adc #<balls+OFFSET_STRUCT_BALL_VEL
sta.z __5
lda.z __2+1
adc #>balls+OFFSET_STRUCT_BALL_VEL
sta.z __5+1
lda.z __2
clc
adc #<balls
sta.z __6
lda.z __2+1
adc #>balls
sta.z __6+1
ldy #0
lda (__4),y
clc
adc (__5),y
sta (__6),y
// balls[i].vel += 10
lda.z __2
clc
adc #<balls+OFFSET_STRUCT_BALL_VEL
sta.z __7
lda.z __2+1
adc #>balls+OFFSET_STRUCT_BALL_VEL
sta.z __7+1
lda.z __2
clc
adc #<balls+OFFSET_STRUCT_BALL_VEL
sta.z __8
lda.z __2+1
adc #>balls+OFFSET_STRUCT_BALL_VEL
sta.z __8+1
lda #$a
clc
adc (__7),y
sta (__8),y
// balls[i].sym ='*'
clc
lda.z __9
adc #<balls+OFFSET_STRUCT_BALL_SYM
sta.z __9
lda.z __9+1
adc #>balls+OFFSET_STRUCT_BALL_SYM
sta.z __9+1
lda #'*'
sta (__9),y
// for(unsigned short i=0;i<NUM_BALLS;i++)
inc.z i
bne !+
inc.z i+1
!:
jmp __b1
}
balls: .fill 3*$19, 0

View File

@ -0,0 +1,26 @@
(void()) main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[1] (word) main::i#2 ← phi( main/(word) 0 main::@2/(word) main::i#1 )
[2] if((word) main::i#2<(byte) $19) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[3] return
to:@return
main::@2: scope:[main] from main::@1
[4] (word~) main::$10 ← (word) main::i#2 << (byte) 1
[5] (word~) main::$2 ← (word~) main::$10 + (word) main::i#2
[6] (byte*~) main::$4 ← (byte*)(const struct Ball*) balls + (word~) main::$2
[7] (byte*~) main::$5 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2
[8] (byte*~) main::$6 ← (byte*)(const struct Ball*) balls + (word~) main::$2
[9] *((byte*~) main::$6) ← *((byte*~) main::$4) + *((byte*~) main::$5)
[10] (byte*~) main::$7 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2
[11] (byte*~) main::$8 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2
[12] *((byte*~) main::$8) ← *((byte*~) main::$7) + (byte) $a
[13] (byte*~) main::$9 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_SYM + (word~) main::$2
[14] *((byte*~) main::$9) ← (byte) '*'
[15] (word) main::i#1 ← ++ (word) main::i#2
to:main::@1

View File

@ -0,0 +1,699 @@
CONTROL FLOW GRAPH SSA
(void()) main()
main: scope:[main] from __start
(word) main::i#0 ← (word) 0
to:main::@1
main::@1: scope:[main] from main main::@2
(word) main::i#2 ← phi( main/(word) main::i#0 main::@2/(word) main::i#1 )
(bool~) main::$0 ← (word) main::i#2 < (number) $19
if((bool~) main::$0) goto main::@2
to:main::@return
main::@2: scope:[main] from main::@1
(word) main::i#3 ← phi( main::@1/(word) main::i#2 )
(word~) main::$1 ← (word) main::i#3 * (const byte) SIZEOF_STRUCT_BALL
*((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_POS + (word~) main::$1) ← *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_POS + (word~) main::$1) + *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$1)
(word~) main::$2 ← (word) main::i#3 * (const byte) SIZEOF_STRUCT_BALL
*((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2) ← *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2) + (number) $a
(word~) main::$3 ← (word) main::i#3 * (const byte) SIZEOF_STRUCT_BALL
*((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_SYM + (word~) main::$3) ← (byte) '*'
(word) main::i#1 ← ++ (word) main::i#3
to:main::@1
main::@return: scope:[main] from main::@1
return
to:@return
(void()) __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
(byte) Ball::pos
(byte) Ball::sym
(byte) Ball::vel
(const byte) OFFSET_STRUCT_BALL_POS = (byte) 0
(const byte) OFFSET_STRUCT_BALL_SYM = (byte) 2
(const byte) OFFSET_STRUCT_BALL_VEL = (byte) 1
(const byte) SIZEOF_STRUCT_BALL = (byte) 3
(void()) __start()
(label) __start::@1
(label) __start::@return
(const struct Ball*) balls[(number) $19] = { fill( $19, 0) }
(void()) main()
(bool~) main::$0
(word~) main::$1
(word~) main::$2
(word~) main::$3
(label) main::@1
(label) main::@2
(label) main::@return
(word) main::i
(word) main::i#0
(word) main::i#1
(word) main::i#2
(word) main::i#3
Adding number conversion cast (unumber) $19 in (bool~) main::$0 ← (word) main::i#2 < (number) $19
Adding number conversion cast (unumber) $a in *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2) ← *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2) + (number) $a
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant integer cast $19
Simplifying constant integer cast $a
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) $19
Finalized unsigned number type (byte) $a
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias main::i#2 = main::i#3
Successful SSA optimization Pass2AliasElimination
Identified duplicate assignment right side [7] (word~) main::$2 ← (word) main::i#2 * (const byte) SIZEOF_STRUCT_BALL
Identified duplicate assignment right side [9] (word~) main::$3 ← (word) main::i#2 * (const byte) SIZEOF_STRUCT_BALL
Successful SSA optimization Pass2DuplicateRValueIdentification
Simple Condition (bool~) main::$0 [3] if((word) main::i#2<(byte) $19) goto main::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const word) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
De-inlining pointer[w] to *(pointer+w) [5] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_POS + (word~) main::$1) ← *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_POS + (word~) main::$1) + *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$1)
De-inlining pointer[w] to *(pointer+w) [5] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_POS + (word~) main::$1) ← *((byte*~) main::$4) + *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$1)
De-inlining pointer[w] to *(pointer+w) [5] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_POS + (word~) main::$1) ← *((byte*~) main::$4) + *((byte*~) main::$5)
De-inlining pointer[w] to *(pointer+w) [7] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2) ← *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2) + (byte) $a
De-inlining pointer[w] to *(pointer+w) [7] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2) ← *((byte*~) main::$7) + (byte) $a
De-inlining pointer[w] to *(pointer+w) [9] *((byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_SYM + (word~) main::$3) ← (byte) '*'
Successful SSA optimization Pass2DeInlineWordDerefIdx
Simplifying expression containing zero (byte*)balls in (byte*~) main::$4 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_POS + (word~) main::$1
Simplifying expression containing zero (byte*)balls in (byte*~) main::$6 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_POS + (word~) main::$1
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused constant (const byte) OFFSET_STRUCT_BALL_POS
Successful SSA optimization PassNEliminateUnusedVars
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Alias main::$2 = main::$1 main::$3
Successful SSA optimization Pass2AliasElimination
Rewriting multiplication to use shift and addition[2] (word~) main::$2 ← (word) main::i#2 * (const byte) SIZEOF_STRUCT_BALL
Inlining constant with var siblings (const word) main::i#0
Constant inlined main::i#0 = (word) 0
Successful SSA optimization Pass2ConstantInlining
Alias main::$2 = main::$11
Successful SSA optimization Pass2AliasElimination
Eliminating unused constant (const byte) SIZEOF_STRUCT_BALL
Successful SSA optimization PassNEliminateUnusedVars
Adding NOP phi() at start of main
CALL GRAPH
Created 1 initial phi equivalence classes
Coalesced [16] main::i#4 ← main::i#1
Coalesced down to 1 phi equivalence classes
Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH
(void()) main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[1] (word) main::i#2 ← phi( main/(word) 0 main::@2/(word) main::i#1 )
[2] if((word) main::i#2<(byte) $19) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[3] return
to:@return
main::@2: scope:[main] from main::@1
[4] (word~) main::$10 ← (word) main::i#2 << (byte) 1
[5] (word~) main::$2 ← (word~) main::$10 + (word) main::i#2
[6] (byte*~) main::$4 ← (byte*)(const struct Ball*) balls + (word~) main::$2
[7] (byte*~) main::$5 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2
[8] (byte*~) main::$6 ← (byte*)(const struct Ball*) balls + (word~) main::$2
[9] *((byte*~) main::$6) ← *((byte*~) main::$4) + *((byte*~) main::$5)
[10] (byte*~) main::$7 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2
[11] (byte*~) main::$8 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2
[12] *((byte*~) main::$8) ← *((byte*~) main::$7) + (byte) $a
[13] (byte*~) main::$9 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_SYM + (word~) main::$2
[14] *((byte*~) main::$9) ← (byte) '*'
[15] (word) main::i#1 ← ++ (word) main::i#2
to:main::@1
VARIABLE REGISTER WEIGHTS
(byte) Ball::pos
(byte) Ball::sym
(byte) Ball::vel
(void()) main()
(word~) main::$10 22.0
(word~) main::$2 9.625
(byte*~) main::$4 7.333333333333333
(byte*~) main::$5 11.0
(byte*~) main::$6 22.0
(byte*~) main::$7 11.0
(byte*~) main::$8 22.0
(byte*~) main::$9 22.0
(word) main::i
(word) main::i#1 22.0
(word) main::i#2 4.230769230769231
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
Added variable main::$10 to live range equivalence class [ main::$10 ]
Added variable main::$2 to live range equivalence class [ main::$2 ]
Added variable main::$4 to live range equivalence class [ main::$4 ]
Added variable main::$5 to live range equivalence class [ main::$5 ]
Added variable main::$6 to live range equivalence class [ main::$6 ]
Added variable main::$7 to live range equivalence class [ main::$7 ]
Added variable main::$8 to live range equivalence class [ main::$8 ]
Added variable main::$9 to live range equivalence class [ main::$9 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ main::$10 ]
[ main::$2 ]
[ main::$4 ]
[ main::$5 ]
[ main::$6 ]
[ main::$7 ]
[ main::$8 ]
[ main::$9 ]
Allocated zp[2]:2 [ main::i#2 main::i#1 ]
Allocated zp[2]:4 [ main::$10 ]
Allocated zp[2]:6 [ main::$2 ]
Allocated zp[2]:8 [ main::$4 ]
Allocated zp[2]:10 [ main::$5 ]
Allocated zp[2]:12 [ main::$6 ]
Allocated zp[2]:14 [ main::$7 ]
Allocated zp[2]:16 [ main::$8 ]
Allocated zp[2]:18 [ main::$9 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Test array index pointer rewriting
// struct array with 16bit index
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_BALL_VEL = 1
.const OFFSET_STRUCT_BALL_SYM = 2
// main
main: {
.label __2 = 6
.label i = 2
.label __4 = 8
.label __5 = $a
.label __6 = $c
.label __7 = $e
.label __8 = $10
.label __9 = $12
.label __10 = 4
// [1] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [1] phi (word) main::i#2 = (word) 0 [phi:main->main::@1#0] -- vwuz1=vwuc1
lda #<0
sta.z i
lda #>0
sta.z i+1
jmp __b1
// main::@1
__b1:
// [2] if((word) main::i#2<(byte) $19) goto main::@2 -- vwuz1_lt_vbuc1_then_la1
lda.z i+1
bne !+
lda.z i
cmp #$19
bcc __b2
!:
jmp __breturn
// main::@return
__breturn:
// [3] return
rts
// main::@2
__b2:
// [4] (word~) main::$10 ← (word) main::i#2 << (byte) 1 -- vwuz1=vwuz2_rol_1
lda.z i
asl
sta.z __10
lda.z i+1
rol
sta.z __10+1
// [5] (word~) main::$2 ← (word~) main::$10 + (word) main::i#2 -- vwuz1=vwuz2_plus_vwuz3
lda.z __10
clc
adc.z i
sta.z __2
lda.z __10+1
adc.z i+1
sta.z __2+1
// [6] (byte*~) main::$4 ← (byte*)(const struct Ball*) balls + (word~) main::$2 -- pbuz1=pbuc1_plus_vwuz2
lda.z __2
clc
adc #<balls
sta.z __4
lda.z __2+1
adc #>balls
sta.z __4+1
// [7] (byte*~) main::$5 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2 -- pbuz1=pbuc1_plus_vwuz2
lda.z __2
clc
adc #<balls+OFFSET_STRUCT_BALL_VEL
sta.z __5
lda.z __2+1
adc #>balls+OFFSET_STRUCT_BALL_VEL
sta.z __5+1
// [8] (byte*~) main::$6 ← (byte*)(const struct Ball*) balls + (word~) main::$2 -- pbuz1=pbuc1_plus_vwuz2
lda.z __2
clc
adc #<balls
sta.z __6
lda.z __2+1
adc #>balls
sta.z __6+1
// [9] *((byte*~) main::$6) ← *((byte*~) main::$4) + *((byte*~) main::$5) -- _deref_pbuz1=_deref_pbuz2_plus__deref_pbuz3
ldy #0
lda (__4),y
clc
ldy #0
adc (__5),y
ldy #0
sta (__6),y
// [10] (byte*~) main::$7 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2 -- pbuz1=pbuc1_plus_vwuz2
lda.z __2
clc
adc #<balls+OFFSET_STRUCT_BALL_VEL
sta.z __7
lda.z __2+1
adc #>balls+OFFSET_STRUCT_BALL_VEL
sta.z __7+1
// [11] (byte*~) main::$8 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2 -- pbuz1=pbuc1_plus_vwuz2
lda.z __2
clc
adc #<balls+OFFSET_STRUCT_BALL_VEL
sta.z __8
lda.z __2+1
adc #>balls+OFFSET_STRUCT_BALL_VEL
sta.z __8+1
// [12] *((byte*~) main::$8) ← *((byte*~) main::$7) + (byte) $a -- _deref_pbuz1=_deref_pbuz2_plus_vbuc1
lda #$a
clc
ldy #0
adc (__7),y
ldy #0
sta (__8),y
// [13] (byte*~) main::$9 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_SYM + (word~) main::$2 -- pbuz1=pbuc1_plus_vwuz2
lda.z __2
clc
adc #<balls+OFFSET_STRUCT_BALL_SYM
sta.z __9
lda.z __2+1
adc #>balls+OFFSET_STRUCT_BALL_SYM
sta.z __9+1
// [14] *((byte*~) main::$9) ← (byte) '*' -- _deref_pbuz1=vbuc1
lda #'*'
ldy #0
sta (__9),y
// [15] (word) main::i#1 ← ++ (word) main::i#2 -- vwuz1=_inc_vwuz1
inc.z i
bne !+
inc.z i+1
!:
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [1] phi (word) main::i#2 = (word) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
balls: .fill 3*$19, 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [2] if((word) main::i#2<(byte) $19) goto main::@2 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
Statement [4] (word~) main::$10 ← (word) main::i#2 << (byte) 1 [ main::i#2 main::$10 ] ( [ main::i#2 main::$10 ] { } ) always clobbers reg byte a
Statement [5] (word~) main::$2 ← (word~) main::$10 + (word) main::i#2 [ main::i#2 main::$2 ] ( [ main::i#2 main::$2 ] { } ) always clobbers reg byte a
Statement [6] (byte*~) main::$4 ← (byte*)(const struct Ball*) balls + (word~) main::$2 [ main::i#2 main::$2 main::$4 ] ( [ main::i#2 main::$2 main::$4 ] { } ) always clobbers reg byte a
Statement [7] (byte*~) main::$5 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2 [ main::i#2 main::$2 main::$4 main::$5 ] ( [ main::i#2 main::$2 main::$4 main::$5 ] { } ) always clobbers reg byte a
Statement [8] (byte*~) main::$6 ← (byte*)(const struct Ball*) balls + (word~) main::$2 [ main::i#2 main::$2 main::$4 main::$5 main::$6 ] ( [ main::i#2 main::$2 main::$4 main::$5 main::$6 ] { } ) always clobbers reg byte a
Statement [9] *((byte*~) main::$6) ← *((byte*~) main::$4) + *((byte*~) main::$5) [ main::i#2 main::$2 ] ( [ main::i#2 main::$2 ] { } ) always clobbers reg byte a reg byte y
Statement [10] (byte*~) main::$7 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2 [ main::i#2 main::$2 main::$7 ] ( [ main::i#2 main::$2 main::$7 ] { } ) always clobbers reg byte a
Statement [11] (byte*~) main::$8 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2 [ main::i#2 main::$2 main::$7 main::$8 ] ( [ main::i#2 main::$2 main::$7 main::$8 ] { } ) always clobbers reg byte a
Statement [12] *((byte*~) main::$8) ← *((byte*~) main::$7) + (byte) $a [ main::i#2 main::$2 ] ( [ main::i#2 main::$2 ] { } ) always clobbers reg byte a reg byte y
Statement [13] (byte*~) main::$9 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_SYM + (word~) main::$2 [ main::i#2 main::$9 ] ( [ main::i#2 main::$9 ] { } ) always clobbers reg byte a
Statement [14] *((byte*~) main::$9) ← (byte) '*' [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a reg byte y
Potential registers zp[2]:2 [ main::i#2 main::i#1 ] : zp[2]:2 ,
Potential registers zp[2]:4 [ main::$10 ] : zp[2]:4 ,
Potential registers zp[2]:6 [ main::$2 ] : zp[2]:6 ,
Potential registers zp[2]:8 [ main::$4 ] : zp[2]:8 ,
Potential registers zp[2]:10 [ main::$5 ] : zp[2]:10 ,
Potential registers zp[2]:12 [ main::$6 ] : zp[2]:12 ,
Potential registers zp[2]:14 [ main::$7 ] : zp[2]:14 ,
Potential registers zp[2]:16 [ main::$8 ] : zp[2]:16 ,
Potential registers zp[2]:18 [ main::$9 ] : zp[2]:18 ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 26.23: zp[2]:2 [ main::i#2 main::i#1 ] 22: zp[2]:4 [ main::$10 ] 22: zp[2]:12 [ main::$6 ] 22: zp[2]:16 [ main::$8 ] 22: zp[2]:18 [ main::$9 ] 11: zp[2]:10 [ main::$5 ] 11: zp[2]:14 [ main::$7 ] 9.62: zp[2]:6 [ main::$2 ] 7.33: zp[2]:8 [ main::$4 ]
Uplift Scope [Ball]
Uplift Scope []
Uplifting [main] best 2436 combination zp[2]:2 [ main::i#2 main::i#1 ] zp[2]:4 [ main::$10 ] zp[2]:12 [ main::$6 ] zp[2]:16 [ main::$8 ] zp[2]:18 [ main::$9 ] zp[2]:10 [ main::$5 ] zp[2]:14 [ main::$7 ] zp[2]:6 [ main::$2 ] zp[2]:8 [ main::$4 ]
Uplifting [Ball] best 2436 combination
Uplifting [] best 2436 combination
Coalescing zero page register [ zp[2]:4 [ main::$10 ] ] with [ zp[2]:6 [ main::$2 ] ] - score: 1
Coalescing zero page register [ zp[2]:4 [ main::$10 main::$2 ] ] with [ zp[2]:18 [ main::$9 ] ] - score: 1
Allocated (was zp[2]:8) zp[2]:6 [ main::$4 ]
Allocated (was zp[2]:10) zp[2]:8 [ main::$5 ]
Allocated (was zp[2]:12) zp[2]:10 [ main::$6 ]
Allocated (was zp[2]:14) zp[2]:12 [ main::$7 ]
Allocated (was zp[2]:16) zp[2]:14 [ main::$8 ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test array index pointer rewriting
// struct array with 16bit index
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_BALL_VEL = 1
.const OFFSET_STRUCT_BALL_SYM = 2
// main
main: {
.label __2 = 4
.label i = 2
.label __4 = 6
.label __5 = 8
.label __6 = $a
.label __7 = $c
.label __8 = $e
.label __9 = 4
.label __10 = 4
// [1] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [1] phi (word) main::i#2 = (word) 0 [phi:main->main::@1#0] -- vwuz1=vwuc1
lda #<0
sta.z i
lda #>0
sta.z i+1
jmp __b1
// main::@1
__b1:
// [2] if((word) main::i#2<(byte) $19) goto main::@2 -- vwuz1_lt_vbuc1_then_la1
lda.z i+1
bne !+
lda.z i
cmp #$19
bcc __b2
!:
jmp __breturn
// main::@return
__breturn:
// [3] return
rts
// main::@2
__b2:
// [4] (word~) main::$10 ← (word) main::i#2 << (byte) 1 -- vwuz1=vwuz2_rol_1
lda.z i
asl
sta.z __10
lda.z i+1
rol
sta.z __10+1
// [5] (word~) main::$2 ← (word~) main::$10 + (word) main::i#2 -- vwuz1=vwuz1_plus_vwuz2
lda.z __2
clc
adc.z i
sta.z __2
lda.z __2+1
adc.z i+1
sta.z __2+1
// [6] (byte*~) main::$4 ← (byte*)(const struct Ball*) balls + (word~) main::$2 -- pbuz1=pbuc1_plus_vwuz2
lda.z __2
clc
adc #<balls
sta.z __4
lda.z __2+1
adc #>balls
sta.z __4+1
// [7] (byte*~) main::$5 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2 -- pbuz1=pbuc1_plus_vwuz2
lda.z __2
clc
adc #<balls+OFFSET_STRUCT_BALL_VEL
sta.z __5
lda.z __2+1
adc #>balls+OFFSET_STRUCT_BALL_VEL
sta.z __5+1
// [8] (byte*~) main::$6 ← (byte*)(const struct Ball*) balls + (word~) main::$2 -- pbuz1=pbuc1_plus_vwuz2
lda.z __2
clc
adc #<balls
sta.z __6
lda.z __2+1
adc #>balls
sta.z __6+1
// [9] *((byte*~) main::$6) ← *((byte*~) main::$4) + *((byte*~) main::$5) -- _deref_pbuz1=_deref_pbuz2_plus__deref_pbuz3
ldy #0
lda (__4),y
clc
ldy #0
adc (__5),y
ldy #0
sta (__6),y
// [10] (byte*~) main::$7 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2 -- pbuz1=pbuc1_plus_vwuz2
lda.z __2
clc
adc #<balls+OFFSET_STRUCT_BALL_VEL
sta.z __7
lda.z __2+1
adc #>balls+OFFSET_STRUCT_BALL_VEL
sta.z __7+1
// [11] (byte*~) main::$8 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2 -- pbuz1=pbuc1_plus_vwuz2
lda.z __2
clc
adc #<balls+OFFSET_STRUCT_BALL_VEL
sta.z __8
lda.z __2+1
adc #>balls+OFFSET_STRUCT_BALL_VEL
sta.z __8+1
// [12] *((byte*~) main::$8) ← *((byte*~) main::$7) + (byte) $a -- _deref_pbuz1=_deref_pbuz2_plus_vbuc1
lda #$a
clc
ldy #0
adc (__7),y
ldy #0
sta (__8),y
// [13] (byte*~) main::$9 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_SYM + (word~) main::$2 -- pbuz1=pbuc1_plus_vwuz1
clc
lda.z __9
adc #<balls+OFFSET_STRUCT_BALL_SYM
sta.z __9
lda.z __9+1
adc #>balls+OFFSET_STRUCT_BALL_SYM
sta.z __9+1
// [14] *((byte*~) main::$9) ← (byte) '*' -- _deref_pbuz1=vbuc1
lda #'*'
ldy #0
sta (__9),y
// [15] (word) main::i#1 ← ++ (word) main::i#2 -- vwuz1=_inc_vwuz1
inc.z i
bne !+
inc.z i+1
!:
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [1] phi (word) main::i#2 = (word) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
balls: .fill 3*$19, 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction lda #>0
Removing instruction ldy #0
Removing instruction ldy #0
Removing instruction ldy #0
Removing instruction ldy #0
Removing instruction ldy #0
Succesful ASM optimization Pass5UnnecesaryLoadElimination
Removing instruction __b1_from_main:
Removing instruction __breturn:
Removing instruction __b1_from___b2:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(byte) Ball::pos
(byte) Ball::sym
(byte) Ball::vel
(const byte) OFFSET_STRUCT_BALL_SYM = (byte) 2
(const byte) OFFSET_STRUCT_BALL_VEL = (byte) 1
(const struct Ball*) balls[(number) $19] = { fill( $19, 0) }
(void()) main()
(word~) main::$10 zp[2]:4 22.0
(word~) main::$2 zp[2]:4 9.625
(byte*~) main::$4 zp[2]:6 7.333333333333333
(byte*~) main::$5 zp[2]:8 11.0
(byte*~) main::$6 zp[2]:10 22.0
(byte*~) main::$7 zp[2]:12 11.0
(byte*~) main::$8 zp[2]:14 22.0
(byte*~) main::$9 zp[2]:4 22.0
(label) main::@1
(label) main::@2
(label) main::@return
(word) main::i
(word) main::i#1 i zp[2]:2 22.0
(word) main::i#2 i zp[2]:2 4.230769230769231
zp[2]:2 [ main::i#2 main::i#1 ]
zp[2]:4 [ main::$10 main::$2 main::$9 ]
zp[2]:6 [ main::$4 ]
zp[2]:8 [ main::$5 ]
zp[2]:10 [ main::$6 ]
zp[2]:12 [ main::$7 ]
zp[2]:14 [ main::$8 ]
FINAL ASSEMBLER
Score: 2256
// File Comments
// Test array index pointer rewriting
// struct array with 16bit index
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_BALL_VEL = 1
.const OFFSET_STRUCT_BALL_SYM = 2
// main
main: {
.label __2 = 4
.label i = 2
.label __4 = 6
.label __5 = 8
.label __6 = $a
.label __7 = $c
.label __8 = $e
.label __9 = 4
.label __10 = 4
// [1] phi from main to main::@1 [phi:main->main::@1]
// [1] phi (word) main::i#2 = (word) 0 [phi:main->main::@1#0] -- vwuz1=vwuc1
lda #<0
sta.z i
sta.z i+1
// main::@1
__b1:
// for(unsigned short i=0;i<NUM_BALLS;i++)
// [2] if((word) main::i#2<(byte) $19) goto main::@2 -- vwuz1_lt_vbuc1_then_la1
lda.z i+1
bne !+
lda.z i
cmp #$19
bcc __b2
!:
// main::@return
// }
// [3] return
rts
// main::@2
__b2:
// balls[i].pos += balls[i].vel
// [4] (word~) main::$10 ← (word) main::i#2 << (byte) 1 -- vwuz1=vwuz2_rol_1
lda.z i
asl
sta.z __10
lda.z i+1
rol
sta.z __10+1
// [5] (word~) main::$2 ← (word~) main::$10 + (word) main::i#2 -- vwuz1=vwuz1_plus_vwuz2
lda.z __2
clc
adc.z i
sta.z __2
lda.z __2+1
adc.z i+1
sta.z __2+1
// [6] (byte*~) main::$4 ← (byte*)(const struct Ball*) balls + (word~) main::$2 -- pbuz1=pbuc1_plus_vwuz2
lda.z __2
clc
adc #<balls
sta.z __4
lda.z __2+1
adc #>balls
sta.z __4+1
// [7] (byte*~) main::$5 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2 -- pbuz1=pbuc1_plus_vwuz2
lda.z __2
clc
adc #<balls+OFFSET_STRUCT_BALL_VEL
sta.z __5
lda.z __2+1
adc #>balls+OFFSET_STRUCT_BALL_VEL
sta.z __5+1
// [8] (byte*~) main::$6 ← (byte*)(const struct Ball*) balls + (word~) main::$2 -- pbuz1=pbuc1_plus_vwuz2
lda.z __2
clc
adc #<balls
sta.z __6
lda.z __2+1
adc #>balls
sta.z __6+1
// [9] *((byte*~) main::$6) ← *((byte*~) main::$4) + *((byte*~) main::$5) -- _deref_pbuz1=_deref_pbuz2_plus__deref_pbuz3
ldy #0
lda (__4),y
clc
adc (__5),y
sta (__6),y
// balls[i].vel += 10
// [10] (byte*~) main::$7 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2 -- pbuz1=pbuc1_plus_vwuz2
lda.z __2
clc
adc #<balls+OFFSET_STRUCT_BALL_VEL
sta.z __7
lda.z __2+1
adc #>balls+OFFSET_STRUCT_BALL_VEL
sta.z __7+1
// [11] (byte*~) main::$8 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_VEL + (word~) main::$2 -- pbuz1=pbuc1_plus_vwuz2
lda.z __2
clc
adc #<balls+OFFSET_STRUCT_BALL_VEL
sta.z __8
lda.z __2+1
adc #>balls+OFFSET_STRUCT_BALL_VEL
sta.z __8+1
// [12] *((byte*~) main::$8) ← *((byte*~) main::$7) + (byte) $a -- _deref_pbuz1=_deref_pbuz2_plus_vbuc1
lda #$a
clc
adc (__7),y
sta (__8),y
// balls[i].sym ='*'
// [13] (byte*~) main::$9 ← (byte*)(const struct Ball*) balls+(const byte) OFFSET_STRUCT_BALL_SYM + (word~) main::$2 -- pbuz1=pbuc1_plus_vwuz1
clc
lda.z __9
adc #<balls+OFFSET_STRUCT_BALL_SYM
sta.z __9
lda.z __9+1
adc #>balls+OFFSET_STRUCT_BALL_SYM
sta.z __9+1
// [14] *((byte*~) main::$9) ← (byte) '*' -- _deref_pbuz1=vbuc1
lda #'*'
sta (__9),y
// for(unsigned short i=0;i<NUM_BALLS;i++)
// [15] (word) main::i#1 ← ++ (word) main::i#2 -- vwuz1=_inc_vwuz1
inc.z i
bne !+
inc.z i+1
!:
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
// [1] phi (word) main::i#2 = (word) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
balls: .fill 3*$19, 0

View File

@ -0,0 +1,29 @@
(byte) Ball::pos
(byte) Ball::sym
(byte) Ball::vel
(const byte) OFFSET_STRUCT_BALL_SYM = (byte) 2
(const byte) OFFSET_STRUCT_BALL_VEL = (byte) 1
(const struct Ball*) balls[(number) $19] = { fill( $19, 0) }
(void()) main()
(word~) main::$10 zp[2]:4 22.0
(word~) main::$2 zp[2]:4 9.625
(byte*~) main::$4 zp[2]:6 7.333333333333333
(byte*~) main::$5 zp[2]:8 11.0
(byte*~) main::$6 zp[2]:10 22.0
(byte*~) main::$7 zp[2]:12 11.0
(byte*~) main::$8 zp[2]:14 22.0
(byte*~) main::$9 zp[2]:4 22.0
(label) main::@1
(label) main::@2
(label) main::@return
(word) main::i
(word) main::i#1 i zp[2]:2 22.0
(word) main::i#2 i zp[2]:2 4.230769230769231
zp[2]:2 [ main::i#2 main::i#1 ]
zp[2]:4 [ main::$10 main::$2 main::$9 ]
zp[2]:6 [ main::$4 ]
zp[2]:8 [ main::$5 ]
zp[2]:10 [ main::$6 ]
zp[2]:12 [ main::$7 ]
zp[2]:14 [ main::$8 ]