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:
parent
5c2d1c48d9
commit
1df52a8c5b
@ -1,4 +1,4 @@
|
||||
//KICKC FRAGMENT CACHE 12011d8c00 12011da5a7
|
||||
//KICKC FRAGMENT CACHE 11cb56b840 11cb56d1f2
|
||||
//FRAGMENT vbuz1=vbuc1
|
||||
lda #{c1}
|
||||
sta {z1}
|
||||
|
@ -1,4 +1,4 @@
|
||||
//KICKC FRAGMENT CACHE 12011d8c00 12011da5a7
|
||||
//KICKC FRAGMENT CACHE 11cb56b840 11cb56d1f2
|
||||
//FRAGMENT _deref_pbuc1=vbuc2
|
||||
lda #{c2}
|
||||
sta {c1}
|
||||
|
@ -1,4 +1,4 @@
|
||||
//KICKC FRAGMENT CACHE 12011d8c00 12011da5a7
|
||||
//KICKC FRAGMENT CACHE 11cb56b840 11cb56d1f2
|
||||
//FRAGMENT vbuz1=vbuc1
|
||||
lda #{c1}
|
||||
sta {z1}
|
||||
|
2474
src/main/fragment/cache/fragment-cache-mos6502x.asm
vendored
2474
src/main/fragment/cache/fragment-cache-mos6502x.asm
vendored
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
//KICKC FRAGMENT CACHE 12011d8c00 12011da5a7
|
||||
//KICKC FRAGMENT CACHE 11cb56b840 11cb56d1f2
|
||||
//FRAGMENT vbuz1=_deref_pbuc1
|
||||
lda {c1}
|
||||
sta {z1}
|
||||
|
@ -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
|
@ -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");
|
||||
|
12
src/test/kc/index-pointer-rewrite-0.c
Normal file
12
src/test/kc/index-pointer-rewrite-0.c
Normal 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;
|
||||
|
||||
}
|
12
src/test/kc/index-pointer-rewrite-1.c
Normal file
12
src/test/kc/index-pointer-rewrite-1.c
Normal 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;
|
||||
|
||||
}
|
12
src/test/kc/index-pointer-rewrite-2.c
Normal file
12
src/test/kc/index-pointer-rewrite-2.c
Normal 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;
|
||||
|
||||
}
|
12
src/test/kc/index-pointer-rewrite-3.c
Normal file
12
src/test/kc/index-pointer-rewrite-3.c
Normal 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;
|
||||
|
||||
}
|
14
src/test/kc/index-pointer-rewrite-4.c
Normal file
14
src/test/kc/index-pointer-rewrite-4.c
Normal 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];
|
||||
}
|
14
src/test/kc/index-pointer-rewrite-5.c
Normal file
14
src/test/kc/index-pointer-rewrite-5.c
Normal 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];
|
||||
}
|
14
src/test/kc/index-pointer-rewrite-6.c
Normal file
14
src/test/kc/index-pointer-rewrite-6.c
Normal 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];
|
||||
}
|
14
src/test/kc/index-pointer-rewrite-7.c
Normal file
14
src/test/kc/index-pointer-rewrite-7.c
Normal 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];
|
||||
}
|
20
src/test/kc/index-pointer-rewrite-8.c
Normal file
20
src/test/kc/index-pointer-rewrite-8.c
Normal 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 ='*';
|
||||
}
|
||||
}
|
20
src/test/kc/index-pointer-rewrite-9.c
Normal file
20
src/test/kc/index-pointer-rewrite-9.c
Normal 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 ='*';
|
||||
}
|
||||
}
|
22
src/test/ref/index-pointer-rewrite-0.asm
Normal file
22
src/test/ref/index-pointer-rewrite-0.asm
Normal 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
|
16
src/test/ref/index-pointer-rewrite-0.cfg
Normal file
16
src/test/ref/index-pointer-rewrite-0.cfg
Normal 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
|
275
src/test/ref/index-pointer-rewrite-0.log
Normal file
275
src/test/ref/index-pointer-rewrite-0.log
Normal 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
|
||||
|
10
src/test/ref/index-pointer-rewrite-0.sym
Normal file
10
src/test/ref/index-pointer-rewrite-0.sym
Normal 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 ]
|
27
src/test/ref/index-pointer-rewrite-1.asm
Normal file
27
src/test/ref/index-pointer-rewrite-1.asm
Normal 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
|
17
src/test/ref/index-pointer-rewrite-1.cfg
Normal file
17
src/test/ref/index-pointer-rewrite-1.cfg
Normal 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
|
311
src/test/ref/index-pointer-rewrite-1.log
Normal file
311
src/test/ref/index-pointer-rewrite-1.log
Normal 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
|
||||
|
12
src/test/ref/index-pointer-rewrite-1.sym
Normal file
12
src/test/ref/index-pointer-rewrite-1.sym
Normal 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 ]
|
41
src/test/ref/index-pointer-rewrite-2.asm
Normal file
41
src/test/ref/index-pointer-rewrite-2.asm
Normal 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
|
17
src/test/ref/index-pointer-rewrite-2.cfg
Normal file
17
src/test/ref/index-pointer-rewrite-2.cfg
Normal 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
|
345
src/test/ref/index-pointer-rewrite-2.log
Normal file
345
src/test/ref/index-pointer-rewrite-2.log
Normal 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
|
||||
|
12
src/test/ref/index-pointer-rewrite-2.sym
Normal file
12
src/test/ref/index-pointer-rewrite-2.sym
Normal 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 ]
|
51
src/test/ref/index-pointer-rewrite-3.asm
Normal file
51
src/test/ref/index-pointer-rewrite-3.asm
Normal 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
|
18
src/test/ref/index-pointer-rewrite-3.cfg
Normal file
18
src/test/ref/index-pointer-rewrite-3.cfg
Normal 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
|
394
src/test/ref/index-pointer-rewrite-3.log
Normal file
394
src/test/ref/index-pointer-rewrite-3.log
Normal 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
|
||||
|
13
src/test/ref/index-pointer-rewrite-3.sym
Normal file
13
src/test/ref/index-pointer-rewrite-3.sym
Normal 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 ]
|
32
src/test/ref/index-pointer-rewrite-4.asm
Normal file
32
src/test/ref/index-pointer-rewrite-4.asm
Normal 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
|
18
src/test/ref/index-pointer-rewrite-4.cfg
Normal file
18
src/test/ref/index-pointer-rewrite-4.cfg
Normal 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
|
357
src/test/ref/index-pointer-rewrite-4.log
Normal file
357
src/test/ref/index-pointer-rewrite-4.log
Normal 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
|
||||
|
12
src/test/ref/index-pointer-rewrite-4.sym
Normal file
12
src/test/ref/index-pointer-rewrite-4.sym
Normal 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 ]
|
64
src/test/ref/index-pointer-rewrite-5.asm
Normal file
64
src/test/ref/index-pointer-rewrite-5.asm
Normal 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
|
23
src/test/ref/index-pointer-rewrite-5.cfg
Normal file
23
src/test/ref/index-pointer-rewrite-5.cfg
Normal 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
|
560
src/test/ref/index-pointer-rewrite-5.log
Normal file
560
src/test/ref/index-pointer-rewrite-5.log
Normal 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
|
||||
|
23
src/test/ref/index-pointer-rewrite-5.sym
Normal file
23
src/test/ref/index-pointer-rewrite-5.sym
Normal 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 ]
|
69
src/test/ref/index-pointer-rewrite-6.asm
Normal file
69
src/test/ref/index-pointer-rewrite-6.asm
Normal 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
|
21
src/test/ref/index-pointer-rewrite-6.cfg
Normal file
21
src/test/ref/index-pointer-rewrite-6.cfg
Normal 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
|
519
src/test/ref/index-pointer-rewrite-6.log
Normal file
519
src/test/ref/index-pointer-rewrite-6.log
Normal 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
|
||||
|
18
src/test/ref/index-pointer-rewrite-6.sym
Normal file
18
src/test/ref/index-pointer-rewrite-6.sym
Normal 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 ]
|
115
src/test/ref/index-pointer-rewrite-7.asm
Normal file
115
src/test/ref/index-pointer-rewrite-7.asm
Normal 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
|
26
src/test/ref/index-pointer-rewrite-7.cfg
Normal file
26
src/test/ref/index-pointer-rewrite-7.cfg
Normal 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
|
762
src/test/ref/index-pointer-rewrite-7.log
Normal file
762
src/test/ref/index-pointer-rewrite-7.log
Normal 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
|
||||
|
23
src/test/ref/index-pointer-rewrite-7.sym
Normal file
23
src/test/ref/index-pointer-rewrite-7.sym
Normal 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 ]
|
40
src/test/ref/index-pointer-rewrite-8.asm
Normal file
40
src/test/ref/index-pointer-rewrite-8.asm
Normal 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
|
20
src/test/ref/index-pointer-rewrite-8.cfg
Normal file
20
src/test/ref/index-pointer-rewrite-8.cfg
Normal 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
|
407
src/test/ref/index-pointer-rewrite-8.log
Normal file
407
src/test/ref/index-pointer-rewrite-8.log
Normal 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
|
||||
|
19
src/test/ref/index-pointer-rewrite-8.sym
Normal file
19
src/test/ref/index-pointer-rewrite-8.sym
Normal 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 ]
|
108
src/test/ref/index-pointer-rewrite-9.asm
Normal file
108
src/test/ref/index-pointer-rewrite-9.asm
Normal 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
|
26
src/test/ref/index-pointer-rewrite-9.cfg
Normal file
26
src/test/ref/index-pointer-rewrite-9.cfg
Normal 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
|
699
src/test/ref/index-pointer-rewrite-9.log
Normal file
699
src/test/ref/index-pointer-rewrite-9.log
Normal 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
|
||||
|
29
src/test/ref/index-pointer-rewrite-9.sym
Normal file
29
src/test/ref/index-pointer-rewrite-9.sym
Normal 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 ]
|
Loading…
x
Reference in New Issue
Block a user