mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-25 20:32:25 +00:00
- Added test cases.
- Checked asm outputs. - banking is only implemented for the cx16 for now.
This commit is contained in:
parent
4706611564
commit
5bd84e7812
@ -1496,68 +1496,63 @@ public class TestProgramsFast extends TestPrograms {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcedureCallingConventionPhiFarx() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-phi-far-x.c");
|
||||
public void testProcedureCallingConventionPhiBank0() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-phi-bank-0.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcedureCallingConventionPhiFar0() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-phi-far-0.c");
|
||||
public void testProcedureCallingConventionPhiBank1() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-phi-bank-1.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcedureCallingConventionPhiFar1() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-phi-far-1.c");
|
||||
public void testProcedureCallingConventionPhiBank2() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-phi-bank-2.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcedureCallingConventionPhiFar2() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-phi-far-2.c");
|
||||
public void testProcedureCallingConventionPhiBank3() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-phi-bank-3.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcedureCallingConventionPhiFar3() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-phi-far-3.c");
|
||||
public void testProcedureCallingConventionPhiBank4() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-phi-bank-4.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcedureCallingConventionPhiFar4() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-phi-far-4.c");
|
||||
public void testProcedureCallingConventionPhiBank5() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-phi-bank-5.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcedureCallingConventionPhiFar5() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-phi-far-5.c");
|
||||
public void testProcedureCallingConventionStackBank5() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-stack-bank-5.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcedureCallingConventionStackFar5() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-stack-far-5.c");
|
||||
public void testProcedureCallingConventionStackBank4() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-stack-bank-4.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcedureCallingConventionStackFar4() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-stack-far-4.c");
|
||||
public void testProcedureCallingConventionStackBank3() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-stack-bank-3.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcedureCallingConventionStackFar3() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-stack-far-3.c");
|
||||
public void testProcedureCallingConventionStackBank2() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-stack-bank-2.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcedureCallingConventionStackFar2() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-stack-far-2.c");
|
||||
public void testProcedureCallingConventionStackBank1() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-stack-bank-1.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcedureCallingConventionStackFar1() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-stack-far-1.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcedureCallingConventionStackFar0() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-stack-far-0.c");
|
||||
public void testProcedureCallingConventionStackBank0() throws IOException {
|
||||
compileAndCompare("procedure-callingconvention-stack-bank-0.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1,12 +1,15 @@
|
||||
// Test a procedure with calling convention stack
|
||||
|
||||
#pragma code_seg(stage)
|
||||
#pragma link("procedure-callingconvention-phi-bank.ld")
|
||||
#pragma target(cx16)
|
||||
|
||||
char* const SCREEN = (char*)0x0400;
|
||||
|
||||
void main(void) {
|
||||
SCREEN[0] = plus('0', 7);
|
||||
}
|
||||
|
||||
#pragma code_seg(stage)
|
||||
char __bank(ram,2) plus(char a, char b) {
|
||||
return a+b;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
// Test a far call procedure with a calling convention sp
|
||||
|
||||
#pragma code_seg(stage)
|
||||
#pragma link("procedure-callingconvention-phi-bank.ld")
|
||||
#pragma target(cx16)
|
||||
|
||||
char* const SCREEN = (char*)0x0400;
|
||||
|
||||
void main(void) {
|
||||
|
@ -1,5 +1,9 @@
|
||||
// Test a far call procedure with a calling convention sp
|
||||
|
||||
#pragma code_seg(stage)
|
||||
#pragma link("procedure-callingconvention-phi-bank.ld")
|
||||
#pragma target(cx16)
|
||||
|
||||
char* const SCREEN = (char*)0x0400;
|
||||
|
||||
void main(void) {
|
||||
|
@ -1,5 +1,9 @@
|
||||
// Test a far call procedure with a calling convention sp
|
||||
|
||||
#pragma code_seg(stage)
|
||||
#pragma link("procedure-callingconvention-phi-bank.ld")
|
||||
#pragma target(cx16)
|
||||
|
||||
char* const SCREEN = (char*)0x0400;
|
||||
|
||||
void main(void) {
|
||||
|
@ -1,5 +1,9 @@
|
||||
// Test a far call procedure with a calling convention phi
|
||||
|
||||
#pragma code_seg(stage)
|
||||
#pragma link("procedure-callingconvention-phi-bank.ld")
|
||||
#pragma target(cx16)
|
||||
|
||||
char* const SCREEN = (char*)0x0400;
|
||||
|
||||
#pragma code_seg(stage)
|
||||
|
@ -1,8 +1,12 @@
|
||||
// Test a far call procedure with a calling convention phi
|
||||
|
||||
#pragma code_seg(stage)
|
||||
#pragma link("procedure-callingconvention-phi-bank.ld")
|
||||
#pragma target(cx16)
|
||||
|
||||
char* const SCREEN = (char*)0x0400;
|
||||
|
||||
#pragma code_seg(bank_1)
|
||||
#pragma code_seg(stage)
|
||||
#pragma bank(ram, 1)
|
||||
|
||||
char func_bank1_a(char a, char b) {
|
||||
@ -19,7 +23,7 @@ char func_bank1_d(char a, char b) {
|
||||
return func_bank2_a(a,b);
|
||||
}
|
||||
|
||||
#pragma code_seg(bank_2)
|
||||
#pragma code_seg(platform)
|
||||
#pragma bank(ram, 2)
|
||||
|
||||
char func_bank2_a(char a, char b) {
|
||||
@ -47,7 +51,7 @@ char func_bank2_f(char a, char b) {
|
||||
return func_bank1_b(a,b);
|
||||
}
|
||||
|
||||
#pragma nobank
|
||||
#pragma nobank(dummy)
|
||||
|
||||
char __bank(ram, 1) func_bank1_b(char a, char b) {
|
||||
return a+b;
|
||||
@ -57,7 +61,7 @@ char __bank(ram, 2) func_bank2_b(char a, char b) {
|
||||
return a+b;
|
||||
}
|
||||
|
||||
#pragma nobank
|
||||
#pragma nobank(dummy)
|
||||
|
||||
char func_bank1_e(char a, char b) {
|
||||
// this should be a far call, because the call is to bank 1.
|
||||
|
7
src/test/kc/procedure-callingconvention-phi-bank.ld
Normal file
7
src/test/kc/procedure-callingconvention-phi-bank.ld
Normal file
@ -0,0 +1,7 @@
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=%P]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
@ -1,12 +1,16 @@
|
||||
// Test a procedure with calling convention stack
|
||||
|
||||
#pragma code_seg(stage)
|
||||
#pragma link("procedure-callingconvention-stack-bank.ld")
|
||||
#pragma target(cx16)
|
||||
|
||||
char* const SCREEN = (char*)0x0400;
|
||||
|
||||
void main(void) {
|
||||
SCREEN[0] = plus('0', 7);
|
||||
}
|
||||
|
||||
#pragma code_seg(test)
|
||||
#pragma code_seg(stage)
|
||||
char __bank(ram, 2) __stackcall plus(char a, char b) {
|
||||
return a+b;
|
||||
}
|
@ -1,5 +1,9 @@
|
||||
// Test a procedure with calling convention stack
|
||||
|
||||
#pragma code_seg(stage)
|
||||
#pragma link("procedure-callingconvention-stack-bank.ld")
|
||||
#pragma target(cx16)
|
||||
|
||||
char* const SCREEN = (char*)0x0400;
|
||||
|
||||
void main(void) {
|
||||
@ -7,7 +11,7 @@ void main(void) {
|
||||
}
|
||||
|
||||
#pragma calling(__stackcall)
|
||||
#pragma code_seg(test)
|
||||
#pragma code_seg(stage)
|
||||
|
||||
char __bank(ram,20) plus(char a, char b) {
|
||||
return a+b;
|
||||
|
@ -1,6 +1,10 @@
|
||||
// Test a procedure with calling convention stack
|
||||
// A slightly more complex call
|
||||
|
||||
#pragma code_seg(stage)
|
||||
#pragma link("procedure-callingconvention-stack-bank.ld")
|
||||
#pragma target(cx16)
|
||||
|
||||
char* const SCREEN = (char*)0x0400;
|
||||
|
||||
char i = 0;
|
||||
|
@ -3,6 +3,10 @@
|
||||
|
||||
#pragma calling(__stackcall)
|
||||
|
||||
#pragma code_seg(stage)
|
||||
#pragma link("procedure-callingconvention-stack-bank.ld")
|
||||
#pragma target(cx16)
|
||||
|
||||
char* const SCREEN = (char*)0x0400;
|
||||
|
||||
char val = 0;
|
||||
|
@ -4,6 +4,10 @@
|
||||
#pragma calling(__stackcall)
|
||||
#pragma struct_model(classic)
|
||||
|
||||
#pragma code_seg(stage)
|
||||
#pragma link("procedure-callingconvention-stack-bank.ld")
|
||||
#pragma target(cx16)
|
||||
|
||||
char* const SCREEN = (char*)0x0400;
|
||||
char idx = 0;
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
// Test a procedure with calling convention stack
|
||||
// Recursion that works (no local variables)
|
||||
|
||||
#pragma code_seg(stage)
|
||||
#pragma link("procedure-callingconvention-stack-bank.ld")
|
||||
#pragma platform(cx16)
|
||||
|
||||
char* const SCREEN = (char*)0x0400;
|
||||
|
||||
void main(void) {
|
||||
|
6
src/test/kc/procedure-callingconvention-stack-bank.ld
Normal file
6
src/test/kc/procedure-callingconvention-stack-bank.ld
Normal file
@ -0,0 +1,6 @@
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=%P]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
@ -12,7 +12,7 @@
|
||||
main: {
|
||||
// asm
|
||||
jmp qwe
|
||||
.byte 0, 25, 51, 76, 102, 128, 153, 179, 204, 230
|
||||
.byte 0, $19, $33, $4c, $66, $80, $99, $b3, $cc, $e6
|
||||
qwe:
|
||||
lda #$32
|
||||
// *((char*)0x0400) = 'c'
|
||||
|
@ -83,7 +83,7 @@ ASSEMBLER BEFORE OPTIMIZATION
|
||||
main: {
|
||||
// asm { jmpqwe .byte0,25,51,76,102,128,153,179,204,230 qwe: lda#50 }
|
||||
jmp qwe
|
||||
.byte 0, 25, 51, 76, 102, 128, 153, 179, 204, 230
|
||||
.byte 0, $19, $33, $4c, $66, $80, $99, $b3, $cc, $e6
|
||||
qwe:
|
||||
lda #$32
|
||||
// [1] *((char *) 1024) = 'c' -- _deref_pbuc1=vbuc2
|
||||
@ -130,7 +130,7 @@ main: {
|
||||
// asm
|
||||
// asm { jmpqwe .byte0,25,51,76,102,128,153,179,204,230 qwe: lda#50 }
|
||||
jmp qwe
|
||||
.byte 0, 25, 51, 76, 102, 128, 153, 179, 204, 230
|
||||
.byte 0, $19, $33, $4c, $66, $80, $99, $b3, $cc, $e6
|
||||
qwe:
|
||||
lda #$32
|
||||
// *((char*)0x0400) = 'c'
|
||||
|
@ -457,7 +457,7 @@ dtvSetCpuBankSegment1: {
|
||||
// asm
|
||||
.byte $32, $dd
|
||||
lda.z $ff
|
||||
.byte $32, $00
|
||||
.byte $32, 0
|
||||
// }
|
||||
rts
|
||||
}
|
||||
|
@ -1872,7 +1872,7 @@ dtvSetCpuBankSegment1: {
|
||||
// asm { .byte$32,$dd lda$ff .byte$32,$00 }
|
||||
.byte $32, $dd
|
||||
lda.z $ff
|
||||
.byte $32, $00
|
||||
.byte $32, 0
|
||||
jmp __breturn
|
||||
// dtvSetCpuBankSegment1::@return
|
||||
__breturn:
|
||||
@ -2714,7 +2714,7 @@ dtvSetCpuBankSegment1: {
|
||||
// asm { .byte$32,$dd lda$ff .byte$32,$00 }
|
||||
.byte $32, $dd
|
||||
lda.z $ff
|
||||
.byte $32, $00
|
||||
.byte $32, 0
|
||||
// dtvSetCpuBankSegment1::@return
|
||||
// }
|
||||
// [87] return
|
||||
|
@ -365,7 +365,7 @@ dtvSetCpuBankSegment1: {
|
||||
// asm
|
||||
.byte $32, $dd
|
||||
lda.z $ff
|
||||
.byte $32, $00
|
||||
.byte $32, 0
|
||||
// }
|
||||
rts
|
||||
}
|
||||
|
@ -1260,7 +1260,7 @@ dtvSetCpuBankSegment1: {
|
||||
// asm { .byte$32,$dd lda$ff .byte$32,$00 }
|
||||
.byte $32, $dd
|
||||
lda.z $ff
|
||||
.byte $32, $00
|
||||
.byte $32, 0
|
||||
jmp __breturn
|
||||
// dtvSetCpuBankSegment1::@return
|
||||
__breturn:
|
||||
@ -1881,7 +1881,7 @@ dtvSetCpuBankSegment1: {
|
||||
// asm { .byte$32,$dd lda$ff .byte$32,$00 }
|
||||
.byte $32, $dd
|
||||
lda.z $ff
|
||||
.byte $32, $00
|
||||
.byte $32, 0
|
||||
// dtvSetCpuBankSegment1::@return
|
||||
// }
|
||||
// [57] return
|
||||
|
28
src/test/ref/procedure-callingconvention-phi-bank-0.asm
Normal file
28
src/test/ref/procedure-callingconvention-phi-bank-0.asm
Normal file
@ -0,0 +1,28 @@
|
||||
// Test a procedure with calling convention stack
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
main: {
|
||||
// plus('0', 7)
|
||||
jsr plus
|
||||
// SCREEN[0] = plus('0', 7)
|
||||
lda #plus.return
|
||||
sta SCREEN
|
||||
// }
|
||||
rts
|
||||
}
|
||||
// char plus(char a, char b)
|
||||
plus: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
.label return = a+b
|
||||
rts
|
||||
}
|
20
src/test/ref/procedure-callingconvention-phi-bank-0.cfg
Normal file
20
src/test/ref/procedure-callingconvention-phi-bank-0.cfg
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
[1] call plus
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main
|
||||
[2] *SCREEN = plus::return#1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[3] return
|
||||
to:@return
|
||||
|
||||
char plus(char a , char b)
|
||||
plus: scope:[plus] from main
|
||||
[4] phi()
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
[5] return
|
||||
to:@return
|
275
src/test/ref/procedure-callingconvention-phi-bank-0.log
Normal file
275
src/test/ref/procedure-callingconvention-phi-bank-0.log
Normal file
@ -0,0 +1,275 @@
|
||||
Loading link script "procedure-callingconvention-phi-bank.ld"
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
void main()
|
||||
main: scope:[main] from __start
|
||||
plus::a#0 = '0'
|
||||
plus::b#0 = 7
|
||||
call plus
|
||||
plus::return#0 = plus::return#2
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main
|
||||
plus::return#3 = phi( main/plus::return#0 )
|
||||
main::$0 = plus::return#3
|
||||
SCREEN[0] = main::$0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
char plus(char a , char b)
|
||||
plus: scope:[plus] from main
|
||||
plus::b#1 = phi( main/plus::b#0 )
|
||||
plus::a#1 = phi( main/plus::a#0 )
|
||||
plus::$0 = plus::a#1 + plus::b#1
|
||||
plus::return#1 = plus::$0
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
plus::return#4 = phi( plus/plus::return#1 )
|
||||
plus::return#2 = plus::return#4
|
||||
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
|
||||
__constant char * const SCREEN = (char *)$400
|
||||
void __start()
|
||||
void main()
|
||||
char main::$0
|
||||
char plus(char a , char b)
|
||||
char plus::$0
|
||||
char plus::a
|
||||
char plus::a#0
|
||||
char plus::a#1
|
||||
char plus::b
|
||||
char plus::b#0
|
||||
char plus::b#1
|
||||
char plus::return
|
||||
char plus::return#0
|
||||
char plus::return#1
|
||||
char plus::return#2
|
||||
char plus::return#3
|
||||
char plus::return#4
|
||||
|
||||
Adding number conversion cast (unumber) 7 in plus::b#0 = 7
|
||||
Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Inlining cast plus::b#0 = (unumber)7
|
||||
Successful SSA optimization Pass2InlineCast
|
||||
Simplifying constant pointer cast (char *) 1024
|
||||
Simplifying constant integer cast 7
|
||||
Simplifying constant integer cast 0
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (char) 7
|
||||
Finalized unsigned number type (char) 0
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Alias plus::return#0 = plus::return#3
|
||||
Alias plus::return#1 = plus::$0 plus::return#4 plus::return#2
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Identical Phi Values plus::a#1 plus::a#0
|
||||
Identical Phi Values plus::b#1 plus::b#0
|
||||
Successful SSA optimization Pass2IdenticalPhiElimination
|
||||
Constant plus::a#0 = '0'
|
||||
Constant plus::b#0 = 7
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Simplifying expression containing zero SCREEN in [5] SCREEN[0] = main::$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
|
||||
Constant right-side identified [5] plus::return#1 = plus::a#0 + plus::b#0
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant plus::return#1 = plus::a#0+plus::b#0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Constant plus::return#0 = plus::return#1
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Constant main::$0 = plus::return#0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Inlining constant with different constant siblings plus::return#0
|
||||
Constant inlined plus::return#0 = plus::return#1
|
||||
Constant inlined main::$0 = plus::return#1
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Adding NOP phi() at start of main
|
||||
Adding NOP phi() at start of plus
|
||||
CALL GRAPH
|
||||
Calls in [main] to plus:1
|
||||
|
||||
Created 0 initial phi equivalence classes
|
||||
Coalesced down to 0 phi equivalence classes
|
||||
Adding NOP phi() at start of main
|
||||
Adding NOP phi() at start of plus
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
[1] call plus
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main
|
||||
[2] *SCREEN = plus::return#1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[3] return
|
||||
to:@return
|
||||
|
||||
char plus(char a , char b)
|
||||
plus: scope:[plus] from main
|
||||
[4] phi()
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
[5] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
void main()
|
||||
char plus(char a , char b)
|
||||
char plus::a
|
||||
char plus::b
|
||||
char plus::return
|
||||
|
||||
Initial phi equivalence classes
|
||||
Complete equivalence classes
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [2] *SCREEN = plus::return#1 [ ] ( [ ] { } ) always clobbers reg byte a
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main]
|
||||
Uplift Scope [plus]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 60 combination
|
||||
Uplifting [plus] best 60 combination
|
||||
Uplifting [] best 60 combination
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Test a procedure with calling convention stack
|
||||
// Upstart
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
|
||||
// Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
// main
|
||||
main: {
|
||||
// [1] call plus
|
||||
// [4] phi from main to plus [phi:main->plus]
|
||||
plus_from_main:
|
||||
jsr plus
|
||||
jmp __b1
|
||||
// main::@1
|
||||
__b1:
|
||||
// [2] *SCREEN = plus::return#1 -- _deref_pbuc1=vbuc2
|
||||
lda #plus.return
|
||||
sta SCREEN
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [3] return
|
||||
rts
|
||||
}
|
||||
// plus
|
||||
// char plus(char a, char b)
|
||||
plus: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
.label return = a+b
|
||||
jmp __breturn
|
||||
// plus::@return
|
||||
__breturn:
|
||||
// [5] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction plus_from_main:
|
||||
Removing instruction __b1:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
void main()
|
||||
char plus(char a , char b)
|
||||
char plus::a
|
||||
__constant char plus::a#0 = '0' // a
|
||||
char plus::b
|
||||
__constant char plus::b#0 = 7 // b
|
||||
char plus::return
|
||||
__constant char plus::return#1 = plus::a#0+plus::b#0 // return
|
||||
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 24
|
||||
|
||||
// File Comments
|
||||
// Test a procedure with calling convention stack
|
||||
// Upstart
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
|
||||
// Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
// main
|
||||
main: {
|
||||
// plus('0', 7)
|
||||
// [1] call plus
|
||||
// [4] phi from main to plus [phi:main->plus]
|
||||
jsr plus
|
||||
// main::@1
|
||||
// SCREEN[0] = plus('0', 7)
|
||||
// [2] *SCREEN = plus::return#1 -- _deref_pbuc1=vbuc2
|
||||
lda #plus.return
|
||||
sta SCREEN
|
||||
// main::@return
|
||||
// }
|
||||
// [3] return
|
||||
rts
|
||||
}
|
||||
// plus
|
||||
// char plus(char a, char b)
|
||||
plus: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
.label return = a+b
|
||||
// plus::@return
|
||||
// [5] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
10
src/test/ref/procedure-callingconvention-phi-bank-0.sym
Normal file
10
src/test/ref/procedure-callingconvention-phi-bank-0.sym
Normal file
@ -0,0 +1,10 @@
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
void main()
|
||||
char plus(char a , char b)
|
||||
char plus::a
|
||||
__constant char plus::a#0 = '0' // a
|
||||
char plus::b
|
||||
__constant char plus::b#0 = 7 // b
|
||||
char plus::return
|
||||
__constant char plus::return#1 = plus::a#0+plus::b#0 // return
|
||||
|
31
src/test/ref/procedure-callingconvention-phi-bank-1.asm
Normal file
31
src/test/ref/procedure-callingconvention-phi-bank-1.asm
Normal file
@ -0,0 +1,31 @@
|
||||
// Test a far call procedure with a calling convention sp
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
main: {
|
||||
// plus('0', 7)
|
||||
jsr $ff6e
|
||||
.byte <plus
|
||||
.byte >plus
|
||||
.byte 1
|
||||
// SCREEN[0] = plus('0', 7)
|
||||
lda #plus.return
|
||||
sta SCREEN
|
||||
// }
|
||||
rts
|
||||
}
|
||||
// char plus(char a, char b)
|
||||
plus: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
.label return = a+b
|
||||
rts
|
||||
}
|
20
src/test/ref/procedure-callingconvention-phi-bank-1.cfg
Normal file
20
src/test/ref/procedure-callingconvention-phi-bank-1.cfg
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
[1] call plus
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main
|
||||
[2] *SCREEN = plus::return#1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[3] return
|
||||
to:@return
|
||||
|
||||
__bank(bank) char plus(char a , char b)
|
||||
plus: scope:[plus] from main
|
||||
[4] phi()
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
[5] return
|
||||
to:@return
|
281
src/test/ref/procedure-callingconvention-phi-bank-1.log
Normal file
281
src/test/ref/procedure-callingconvention-phi-bank-1.log
Normal file
@ -0,0 +1,281 @@
|
||||
Loading link script "procedure-callingconvention-phi-bank.ld"
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
void main()
|
||||
main: scope:[main] from __start
|
||||
plus::a#0 = '0'
|
||||
plus::b#0 = 7
|
||||
call plus
|
||||
plus::return#0 = plus::return#2
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main
|
||||
plus::return#3 = phi( main/plus::return#0 )
|
||||
main::$0 = plus::return#3
|
||||
SCREEN[0] = main::$0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
__bank(bank) char plus(char a , char b)
|
||||
plus: scope:[plus] from main
|
||||
plus::b#1 = phi( main/plus::b#0 )
|
||||
plus::a#1 = phi( main/plus::a#0 )
|
||||
plus::$0 = plus::a#1 + plus::b#1
|
||||
plus::return#1 = plus::$0
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
plus::return#4 = phi( plus/plus::return#1 )
|
||||
plus::return#2 = plus::return#4
|
||||
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
|
||||
__constant char * const SCREEN = (char *)$400
|
||||
void __start()
|
||||
void main()
|
||||
char main::$0
|
||||
__bank(bank) char plus(char a , char b)
|
||||
char plus::$0
|
||||
char plus::a
|
||||
char plus::a#0
|
||||
char plus::a#1
|
||||
char plus::b
|
||||
char plus::b#0
|
||||
char plus::b#1
|
||||
char plus::return
|
||||
char plus::return#0
|
||||
char plus::return#1
|
||||
char plus::return#2
|
||||
char plus::return#3
|
||||
char plus::return#4
|
||||
|
||||
Adding number conversion cast (unumber) 7 in plus::b#0 = 7
|
||||
Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Inlining cast plus::b#0 = (unumber)7
|
||||
Successful SSA optimization Pass2InlineCast
|
||||
Simplifying constant pointer cast (char *) 1024
|
||||
Simplifying constant integer cast 7
|
||||
Simplifying constant integer cast 0
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (char) 7
|
||||
Finalized unsigned number type (char) 0
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Alias plus::return#0 = plus::return#3
|
||||
Alias plus::return#1 = plus::$0 plus::return#4 plus::return#2
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Identical Phi Values plus::a#1 plus::a#0
|
||||
Identical Phi Values plus::b#1 plus::b#0
|
||||
Successful SSA optimization Pass2IdenticalPhiElimination
|
||||
Constant plus::a#0 = '0'
|
||||
Constant plus::b#0 = 7
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Simplifying expression containing zero SCREEN in [5] SCREEN[0] = main::$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
|
||||
Constant right-side identified [5] plus::return#1 = plus::a#0 + plus::b#0
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant plus::return#1 = plus::a#0+plus::b#0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Constant plus::return#0 = plus::return#1
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Constant main::$0 = plus::return#0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Inlining constant with different constant siblings plus::return#0
|
||||
Constant inlined plus::return#0 = plus::return#1
|
||||
Constant inlined main::$0 = plus::return#1
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Adding NOP phi() at start of main
|
||||
Adding NOP phi() at start of plus
|
||||
CALL GRAPH
|
||||
Calls in [main] to plus:1
|
||||
|
||||
Created 0 initial phi equivalence classes
|
||||
Coalesced down to 0 phi equivalence classes
|
||||
Adding NOP phi() at start of main
|
||||
Adding NOP phi() at start of plus
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
[1] call plus
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main
|
||||
[2] *SCREEN = plus::return#1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[3] return
|
||||
to:@return
|
||||
|
||||
__bank(bank) char plus(char a , char b)
|
||||
plus: scope:[plus] from main
|
||||
[4] phi()
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
[5] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
void main()
|
||||
__bank(bank) char plus(char a , char b)
|
||||
char plus::a
|
||||
char plus::b
|
||||
char plus::return
|
||||
|
||||
Initial phi equivalence classes
|
||||
Complete equivalence classes
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [2] *SCREEN = plus::return#1 [ ] ( [ ] { } ) always clobbers reg byte a
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main]
|
||||
Uplift Scope [plus]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 60 combination
|
||||
Uplifting [plus] best 60 combination
|
||||
Uplifting [] best 60 combination
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Test a far call procedure with a calling convention sp
|
||||
// Upstart
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
|
||||
// Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
// main
|
||||
main: {
|
||||
// [1] call plus
|
||||
// [4] phi from main to plus [phi:main->plus] -- call_far_cx16_ram_finalize
|
||||
plus_from_main:
|
||||
jsr $ff6e
|
||||
.byte <plus
|
||||
.byte >plus
|
||||
.byte 1
|
||||
jmp __b1
|
||||
// main::@1
|
||||
__b1:
|
||||
// [2] *SCREEN = plus::return#1 -- _deref_pbuc1=vbuc2
|
||||
lda #plus.return
|
||||
sta SCREEN
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [3] return
|
||||
rts
|
||||
}
|
||||
// plus
|
||||
// char plus(char a, char b)
|
||||
plus: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
.label return = a+b
|
||||
jmp __breturn
|
||||
// plus::@return
|
||||
__breturn:
|
||||
// [5] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction plus_from_main:
|
||||
Removing instruction __b1:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
void main()
|
||||
__bank(bank) char plus(char a , char b)
|
||||
char plus::a
|
||||
__constant char plus::a#0 = '0' // a
|
||||
char plus::b
|
||||
__constant char plus::b#0 = 7 // b
|
||||
char plus::return
|
||||
__constant char plus::return#1 = plus::a#0+plus::b#0 // return
|
||||
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 24
|
||||
|
||||
// File Comments
|
||||
// Test a far call procedure with a calling convention sp
|
||||
// Upstart
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
|
||||
// Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
// main
|
||||
main: {
|
||||
// plus('0', 7)
|
||||
// [1] call plus
|
||||
// [4] phi from main to plus [phi:main->plus] -- call_far_cx16_ram_finalize
|
||||
jsr $ff6e
|
||||
.byte <plus
|
||||
.byte >plus
|
||||
.byte 1
|
||||
// main::@1
|
||||
// SCREEN[0] = plus('0', 7)
|
||||
// [2] *SCREEN = plus::return#1 -- _deref_pbuc1=vbuc2
|
||||
lda #plus.return
|
||||
sta SCREEN
|
||||
// main::@return
|
||||
// }
|
||||
// [3] return
|
||||
rts
|
||||
}
|
||||
// plus
|
||||
// char plus(char a, char b)
|
||||
plus: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
.label return = a+b
|
||||
// plus::@return
|
||||
// [5] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
10
src/test/ref/procedure-callingconvention-phi-bank-1.sym
Normal file
10
src/test/ref/procedure-callingconvention-phi-bank-1.sym
Normal file
@ -0,0 +1,10 @@
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
void main()
|
||||
__bank(bank) char plus(char a , char b)
|
||||
char plus::a
|
||||
__constant char plus::a#0 = '0' // a
|
||||
char plus::b
|
||||
__constant char plus::b#0 = 7 // b
|
||||
char plus::return
|
||||
__constant char plus::return#1 = plus::a#0+plus::b#0 // return
|
||||
|
28
src/test/ref/procedure-callingconvention-phi-bank-2.asm
Normal file
28
src/test/ref/procedure-callingconvention-phi-bank-2.asm
Normal file
@ -0,0 +1,28 @@
|
||||
// Test a far call procedure with a calling convention sp
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
main: {
|
||||
// plus('0', 7)
|
||||
.assert "Missing ASM fragment Fragment not found call_far_cx16_rubbish_prepare. Attempted variations call_far_cx16_rubbish_prepare ", 0, 1
|
||||
// SCREEN[0] = plus('0', 7)
|
||||
lda #plus.return
|
||||
sta SCREEN
|
||||
// }
|
||||
rts
|
||||
}
|
||||
// char plus(char a, char b)
|
||||
plus: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
.label return = a+b
|
||||
rts
|
||||
}
|
20
src/test/ref/procedure-callingconvention-phi-bank-2.cfg
Normal file
20
src/test/ref/procedure-callingconvention-phi-bank-2.cfg
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
[1] call plus
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main
|
||||
[2] *SCREEN = plus::return#1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[3] return
|
||||
to:@return
|
||||
|
||||
__bank(bank) char plus(char a , char b)
|
||||
plus: scope:[plus] from main
|
||||
[4] phi()
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
[5] return
|
||||
to:@return
|
294
src/test/ref/procedure-callingconvention-phi-bank-2.log
Normal file
294
src/test/ref/procedure-callingconvention-phi-bank-2.log
Normal file
@ -0,0 +1,294 @@
|
||||
Loading link script "procedure-callingconvention-phi-bank.ld"
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
void main()
|
||||
main: scope:[main] from __start
|
||||
plus::a#0 = '0'
|
||||
plus::b#0 = 7
|
||||
call plus
|
||||
plus::return#0 = plus::return#2
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main
|
||||
plus::return#3 = phi( main/plus::return#0 )
|
||||
main::$0 = plus::return#3
|
||||
SCREEN[0] = main::$0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
__bank(bank) char plus(char a , char b)
|
||||
plus: scope:[plus] from main
|
||||
plus::b#1 = phi( main/plus::b#0 )
|
||||
plus::a#1 = phi( main/plus::a#0 )
|
||||
plus::$0 = plus::a#1 + plus::b#1
|
||||
plus::return#1 = plus::$0
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
plus::return#4 = phi( plus/plus::return#1 )
|
||||
plus::return#2 = plus::return#4
|
||||
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
|
||||
__constant char * const SCREEN = (char *)$400
|
||||
void __start()
|
||||
void main()
|
||||
char main::$0
|
||||
__bank(bank) char plus(char a , char b)
|
||||
char plus::$0
|
||||
char plus::a
|
||||
char plus::a#0
|
||||
char plus::a#1
|
||||
char plus::b
|
||||
char plus::b#0
|
||||
char plus::b#1
|
||||
char plus::return
|
||||
char plus::return#0
|
||||
char plus::return#1
|
||||
char plus::return#2
|
||||
char plus::return#3
|
||||
char plus::return#4
|
||||
|
||||
Adding number conversion cast (unumber) 7 in plus::b#0 = 7
|
||||
Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Inlining cast plus::b#0 = (unumber)7
|
||||
Successful SSA optimization Pass2InlineCast
|
||||
Simplifying constant pointer cast (char *) 1024
|
||||
Simplifying constant integer cast 7
|
||||
Simplifying constant integer cast 0
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (char) 7
|
||||
Finalized unsigned number type (char) 0
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Alias plus::return#0 = plus::return#3
|
||||
Alias plus::return#1 = plus::$0 plus::return#4 plus::return#2
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Identical Phi Values plus::a#1 plus::a#0
|
||||
Identical Phi Values plus::b#1 plus::b#0
|
||||
Successful SSA optimization Pass2IdenticalPhiElimination
|
||||
Constant plus::a#0 = '0'
|
||||
Constant plus::b#0 = 7
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Simplifying expression containing zero SCREEN in [5] SCREEN[0] = main::$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
|
||||
Constant right-side identified [5] plus::return#1 = plus::a#0 + plus::b#0
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant plus::return#1 = plus::a#0+plus::b#0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Constant plus::return#0 = plus::return#1
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Constant main::$0 = plus::return#0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Inlining constant with different constant siblings plus::return#0
|
||||
Constant inlined plus::return#0 = plus::return#1
|
||||
Constant inlined main::$0 = plus::return#1
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Adding NOP phi() at start of main
|
||||
Adding NOP phi() at start of plus
|
||||
CALL GRAPH
|
||||
Calls in [main] to plus:1
|
||||
|
||||
Created 0 initial phi equivalence classes
|
||||
Coalesced down to 0 phi equivalence classes
|
||||
Adding NOP phi() at start of main
|
||||
Adding NOP phi() at start of plus
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
[1] call plus
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main
|
||||
[2] *SCREEN = plus::return#1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[3] return
|
||||
to:@return
|
||||
|
||||
__bank(bank) char plus(char a , char b)
|
||||
plus: scope:[plus] from main
|
||||
[4] phi()
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
[5] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
void main()
|
||||
__bank(bank) char plus(char a , char b)
|
||||
char plus::a
|
||||
char plus::b
|
||||
char plus::return
|
||||
|
||||
Initial phi equivalence classes
|
||||
Complete equivalence classes
|
||||
Warning! Unknown fragment for statement [1] call plus
|
||||
Missing ASM fragment Fragment not found call_far_cx16_rubbish_prepare. Attempted variations call_far_cx16_rubbish_prepare
|
||||
D:\Users\svenv\OneDrive\Documents\GitHub\kickc\src\test\kc\procedure-callingconvention-phi-bank-2.c:10:17:
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Potential register analysis [1] call plus missing fragment Fragment not found call_far_cx16_rubbish_prepare. Attempted variations call_far_cx16_rubbish_prepare allocation:
|
||||
MISSING FRAGMENTS
|
||||
Fragment not found call_far_cx16_rubbish_prepare. Attempted variations call_far_cx16_rubbish_prepare
|
||||
Statement [1] call plus [ ] ( [ ] { } ) always clobbers reg byte a reg byte x reg byte y
|
||||
Statement [2] *SCREEN = plus::return#1 [ ] ( [ ] { } ) always clobbers reg byte a
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main]
|
||||
Uplift Scope [plus]
|
||||
Uplift Scope []
|
||||
|
||||
Warning! Unknown fragment for statement [1] call plus
|
||||
Missing ASM fragment Fragment not found call_far_cx16_rubbish_prepare. Attempted variations call_far_cx16_rubbish_prepare
|
||||
D:\Users\svenv\OneDrive\Documents\GitHub\kickc\src\test\kc\procedure-callingconvention-phi-bank-2.c:10:17:
|
||||
Uplifting [main] best 54 combination
|
||||
Warning! Unknown fragment for statement [1] call plus
|
||||
Missing ASM fragment Fragment not found call_far_cx16_rubbish_prepare. Attempted variations call_far_cx16_rubbish_prepare
|
||||
D:\Users\svenv\OneDrive\Documents\GitHub\kickc\src\test\kc\procedure-callingconvention-phi-bank-2.c:10:17:
|
||||
Uplifting [plus] best 54 combination
|
||||
Warning! Unknown fragment for statement [1] call plus
|
||||
Missing ASM fragment Fragment not found call_far_cx16_rubbish_prepare. Attempted variations call_far_cx16_rubbish_prepare
|
||||
D:\Users\svenv\OneDrive\Documents\GitHub\kickc\src\test\kc\procedure-callingconvention-phi-bank-2.c:10:17:
|
||||
Uplifting [] best 54 combination
|
||||
Warning! Unknown fragment for statement [1] call plus
|
||||
Missing ASM fragment Fragment not found call_far_cx16_rubbish_prepare. Attempted variations call_far_cx16_rubbish_prepare
|
||||
D:\Users\svenv\OneDrive\Documents\GitHub\kickc\src\test\kc\procedure-callingconvention-phi-bank-2.c:10:17:
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Test a far call procedure with a calling convention sp
|
||||
// Upstart
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
|
||||
// Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
// main
|
||||
main: {
|
||||
// [1] call plus
|
||||
// [4] phi from main to plus [phi:main->plus]
|
||||
plus_from_main:
|
||||
.assert "Missing ASM fragment Fragment not found call_far_cx16_rubbish_prepare. Attempted variations call_far_cx16_rubbish_prepare ", 0, 1
|
||||
jmp __b1
|
||||
// main::@1
|
||||
__b1:
|
||||
// [2] *SCREEN = plus::return#1 -- _deref_pbuc1=vbuc2
|
||||
lda #plus.return
|
||||
sta SCREEN
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [3] return
|
||||
rts
|
||||
}
|
||||
// plus
|
||||
// char plus(char a, char b)
|
||||
plus: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
.label return = a+b
|
||||
jmp __breturn
|
||||
// plus::@return
|
||||
__breturn:
|
||||
// [5] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction plus_from_main:
|
||||
Removing instruction __b1:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
void main()
|
||||
__bank(bank) char plus(char a , char b)
|
||||
char plus::a
|
||||
__constant char plus::a#0 = '0' // a
|
||||
char plus::b
|
||||
__constant char plus::b#0 = 7 // b
|
||||
char plus::return
|
||||
__constant char plus::return#1 = plus::a#0+plus::b#0 // return
|
||||
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 18
|
||||
|
||||
// File Comments
|
||||
// Test a far call procedure with a calling convention sp
|
||||
// Upstart
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
|
||||
// Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
// main
|
||||
main: {
|
||||
// plus('0', 7)
|
||||
// [1] call plus
|
||||
// [4] phi from main to plus [phi:main->plus]
|
||||
.assert "Missing ASM fragment Fragment not found call_far_cx16_rubbish_prepare. Attempted variations call_far_cx16_rubbish_prepare ", 0, 1
|
||||
// main::@1
|
||||
// SCREEN[0] = plus('0', 7)
|
||||
// [2] *SCREEN = plus::return#1 -- _deref_pbuc1=vbuc2
|
||||
lda #plus.return
|
||||
sta SCREEN
|
||||
// main::@return
|
||||
// }
|
||||
// [3] return
|
||||
rts
|
||||
}
|
||||
// plus
|
||||
// char plus(char a, char b)
|
||||
plus: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
.label return = a+b
|
||||
// plus::@return
|
||||
// [5] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
10
src/test/ref/procedure-callingconvention-phi-bank-2.sym
Normal file
10
src/test/ref/procedure-callingconvention-phi-bank-2.sym
Normal file
@ -0,0 +1,10 @@
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
void main()
|
||||
__bank(bank) char plus(char a , char b)
|
||||
char plus::a
|
||||
__constant char plus::a#0 = '0' // a
|
||||
char plus::b
|
||||
__constant char plus::b#0 = 7 // b
|
||||
char plus::return
|
||||
__constant char plus::return#1 = plus::a#0+plus::b#0 // return
|
||||
|
28
src/test/ref/procedure-callingconvention-phi-bank-3.asm
Normal file
28
src/test/ref/procedure-callingconvention-phi-bank-3.asm
Normal file
@ -0,0 +1,28 @@
|
||||
// Test a far call procedure with a calling convention sp
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
main: {
|
||||
// plus('0', 7)
|
||||
.assert "Missing ASM fragment Fragment not found call_far_cx16_stage_prepare. Attempted variations call_far_cx16_stage_prepare ", 0, 1
|
||||
// SCREEN[0] = plus('0', 7)
|
||||
lda #plus.return
|
||||
sta SCREEN
|
||||
// }
|
||||
rts
|
||||
}
|
||||
// char plus(char a, char b)
|
||||
plus: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
.label return = a+b
|
||||
rts
|
||||
}
|
20
src/test/ref/procedure-callingconvention-phi-bank-3.cfg
Normal file
20
src/test/ref/procedure-callingconvention-phi-bank-3.cfg
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
[1] call plus
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main
|
||||
[2] *SCREEN = plus::return#1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[3] return
|
||||
to:@return
|
||||
|
||||
__bank(bank) char plus(char a , char b)
|
||||
plus: scope:[plus] from main
|
||||
[4] phi()
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
[5] return
|
||||
to:@return
|
294
src/test/ref/procedure-callingconvention-phi-bank-3.log
Normal file
294
src/test/ref/procedure-callingconvention-phi-bank-3.log
Normal file
@ -0,0 +1,294 @@
|
||||
Loading link script "procedure-callingconvention-phi-bank.ld"
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
void main()
|
||||
main: scope:[main] from __start
|
||||
plus::a#0 = '0'
|
||||
plus::b#0 = 7
|
||||
call plus
|
||||
plus::return#0 = plus::return#2
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main
|
||||
plus::return#3 = phi( main/plus::return#0 )
|
||||
main::$0 = plus::return#3
|
||||
SCREEN[0] = main::$0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
__bank(bank) char plus(char a , char b)
|
||||
plus: scope:[plus] from main
|
||||
plus::b#1 = phi( main/plus::b#0 )
|
||||
plus::a#1 = phi( main/plus::a#0 )
|
||||
plus::$0 = plus::a#1 + plus::b#1
|
||||
plus::return#1 = plus::$0
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
plus::return#4 = phi( plus/plus::return#1 )
|
||||
plus::return#2 = plus::return#4
|
||||
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
|
||||
__constant char * const SCREEN = (char *)$400
|
||||
void __start()
|
||||
void main()
|
||||
char main::$0
|
||||
__bank(bank) char plus(char a , char b)
|
||||
char plus::$0
|
||||
char plus::a
|
||||
char plus::a#0
|
||||
char plus::a#1
|
||||
char plus::b
|
||||
char plus::b#0
|
||||
char plus::b#1
|
||||
char plus::return
|
||||
char plus::return#0
|
||||
char plus::return#1
|
||||
char plus::return#2
|
||||
char plus::return#3
|
||||
char plus::return#4
|
||||
|
||||
Adding number conversion cast (unumber) 7 in plus::b#0 = 7
|
||||
Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Inlining cast plus::b#0 = (unumber)7
|
||||
Successful SSA optimization Pass2InlineCast
|
||||
Simplifying constant pointer cast (char *) 1024
|
||||
Simplifying constant integer cast 7
|
||||
Simplifying constant integer cast 0
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (char) 7
|
||||
Finalized unsigned number type (char) 0
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Alias plus::return#0 = plus::return#3
|
||||
Alias plus::return#1 = plus::$0 plus::return#4 plus::return#2
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Identical Phi Values plus::a#1 plus::a#0
|
||||
Identical Phi Values plus::b#1 plus::b#0
|
||||
Successful SSA optimization Pass2IdenticalPhiElimination
|
||||
Constant plus::a#0 = '0'
|
||||
Constant plus::b#0 = 7
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Simplifying expression containing zero SCREEN in [5] SCREEN[0] = main::$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
|
||||
Constant right-side identified [5] plus::return#1 = plus::a#0 + plus::b#0
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant plus::return#1 = plus::a#0+plus::b#0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Constant plus::return#0 = plus::return#1
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Constant main::$0 = plus::return#0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Inlining constant with different constant siblings plus::return#0
|
||||
Constant inlined plus::return#0 = plus::return#1
|
||||
Constant inlined main::$0 = plus::return#1
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Adding NOP phi() at start of main
|
||||
Adding NOP phi() at start of plus
|
||||
CALL GRAPH
|
||||
Calls in [main] to plus:1
|
||||
|
||||
Created 0 initial phi equivalence classes
|
||||
Coalesced down to 0 phi equivalence classes
|
||||
Adding NOP phi() at start of main
|
||||
Adding NOP phi() at start of plus
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
[1] call plus
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main
|
||||
[2] *SCREEN = plus::return#1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[3] return
|
||||
to:@return
|
||||
|
||||
__bank(bank) char plus(char a , char b)
|
||||
plus: scope:[plus] from main
|
||||
[4] phi()
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
[5] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
void main()
|
||||
__bank(bank) char plus(char a , char b)
|
||||
char plus::a
|
||||
char plus::b
|
||||
char plus::return
|
||||
|
||||
Initial phi equivalence classes
|
||||
Complete equivalence classes
|
||||
Warning! Unknown fragment for statement [1] call plus
|
||||
Missing ASM fragment Fragment not found call_far_cx16_stage_prepare. Attempted variations call_far_cx16_stage_prepare
|
||||
D:\Users\svenv\OneDrive\Documents\GitHub\kickc\src\test\kc\procedure-callingconvention-phi-bank-3.c:10:17:
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Potential register analysis [1] call plus missing fragment Fragment not found call_far_cx16_stage_prepare. Attempted variations call_far_cx16_stage_prepare allocation:
|
||||
MISSING FRAGMENTS
|
||||
Fragment not found call_far_cx16_stage_prepare. Attempted variations call_far_cx16_stage_prepare
|
||||
Statement [1] call plus [ ] ( [ ] { } ) always clobbers reg byte a reg byte x reg byte y
|
||||
Statement [2] *SCREEN = plus::return#1 [ ] ( [ ] { } ) always clobbers reg byte a
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main]
|
||||
Uplift Scope [plus]
|
||||
Uplift Scope []
|
||||
|
||||
Warning! Unknown fragment for statement [1] call plus
|
||||
Missing ASM fragment Fragment not found call_far_cx16_stage_prepare. Attempted variations call_far_cx16_stage_prepare
|
||||
D:\Users\svenv\OneDrive\Documents\GitHub\kickc\src\test\kc\procedure-callingconvention-phi-bank-3.c:10:17:
|
||||
Uplifting [main] best 54 combination
|
||||
Warning! Unknown fragment for statement [1] call plus
|
||||
Missing ASM fragment Fragment not found call_far_cx16_stage_prepare. Attempted variations call_far_cx16_stage_prepare
|
||||
D:\Users\svenv\OneDrive\Documents\GitHub\kickc\src\test\kc\procedure-callingconvention-phi-bank-3.c:10:17:
|
||||
Uplifting [plus] best 54 combination
|
||||
Warning! Unknown fragment for statement [1] call plus
|
||||
Missing ASM fragment Fragment not found call_far_cx16_stage_prepare. Attempted variations call_far_cx16_stage_prepare
|
||||
D:\Users\svenv\OneDrive\Documents\GitHub\kickc\src\test\kc\procedure-callingconvention-phi-bank-3.c:10:17:
|
||||
Uplifting [] best 54 combination
|
||||
Warning! Unknown fragment for statement [1] call plus
|
||||
Missing ASM fragment Fragment not found call_far_cx16_stage_prepare. Attempted variations call_far_cx16_stage_prepare
|
||||
D:\Users\svenv\OneDrive\Documents\GitHub\kickc\src\test\kc\procedure-callingconvention-phi-bank-3.c:10:17:
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Test a far call procedure with a calling convention sp
|
||||
// Upstart
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
|
||||
// Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
// main
|
||||
main: {
|
||||
// [1] call plus
|
||||
// [4] phi from main to plus [phi:main->plus]
|
||||
plus_from_main:
|
||||
.assert "Missing ASM fragment Fragment not found call_far_cx16_stage_prepare. Attempted variations call_far_cx16_stage_prepare ", 0, 1
|
||||
jmp __b1
|
||||
// main::@1
|
||||
__b1:
|
||||
// [2] *SCREEN = plus::return#1 -- _deref_pbuc1=vbuc2
|
||||
lda #plus.return
|
||||
sta SCREEN
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [3] return
|
||||
rts
|
||||
}
|
||||
// plus
|
||||
// char plus(char a, char b)
|
||||
plus: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
.label return = a+b
|
||||
jmp __breturn
|
||||
// plus::@return
|
||||
__breturn:
|
||||
// [5] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction plus_from_main:
|
||||
Removing instruction __b1:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
void main()
|
||||
__bank(bank) char plus(char a , char b)
|
||||
char plus::a
|
||||
__constant char plus::a#0 = '0' // a
|
||||
char plus::b
|
||||
__constant char plus::b#0 = 7 // b
|
||||
char plus::return
|
||||
__constant char plus::return#1 = plus::a#0+plus::b#0 // return
|
||||
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 18
|
||||
|
||||
// File Comments
|
||||
// Test a far call procedure with a calling convention sp
|
||||
// Upstart
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
|
||||
// Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
// main
|
||||
main: {
|
||||
// plus('0', 7)
|
||||
// [1] call plus
|
||||
// [4] phi from main to plus [phi:main->plus]
|
||||
.assert "Missing ASM fragment Fragment not found call_far_cx16_stage_prepare. Attempted variations call_far_cx16_stage_prepare ", 0, 1
|
||||
// main::@1
|
||||
// SCREEN[0] = plus('0', 7)
|
||||
// [2] *SCREEN = plus::return#1 -- _deref_pbuc1=vbuc2
|
||||
lda #plus.return
|
||||
sta SCREEN
|
||||
// main::@return
|
||||
// }
|
||||
// [3] return
|
||||
rts
|
||||
}
|
||||
// plus
|
||||
// char plus(char a, char b)
|
||||
plus: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
.label return = a+b
|
||||
// plus::@return
|
||||
// [5] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
10
src/test/ref/procedure-callingconvention-phi-bank-3.sym
Normal file
10
src/test/ref/procedure-callingconvention-phi-bank-3.sym
Normal file
@ -0,0 +1,10 @@
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
void main()
|
||||
__bank(bank) char plus(char a , char b)
|
||||
char plus::a
|
||||
__constant char plus::a#0 = '0' // a
|
||||
char plus::b
|
||||
__constant char plus::b#0 = 7 // b
|
||||
char plus::return
|
||||
__constant char plus::return#1 = plus::a#0+plus::b#0 // return
|
||||
|
28
src/test/ref/procedure-callingconvention-phi-bank-4.asm
Normal file
28
src/test/ref/procedure-callingconvention-phi-bank-4.asm
Normal file
@ -0,0 +1,28 @@
|
||||
// Test a far call procedure with a calling convention phi
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
main: {
|
||||
// plus('0', 7)
|
||||
jsr plus
|
||||
// SCREEN[0] = plus('0', 7)
|
||||
lda #plus.return
|
||||
sta SCREEN
|
||||
// }
|
||||
rts
|
||||
}
|
||||
// char plus(char a, char b)
|
||||
plus: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
.label return = a+b
|
||||
rts
|
||||
}
|
20
src/test/ref/procedure-callingconvention-phi-bank-4.cfg
Normal file
20
src/test/ref/procedure-callingconvention-phi-bank-4.cfg
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
__bank(bank) void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
[1] call plus
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main
|
||||
[2] *SCREEN = plus::return#0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[3] return
|
||||
to:@return
|
||||
|
||||
__bank(bank) char plus(char a , char b)
|
||||
plus: scope:[plus] from main
|
||||
[4] phi()
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
[5] return
|
||||
to:@return
|
275
src/test/ref/procedure-callingconvention-phi-bank-4.log
Normal file
275
src/test/ref/procedure-callingconvention-phi-bank-4.log
Normal file
@ -0,0 +1,275 @@
|
||||
Loading link script "procedure-callingconvention-phi-bank.ld"
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
__bank(bank) char plus(char a , char b)
|
||||
plus: scope:[plus] from main
|
||||
plus::b#1 = phi( main/plus::b#0 )
|
||||
plus::a#1 = phi( main/plus::a#0 )
|
||||
plus::$0 = plus::a#1 + plus::b#1
|
||||
plus::return#0 = plus::$0
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
plus::return#3 = phi( plus/plus::return#0 )
|
||||
plus::return#1 = plus::return#3
|
||||
return
|
||||
to:@return
|
||||
|
||||
__bank(bank) void main()
|
||||
main: scope:[main] from __start
|
||||
plus::a#0 = '0'
|
||||
plus::b#0 = 7
|
||||
call plus
|
||||
plus::return#2 = plus::return#1
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main
|
||||
plus::return#4 = phi( main/plus::return#2 )
|
||||
main::$0 = plus::return#4
|
||||
SCREEN[0] = main::$0
|
||||
to:main::@return
|
||||
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
|
||||
__constant char * const SCREEN = (char *)$400
|
||||
void __start()
|
||||
__bank(bank) void main()
|
||||
char main::$0
|
||||
__bank(bank) char plus(char a , char b)
|
||||
char plus::$0
|
||||
char plus::a
|
||||
char plus::a#0
|
||||
char plus::a#1
|
||||
char plus::b
|
||||
char plus::b#0
|
||||
char plus::b#1
|
||||
char plus::return
|
||||
char plus::return#0
|
||||
char plus::return#1
|
||||
char plus::return#2
|
||||
char plus::return#3
|
||||
char plus::return#4
|
||||
|
||||
Adding number conversion cast (unumber) 7 in plus::b#0 = 7
|
||||
Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Inlining cast plus::b#0 = (unumber)7
|
||||
Successful SSA optimization Pass2InlineCast
|
||||
Simplifying constant pointer cast (char *) 1024
|
||||
Simplifying constant integer cast 7
|
||||
Simplifying constant integer cast 0
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (char) 7
|
||||
Finalized unsigned number type (char) 0
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Alias plus::return#0 = plus::$0 plus::return#3 plus::return#1
|
||||
Alias plus::return#2 = plus::return#4
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Identical Phi Values plus::a#1 plus::a#0
|
||||
Identical Phi Values plus::b#1 plus::b#0
|
||||
Successful SSA optimization Pass2IdenticalPhiElimination
|
||||
Constant plus::a#0 = '0'
|
||||
Constant plus::b#0 = 7
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Simplifying expression containing zero SCREEN in [8] SCREEN[0] = main::$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
|
||||
Constant right-side identified [0] plus::return#0 = plus::a#0 + plus::b#0
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant plus::return#0 = plus::a#0+plus::b#0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Constant plus::return#2 = plus::return#0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Constant main::$0 = plus::return#2
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Inlining constant with different constant siblings plus::return#2
|
||||
Constant inlined plus::return#2 = plus::return#0
|
||||
Constant inlined main::$0 = plus::return#0
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Adding NOP phi() at start of main
|
||||
Adding NOP phi() at start of plus
|
||||
CALL GRAPH
|
||||
Calls in [main] to plus:1
|
||||
|
||||
Created 0 initial phi equivalence classes
|
||||
Coalesced down to 0 phi equivalence classes
|
||||
Adding NOP phi() at start of main
|
||||
Adding NOP phi() at start of plus
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
|
||||
__bank(bank) void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
[1] call plus
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main
|
||||
[2] *SCREEN = plus::return#0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[3] return
|
||||
to:@return
|
||||
|
||||
__bank(bank) char plus(char a , char b)
|
||||
plus: scope:[plus] from main
|
||||
[4] phi()
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
[5] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
__bank(bank) void main()
|
||||
__bank(bank) char plus(char a , char b)
|
||||
char plus::a
|
||||
char plus::b
|
||||
char plus::return
|
||||
|
||||
Initial phi equivalence classes
|
||||
Complete equivalence classes
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [2] *SCREEN = plus::return#0 [ ] ( [ ] { } ) always clobbers reg byte a
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [plus]
|
||||
Uplift Scope [main]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [plus] best 60 combination
|
||||
Uplifting [main] best 60 combination
|
||||
Uplifting [] best 60 combination
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Test a far call procedure with a calling convention phi
|
||||
// Upstart
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
|
||||
// Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
// main
|
||||
main: {
|
||||
// [1] call plus
|
||||
// [4] phi from main to plus [phi:main->plus]
|
||||
plus_from_main:
|
||||
jsr plus
|
||||
jmp __b1
|
||||
// main::@1
|
||||
__b1:
|
||||
// [2] *SCREEN = plus::return#0 -- _deref_pbuc1=vbuc2
|
||||
lda #plus.return
|
||||
sta SCREEN
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [3] return
|
||||
rts
|
||||
}
|
||||
// plus
|
||||
// char plus(char a, char b)
|
||||
plus: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
.label return = a+b
|
||||
jmp __breturn
|
||||
// plus::@return
|
||||
__breturn:
|
||||
// [5] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction plus_from_main:
|
||||
Removing instruction __b1:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
__bank(bank) void main()
|
||||
__bank(bank) char plus(char a , char b)
|
||||
char plus::a
|
||||
__constant char plus::a#0 = '0' // a
|
||||
char plus::b
|
||||
__constant char plus::b#0 = 7 // b
|
||||
char plus::return
|
||||
__constant char plus::return#0 = plus::a#0+plus::b#0 // return
|
||||
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 24
|
||||
|
||||
// File Comments
|
||||
// Test a far call procedure with a calling convention phi
|
||||
// Upstart
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
|
||||
// Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
// main
|
||||
main: {
|
||||
// plus('0', 7)
|
||||
// [1] call plus
|
||||
// [4] phi from main to plus [phi:main->plus]
|
||||
jsr plus
|
||||
// main::@1
|
||||
// SCREEN[0] = plus('0', 7)
|
||||
// [2] *SCREEN = plus::return#0 -- _deref_pbuc1=vbuc2
|
||||
lda #plus.return
|
||||
sta SCREEN
|
||||
// main::@return
|
||||
// }
|
||||
// [3] return
|
||||
rts
|
||||
}
|
||||
// plus
|
||||
// char plus(char a, char b)
|
||||
plus: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
.label return = a+b
|
||||
// plus::@return
|
||||
// [5] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
10
src/test/ref/procedure-callingconvention-phi-bank-4.sym
Normal file
10
src/test/ref/procedure-callingconvention-phi-bank-4.sym
Normal file
@ -0,0 +1,10 @@
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
__bank(bank) void main()
|
||||
__bank(bank) char plus(char a , char b)
|
||||
char plus::a
|
||||
__constant char plus::a#0 = '0' // a
|
||||
char plus::b
|
||||
__constant char plus::b#0 = 7 // b
|
||||
char plus::return
|
||||
__constant char plus::return#0 = plus::a#0+plus::b#0 // return
|
||||
|
268
src/test/ref/procedure-callingconvention-phi-bank-5.asm
Normal file
268
src/test/ref/procedure-callingconvention-phi-bank-5.asm
Normal file
@ -0,0 +1,268 @@
|
||||
// Test a far call procedure with a calling convention phi
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
|
||||
.label SCREEN = $400
|
||||
.segment Code
|
||||
main: {
|
||||
// func_bank1_a('0', 7)
|
||||
lda #7
|
||||
ldx #'0'
|
||||
jsr $ff6e
|
||||
.byte <func_bank1_a
|
||||
.byte >func_bank1_a
|
||||
.byte 1
|
||||
// func_bank1_a('0', 7)
|
||||
// SCREEN[0] = func_bank1_a('0', 7)
|
||||
// far call
|
||||
sta SCREEN
|
||||
// func_bank1_b('0', 7)
|
||||
lda #7
|
||||
ldx #'0'
|
||||
jsr func_bank1_b
|
||||
// func_bank1_b('0', 7)
|
||||
// SCREEN[0] = func_bank1_b('0', 7)
|
||||
// far call
|
||||
sta SCREEN
|
||||
// func_bank1_c('0', 7)
|
||||
jsr $ff6e
|
||||
.byte <func_bank1_c
|
||||
.byte >func_bank1_c
|
||||
.byte 1
|
||||
// func_bank1_c('0', 7)
|
||||
// SCREEN[0] = func_bank1_c('0', 7)
|
||||
// far call
|
||||
sta SCREEN
|
||||
// func_bank1_d('0', 7)
|
||||
jsr $ff6e
|
||||
.byte <func_bank1_d
|
||||
.byte >func_bank1_d
|
||||
.byte 1
|
||||
// func_bank1_d('0', 7)
|
||||
// SCREEN[0] = func_bank1_d('0', 7)
|
||||
// far call
|
||||
sta SCREEN
|
||||
// func_bank1_e('0', 7)
|
||||
jsr func_bank1_e
|
||||
// func_bank1_e('0', 7)
|
||||
// SCREEN[0] = func_bank1_e('0', 7)
|
||||
// near call
|
||||
sta SCREEN
|
||||
// func_bank1_f('0', 7)
|
||||
jsr func_bank1_f
|
||||
// func_bank1_f('0', 7)
|
||||
// SCREEN[0] = func_bank1_f('0', 7)
|
||||
// near call
|
||||
sta SCREEN
|
||||
// func_bank2_a('0', 7)
|
||||
lda #7
|
||||
ldx #'0'
|
||||
jsr $ff6e
|
||||
.byte <func_bank2_a
|
||||
.byte >func_bank2_a
|
||||
.byte 2
|
||||
// func_bank2_a('0', 7)
|
||||
// SCREEN[0] = func_bank2_a('0', 7)
|
||||
// far call
|
||||
sta SCREEN
|
||||
// func_bank2_b('0', 7)
|
||||
lda #7
|
||||
ldx #'0'
|
||||
jsr func_bank2_b
|
||||
// func_bank2_b('0', 7)
|
||||
// SCREEN[0] = func_bank2_b('0', 7)
|
||||
// far call
|
||||
sta SCREEN
|
||||
// func_bank2_c('0', 7)
|
||||
jsr $ff6e
|
||||
.byte <func_bank2_c
|
||||
.byte >func_bank2_c
|
||||
.byte 2
|
||||
// func_bank2_c('0', 7)
|
||||
// SCREEN[0] = func_bank2_c('0', 7)
|
||||
// far call
|
||||
sta SCREEN
|
||||
// func_bank2_d('0', 7)
|
||||
jsr $ff6e
|
||||
.byte <func_bank2_d
|
||||
.byte >func_bank2_d
|
||||
.byte 2
|
||||
// func_bank2_d('0', 7)
|
||||
// SCREEN[0] = func_bank2_d('0', 7)
|
||||
// far call
|
||||
sta SCREEN
|
||||
// func_bank2_e('0', 7)
|
||||
jsr $ff6e
|
||||
.byte <func_bank2_e
|
||||
.byte >func_bank2_e
|
||||
.byte 2
|
||||
// func_bank2_e('0', 7)
|
||||
// SCREEN[0] = func_bank2_e('0', 7)
|
||||
// far call
|
||||
sta SCREEN
|
||||
// func_bank2_f('0', 7)
|
||||
jsr $ff6e
|
||||
.byte <func_bank2_f
|
||||
.byte >func_bank2_f
|
||||
.byte 2
|
||||
// func_bank2_f('0', 7)
|
||||
// SCREEN[0] = func_bank2_f('0', 7)
|
||||
// far call
|
||||
sta SCREEN
|
||||
// }
|
||||
rts
|
||||
}
|
||||
.segment stage
|
||||
// __register(A) char func_bank1_a(__register(X) char a, __register(A) char b)
|
||||
func_bank1_a: {
|
||||
// a+b
|
||||
stx.z $ff
|
||||
clc
|
||||
adc.z $ff
|
||||
// }
|
||||
rts
|
||||
}
|
||||
.segment platform
|
||||
// __register(A) char func_bank1_b(__register(X) char a, __register(A) char b)
|
||||
func_bank1_b: {
|
||||
// a+b
|
||||
stx.z $ff
|
||||
clc
|
||||
adc.z $ff
|
||||
// }
|
||||
rts
|
||||
}
|
||||
.segment stage
|
||||
// __register(A) char func_bank1_c(char a, char b)
|
||||
func_bank1_c: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
// func_bank1_a(a,b)
|
||||
lda #b
|
||||
ldx #a
|
||||
jsr func_bank1_a
|
||||
// func_bank1_a(a,b)
|
||||
// }
|
||||
rts
|
||||
}
|
||||
// __register(A) char func_bank1_d(char a, char b)
|
||||
func_bank1_d: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
// func_bank2_a(a,b)
|
||||
lda #b
|
||||
ldx #a
|
||||
jsr $ff6e
|
||||
.byte <func_bank2_a
|
||||
.byte >func_bank2_a
|
||||
.byte 2
|
||||
// func_bank2_a(a,b)
|
||||
// }
|
||||
rts
|
||||
}
|
||||
.segment platform
|
||||
// __register(A) char func_bank1_e(char a, char b)
|
||||
func_bank1_e: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
// func_bank1_a(a,b)
|
||||
lda #b
|
||||
ldx #a
|
||||
jsr $ff6e
|
||||
.byte <func_bank1_a
|
||||
.byte >func_bank1_a
|
||||
.byte 1
|
||||
// func_bank1_a(a,b)
|
||||
// }
|
||||
rts
|
||||
}
|
||||
// __register(A) char func_bank1_f(char a, char b)
|
||||
func_bank1_f: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
// func_bank2_a(a,b)
|
||||
lda #b
|
||||
ldx #a
|
||||
jsr $ff6e
|
||||
.byte <func_bank2_a
|
||||
.byte >func_bank2_a
|
||||
.byte 2
|
||||
// func_bank2_a(a,b)
|
||||
// }
|
||||
rts
|
||||
}
|
||||
// __register(A) char func_bank2_a(__register(X) char a, __register(A) char b)
|
||||
func_bank2_a: {
|
||||
// a+b
|
||||
stx.z $ff
|
||||
clc
|
||||
adc.z $ff
|
||||
// }
|
||||
rts
|
||||
}
|
||||
// __register(A) char func_bank2_b(__register(X) char a, __register(A) char b)
|
||||
func_bank2_b: {
|
||||
// a+b
|
||||
stx.z $ff
|
||||
clc
|
||||
adc.z $ff
|
||||
// }
|
||||
rts
|
||||
}
|
||||
// __register(A) char func_bank2_c(char a, char b)
|
||||
func_bank2_c: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
// func_bank1_a(a,b)
|
||||
lda #b
|
||||
ldx #a
|
||||
jsr $ff6e
|
||||
.byte <func_bank1_a
|
||||
.byte >func_bank1_a
|
||||
.byte 1
|
||||
// func_bank1_a(a,b)
|
||||
// }
|
||||
rts
|
||||
}
|
||||
// __register(A) char func_bank2_d(char a, char b)
|
||||
func_bank2_d: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
// func_bank2_a(a,b)
|
||||
lda #b
|
||||
ldx #a
|
||||
jsr func_bank2_a
|
||||
// func_bank2_a(a,b)
|
||||
// }
|
||||
rts
|
||||
}
|
||||
// __register(A) char func_bank2_e(char a, char b)
|
||||
func_bank2_e: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
// func_bank2_b(a,b)
|
||||
lda #b
|
||||
ldx #a
|
||||
jsr func_bank2_b
|
||||
// func_bank2_b(a,b)
|
||||
// }
|
||||
rts
|
||||
}
|
||||
// __register(A) char func_bank2_f(char a, char b)
|
||||
func_bank2_f: {
|
||||
.const a = '0'
|
||||
.const b = 7
|
||||
// func_bank1_b(a,b)
|
||||
lda #b
|
||||
ldx #a
|
||||
jsr func_bank1_b
|
||||
// func_bank1_b(a,b)
|
||||
// }
|
||||
rts
|
||||
}
|
224
src/test/ref/procedure-callingconvention-phi-bank-5.cfg
Normal file
224
src/test/ref/procedure-callingconvention-phi-bank-5.cfg
Normal file
@ -0,0 +1,224 @@
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
[1] call func_bank1_a
|
||||
[2] func_bank1_a::return#10 = func_bank1_a::return#0
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main
|
||||
[3] main::$0 = func_bank1_a::return#10
|
||||
[4] *SCREEN = main::$0
|
||||
[5] call func_bank1_b
|
||||
[6] func_bank1_b::return#3 = func_bank1_b::return#1
|
||||
to:main::@2
|
||||
main::@2: scope:[main] from main::@1
|
||||
[7] main::$1 = func_bank1_b::return#3
|
||||
[8] *SCREEN = main::$1
|
||||
[9] call func_bank1_c
|
||||
[10] func_bank1_c::return#2 = func_bank1_c::return#0
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@2
|
||||
[11] main::$2 = func_bank1_c::return#2
|
||||
[12] *SCREEN = main::$2
|
||||
[13] call func_bank1_d
|
||||
[14] func_bank1_d::return#2 = func_bank1_d::return#0
|
||||
to:main::@4
|
||||
main::@4: scope:[main] from main::@3
|
||||
[15] main::$3 = func_bank1_d::return#2
|
||||
[16] *SCREEN = main::$3
|
||||
[17] call func_bank1_e
|
||||
[18] func_bank1_e::return#2 = func_bank1_e::return#0
|
||||
to:main::@5
|
||||
main::@5: scope:[main] from main::@4
|
||||
[19] main::$4 = func_bank1_e::return#2
|
||||
[20] *SCREEN = main::$4
|
||||
[21] call func_bank1_f
|
||||
[22] func_bank1_f::return#2 = func_bank1_f::return#0
|
||||
to:main::@6
|
||||
main::@6: scope:[main] from main::@5
|
||||
[23] main::$5 = func_bank1_f::return#2
|
||||
[24] *SCREEN = main::$5
|
||||
[25] call func_bank2_a
|
||||
[26] func_bank2_a::return#10 = func_bank2_a::return#1
|
||||
to:main::@7
|
||||
main::@7: scope:[main] from main::@6
|
||||
[27] main::$6 = func_bank2_a::return#10
|
||||
[28] *SCREEN = main::$6
|
||||
[29] call func_bank2_b
|
||||
[30] func_bank2_b::return#3 = func_bank2_b::return#1
|
||||
to:main::@8
|
||||
main::@8: scope:[main] from main::@7
|
||||
[31] main::$7 = func_bank2_b::return#3
|
||||
[32] *SCREEN = main::$7
|
||||
[33] call func_bank2_c
|
||||
[34] func_bank2_c::return#2 = func_bank2_c::return#0
|
||||
to:main::@9
|
||||
main::@9: scope:[main] from main::@8
|
||||
[35] main::$8 = func_bank2_c::return#2
|
||||
[36] *SCREEN = main::$8
|
||||
[37] call func_bank2_d
|
||||
[38] func_bank2_d::return#2 = func_bank2_d::return#0
|
||||
to:main::@10
|
||||
main::@10: scope:[main] from main::@9
|
||||
[39] main::$9 = func_bank2_d::return#2
|
||||
[40] *SCREEN = main::$9
|
||||
[41] call func_bank2_e
|
||||
[42] func_bank2_e::return#2 = func_bank2_e::return#0
|
||||
to:main::@11
|
||||
main::@11: scope:[main] from main::@10
|
||||
[43] main::$10 = func_bank2_e::return#2
|
||||
[44] *SCREEN = main::$10
|
||||
[45] call func_bank2_f
|
||||
[46] func_bank2_f::return#2 = func_bank2_f::return#0
|
||||
to:main::@12
|
||||
main::@12: scope:[main] from main::@11
|
||||
[47] main::$11 = func_bank2_f::return#2
|
||||
[48] *SCREEN = main::$11
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@12
|
||||
[49] return
|
||||
to:@return
|
||||
|
||||
__bank(bank) char func_bank1_a(char a , char b)
|
||||
func_bank1_a: scope:[func_bank1_a] from func_bank1_c func_bank1_e func_bank2_c main
|
||||
[50] func_bank1_a::b#4 = phi( func_bank1_c/func_bank1_c::b#0, func_bank1_e/func_bank1_e::b#0, func_bank2_c/func_bank2_c::b#0, main/7 )
|
||||
[50] func_bank1_a::a#4 = phi( func_bank1_c/func_bank1_c::a#0, func_bank1_e/func_bank1_e::a#0, func_bank2_c/func_bank2_c::a#0, main/'0' )
|
||||
[51] func_bank1_a::return#0 = func_bank1_a::a#4 + func_bank1_a::b#4
|
||||
to:func_bank1_a::@return
|
||||
func_bank1_a::@return: scope:[func_bank1_a] from func_bank1_a
|
||||
[52] return
|
||||
to:@return
|
||||
|
||||
char func_bank1_b(char a , char b)
|
||||
func_bank1_b: scope:[func_bank1_b] from func_bank2_f main::@1
|
||||
[53] func_bank1_b::b#2 = phi( func_bank2_f/func_bank2_f::b#0, main::@1/7 )
|
||||
[53] func_bank1_b::a#2 = phi( func_bank2_f/func_bank2_f::a#0, main::@1/'0' )
|
||||
[54] func_bank1_b::return#1 = func_bank1_b::a#2 + func_bank1_b::b#2
|
||||
to:func_bank1_b::@return
|
||||
func_bank1_b::@return: scope:[func_bank1_b] from func_bank1_b
|
||||
[55] return
|
||||
to:@return
|
||||
|
||||
__bank(bank) char func_bank1_c(char a , char b)
|
||||
func_bank1_c: scope:[func_bank1_c] from main::@2
|
||||
[56] phi()
|
||||
[57] call func_bank1_a
|
||||
[58] func_bank1_a::return#2 = func_bank1_a::return#0
|
||||
to:func_bank1_c::@1
|
||||
func_bank1_c::@1: scope:[func_bank1_c] from func_bank1_c
|
||||
[59] func_bank1_c::return#0 = func_bank1_a::return#2
|
||||
to:func_bank1_c::@return
|
||||
func_bank1_c::@return: scope:[func_bank1_c] from func_bank1_c::@1
|
||||
[60] return
|
||||
to:@return
|
||||
|
||||
__bank(bank) char func_bank1_d(char a , char b)
|
||||
func_bank1_d: scope:[func_bank1_d] from main::@3
|
||||
[61] phi()
|
||||
[62] call func_bank2_a
|
||||
[63] func_bank2_a::return#0 = func_bank2_a::return#1
|
||||
to:func_bank1_d::@1
|
||||
func_bank1_d::@1: scope:[func_bank1_d] from func_bank1_d
|
||||
[64] func_bank1_d::return#0 = func_bank2_a::return#0
|
||||
to:func_bank1_d::@return
|
||||
func_bank1_d::@return: scope:[func_bank1_d] from func_bank1_d::@1
|
||||
[65] return
|
||||
to:@return
|
||||
|
||||
char func_bank1_e(char a , char b)
|
||||
func_bank1_e: scope:[func_bank1_e] from main::@4
|
||||
[66] phi()
|
||||
[67] call func_bank1_a
|
||||
[68] func_bank1_a::return#4 = func_bank1_a::return#0
|
||||
to:func_bank1_e::@1
|
||||
func_bank1_e::@1: scope:[func_bank1_e] from func_bank1_e
|
||||
[69] func_bank1_e::return#0 = func_bank1_a::return#4
|
||||
to:func_bank1_e::@return
|
||||
func_bank1_e::@return: scope:[func_bank1_e] from func_bank1_e::@1
|
||||
[70] return
|
||||
to:@return
|
||||
|
||||
char func_bank1_f(char a , char b)
|
||||
func_bank1_f: scope:[func_bank1_f] from main::@5
|
||||
[71] phi()
|
||||
[72] call func_bank2_a
|
||||
[73] func_bank2_a::return#4 = func_bank2_a::return#1
|
||||
to:func_bank1_f::@1
|
||||
func_bank1_f::@1: scope:[func_bank1_f] from func_bank1_f
|
||||
[74] func_bank1_f::return#0 = func_bank2_a::return#4
|
||||
to:func_bank1_f::@return
|
||||
func_bank1_f::@return: scope:[func_bank1_f] from func_bank1_f::@1
|
||||
[75] return
|
||||
to:@return
|
||||
|
||||
__bank(bank) char func_bank2_a(char a , char b)
|
||||
func_bank2_a: scope:[func_bank2_a] from func_bank1_d func_bank1_f func_bank2_d main::@6
|
||||
[76] func_bank2_a::b#4 = phi( func_bank1_d/func_bank1_d::b#0, func_bank1_f/func_bank1_f::b#0, func_bank2_d/func_bank2_d::b#0, main::@6/7 )
|
||||
[76] func_bank2_a::a#4 = phi( func_bank1_d/func_bank1_d::a#0, func_bank1_f/func_bank1_f::a#0, func_bank2_d/func_bank2_d::a#0, main::@6/'0' )
|
||||
[77] func_bank2_a::return#1 = func_bank2_a::a#4 + func_bank2_a::b#4
|
||||
to:func_bank2_a::@return
|
||||
func_bank2_a::@return: scope:[func_bank2_a] from func_bank2_a
|
||||
[78] return
|
||||
to:@return
|
||||
|
||||
char func_bank2_b(char a , char b)
|
||||
func_bank2_b: scope:[func_bank2_b] from func_bank2_e main::@7
|
||||
[79] func_bank2_b::b#2 = phi( func_bank2_e/func_bank2_e::b#0, main::@7/7 )
|
||||
[79] func_bank2_b::a#2 = phi( func_bank2_e/func_bank2_e::a#0, main::@7/'0' )
|
||||
[80] func_bank2_b::return#1 = func_bank2_b::a#2 + func_bank2_b::b#2
|
||||
to:func_bank2_b::@return
|
||||
func_bank2_b::@return: scope:[func_bank2_b] from func_bank2_b
|
||||
[81] return
|
||||
to:@return
|
||||
|
||||
__bank(bank) char func_bank2_c(char a , char b)
|
||||
func_bank2_c: scope:[func_bank2_c] from main::@8
|
||||
[82] phi()
|
||||
[83] call func_bank1_a
|
||||
[84] func_bank1_a::return#3 = func_bank1_a::return#0
|
||||
to:func_bank2_c::@1
|
||||
func_bank2_c::@1: scope:[func_bank2_c] from func_bank2_c
|
||||
[85] func_bank2_c::return#0 = func_bank1_a::return#3
|
||||
to:func_bank2_c::@return
|
||||
func_bank2_c::@return: scope:[func_bank2_c] from func_bank2_c::@1
|
||||
[86] return
|
||||
to:@return
|
||||
|
||||
__bank(bank) char func_bank2_d(char a , char b)
|
||||
func_bank2_d: scope:[func_bank2_d] from main::@9
|
||||
[87] phi()
|
||||
[88] call func_bank2_a
|
||||
[89] func_bank2_a::return#3 = func_bank2_a::return#1
|
||||
to:func_bank2_d::@1
|
||||
func_bank2_d::@1: scope:[func_bank2_d] from func_bank2_d
|
||||
[90] func_bank2_d::return#0 = func_bank2_a::return#3
|
||||
to:func_bank2_d::@return
|
||||
func_bank2_d::@return: scope:[func_bank2_d] from func_bank2_d::@1
|
||||
[91] return
|
||||
to:@return
|
||||
|
||||
__bank(bank) char func_bank2_e(char a , char b)
|
||||
func_bank2_e: scope:[func_bank2_e] from main::@10
|
||||
[92] phi()
|
||||
[93] call func_bank2_b
|
||||
[94] func_bank2_b::return#0 = func_bank2_b::return#1
|
||||
to:func_bank2_e::@1
|
||||
func_bank2_e::@1: scope:[func_bank2_e] from func_bank2_e
|
||||
[95] func_bank2_e::return#0 = func_bank2_b::return#0
|
||||
to:func_bank2_e::@return
|
||||
func_bank2_e::@return: scope:[func_bank2_e] from func_bank2_e::@1
|
||||
[96] return
|
||||
to:@return
|
||||
|
||||
__bank(bank) char func_bank2_f(char a , char b)
|
||||
func_bank2_f: scope:[func_bank2_f] from main::@11
|
||||
[97] phi()
|
||||
[98] call func_bank1_b
|
||||
[99] func_bank1_b::return#0 = func_bank1_b::return#1
|
||||
to:func_bank2_f::@1
|
||||
func_bank2_f::@1: scope:[func_bank2_f] from func_bank2_f
|
||||
[100] func_bank2_f::return#0 = func_bank1_b::return#0
|
||||
to:func_bank2_f::@return
|
||||
func_bank2_f::@return: scope:[func_bank2_f] from func_bank2_f::@1
|
||||
[101] return
|
||||
to:@return
|
2642
src/test/ref/procedure-callingconvention-phi-bank-5.log
Normal file
2642
src/test/ref/procedure-callingconvention-phi-bank-5.log
Normal file
File diff suppressed because it is too large
Load Diff
171
src/test/ref/procedure-callingconvention-phi-bank-5.sym
Normal file
171
src/test/ref/procedure-callingconvention-phi-bank-5.sym
Normal file
@ -0,0 +1,171 @@
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
__bank(bank) char func_bank1_a(char a , char b)
|
||||
char func_bank1_a::a
|
||||
char func_bank1_a::a#4 // reg byte x 101.0
|
||||
char func_bank1_a::b
|
||||
char func_bank1_a::b#4 // reg byte a 101.0
|
||||
char func_bank1_a::return
|
||||
char func_bank1_a::return#0 // reg byte a 22.66666666666666
|
||||
char func_bank1_a::return#10 // reg byte a 4.0
|
||||
char func_bank1_a::return#2 // reg byte a 22.0
|
||||
char func_bank1_a::return#3 // reg byte a 22.0
|
||||
char func_bank1_a::return#4 // reg byte a 22.0
|
||||
char func_bank1_b(char a , char b)
|
||||
char func_bank1_b::a
|
||||
char func_bank1_b::a#2 // reg byte x 101.0
|
||||
char func_bank1_b::b
|
||||
char func_bank1_b::b#2 // reg byte a 101.0
|
||||
char func_bank1_b::return
|
||||
char func_bank1_b::return#0 // reg byte a 22.0
|
||||
char func_bank1_b::return#1 // reg byte a 28.5
|
||||
char func_bank1_b::return#3 // reg byte a 4.0
|
||||
__bank(bank) char func_bank1_c(char a , char b)
|
||||
char func_bank1_c::a
|
||||
__constant char func_bank1_c::a#0 = '0' // a
|
||||
char func_bank1_c::b
|
||||
__constant char func_bank1_c::b#0 = 7 // b
|
||||
char func_bank1_c::return
|
||||
char func_bank1_c::return#0 // reg byte a 4.333333333333333
|
||||
char func_bank1_c::return#2 // reg byte a 4.0
|
||||
__bank(bank) char func_bank1_d(char a , char b)
|
||||
char func_bank1_d::a
|
||||
__constant char func_bank1_d::a#0 = '0' // a
|
||||
char func_bank1_d::b
|
||||
__constant char func_bank1_d::b#0 = 7 // b
|
||||
char func_bank1_d::return
|
||||
char func_bank1_d::return#0 // reg byte a 4.333333333333333
|
||||
char func_bank1_d::return#2 // reg byte a 4.0
|
||||
char func_bank1_e(char a , char b)
|
||||
char func_bank1_e::a
|
||||
__constant char func_bank1_e::a#0 = '0' // a
|
||||
char func_bank1_e::b
|
||||
__constant char func_bank1_e::b#0 = 7 // b
|
||||
char func_bank1_e::return
|
||||
char func_bank1_e::return#0 // reg byte a 4.333333333333333
|
||||
char func_bank1_e::return#2 // reg byte a 4.0
|
||||
char func_bank1_f(char a , char b)
|
||||
char func_bank1_f::a
|
||||
__constant char func_bank1_f::a#0 = '0' // a
|
||||
char func_bank1_f::b
|
||||
__constant char func_bank1_f::b#0 = 7 // b
|
||||
char func_bank1_f::return
|
||||
char func_bank1_f::return#0 // reg byte a 4.333333333333333
|
||||
char func_bank1_f::return#2 // reg byte a 4.0
|
||||
__bank(bank) char func_bank2_a(char a , char b)
|
||||
char func_bank2_a::a
|
||||
char func_bank2_a::a#4 // reg byte x 101.0
|
||||
char func_bank2_a::b
|
||||
char func_bank2_a::b#4 // reg byte a 101.0
|
||||
char func_bank2_a::return
|
||||
char func_bank2_a::return#0 // reg byte a 22.0
|
||||
char func_bank2_a::return#1 // reg byte a 22.666666666666664
|
||||
char func_bank2_a::return#10 // reg byte a 4.0
|
||||
char func_bank2_a::return#3 // reg byte a 22.0
|
||||
char func_bank2_a::return#4 // reg byte a 22.0
|
||||
char func_bank2_b(char a , char b)
|
||||
char func_bank2_b::a
|
||||
char func_bank2_b::a#2 // reg byte x 101.0
|
||||
char func_bank2_b::b
|
||||
char func_bank2_b::b#2 // reg byte a 101.0
|
||||
char func_bank2_b::return
|
||||
char func_bank2_b::return#0 // reg byte a 22.0
|
||||
char func_bank2_b::return#1 // reg byte a 28.5
|
||||
char func_bank2_b::return#3 // reg byte a 4.0
|
||||
__bank(bank) char func_bank2_c(char a , char b)
|
||||
char func_bank2_c::a
|
||||
__constant char func_bank2_c::a#0 = '0' // a
|
||||
char func_bank2_c::b
|
||||
__constant char func_bank2_c::b#0 = 7 // b
|
||||
char func_bank2_c::return
|
||||
char func_bank2_c::return#0 // reg byte a 4.333333333333333
|
||||
char func_bank2_c::return#2 // reg byte a 4.0
|
||||
__bank(bank) char func_bank2_d(char a , char b)
|
||||
char func_bank2_d::a
|
||||
__constant char func_bank2_d::a#0 = '0' // a
|
||||
char func_bank2_d::b
|
||||
__constant char func_bank2_d::b#0 = 7 // b
|
||||
char func_bank2_d::return
|
||||
char func_bank2_d::return#0 // reg byte a 4.333333333333333
|
||||
char func_bank2_d::return#2 // reg byte a 4.0
|
||||
__bank(bank) char func_bank2_e(char a , char b)
|
||||
char func_bank2_e::a
|
||||
__constant char func_bank2_e::a#0 = '0' // a
|
||||
char func_bank2_e::b
|
||||
__constant char func_bank2_e::b#0 = 7 // b
|
||||
char func_bank2_e::return
|
||||
char func_bank2_e::return#0 // reg byte a 4.333333333333333
|
||||
char func_bank2_e::return#2 // reg byte a 4.0
|
||||
__bank(bank) char func_bank2_f(char a , char b)
|
||||
char func_bank2_f::a
|
||||
__constant char func_bank2_f::a#0 = '0' // a
|
||||
char func_bank2_f::b
|
||||
__constant char func_bank2_f::b#0 = 7 // b
|
||||
char func_bank2_f::return
|
||||
char func_bank2_f::return#0 // reg byte a 4.333333333333333
|
||||
char func_bank2_f::return#2 // reg byte a 4.0
|
||||
void main()
|
||||
char main::$0 // reg byte a 4.0
|
||||
char main::$1 // reg byte a 4.0
|
||||
char main::$10 // reg byte a 4.0
|
||||
char main::$11 // reg byte a 4.0
|
||||
char main::$2 // reg byte a 4.0
|
||||
char main::$3 // reg byte a 4.0
|
||||
char main::$4 // reg byte a 4.0
|
||||
char main::$5 // reg byte a 4.0
|
||||
char main::$6 // reg byte a 4.0
|
||||
char main::$7 // reg byte a 4.0
|
||||
char main::$8 // reg byte a 4.0
|
||||
char main::$9 // reg byte a 4.0
|
||||
|
||||
reg byte x [ func_bank1_a::a#4 ]
|
||||
reg byte a [ func_bank1_a::b#4 ]
|
||||
reg byte x [ func_bank1_b::a#2 ]
|
||||
reg byte a [ func_bank1_b::b#2 ]
|
||||
reg byte x [ func_bank2_a::a#4 ]
|
||||
reg byte a [ func_bank2_a::b#4 ]
|
||||
reg byte x [ func_bank2_b::a#2 ]
|
||||
reg byte a [ func_bank2_b::b#2 ]
|
||||
reg byte a [ func_bank1_a::return#10 ]
|
||||
reg byte a [ main::$0 ]
|
||||
reg byte a [ func_bank1_b::return#3 ]
|
||||
reg byte a [ main::$1 ]
|
||||
reg byte a [ func_bank1_c::return#2 ]
|
||||
reg byte a [ main::$2 ]
|
||||
reg byte a [ func_bank1_d::return#2 ]
|
||||
reg byte a [ main::$3 ]
|
||||
reg byte a [ func_bank1_e::return#2 ]
|
||||
reg byte a [ main::$4 ]
|
||||
reg byte a [ func_bank1_f::return#2 ]
|
||||
reg byte a [ main::$5 ]
|
||||
reg byte a [ func_bank2_a::return#10 ]
|
||||
reg byte a [ main::$6 ]
|
||||
reg byte a [ func_bank2_b::return#3 ]
|
||||
reg byte a [ main::$7 ]
|
||||
reg byte a [ func_bank2_c::return#2 ]
|
||||
reg byte a [ main::$8 ]
|
||||
reg byte a [ func_bank2_d::return#2 ]
|
||||
reg byte a [ main::$9 ]
|
||||
reg byte a [ func_bank2_e::return#2 ]
|
||||
reg byte a [ main::$10 ]
|
||||
reg byte a [ func_bank2_f::return#2 ]
|
||||
reg byte a [ main::$11 ]
|
||||
reg byte a [ func_bank1_a::return#0 ]
|
||||
reg byte a [ func_bank1_b::return#1 ]
|
||||
reg byte a [ func_bank1_a::return#2 ]
|
||||
reg byte a [ func_bank1_c::return#0 ]
|
||||
reg byte a [ func_bank2_a::return#0 ]
|
||||
reg byte a [ func_bank1_d::return#0 ]
|
||||
reg byte a [ func_bank1_a::return#4 ]
|
||||
reg byte a [ func_bank1_e::return#0 ]
|
||||
reg byte a [ func_bank2_a::return#4 ]
|
||||
reg byte a [ func_bank1_f::return#0 ]
|
||||
reg byte a [ func_bank2_a::return#1 ]
|
||||
reg byte a [ func_bank2_b::return#1 ]
|
||||
reg byte a [ func_bank1_a::return#3 ]
|
||||
reg byte a [ func_bank2_c::return#0 ]
|
||||
reg byte a [ func_bank2_a::return#3 ]
|
||||
reg byte a [ func_bank2_d::return#0 ]
|
||||
reg byte a [ func_bank2_b::return#0 ]
|
||||
reg byte a [ func_bank2_e::return#0 ]
|
||||
reg byte a [ func_bank1_b::return#0 ]
|
||||
reg byte a [ func_bank2_f::return#0 ]
|
45
src/test/ref/procedure-callingconvention-stack-bank-0.asm
Normal file
45
src/test/ref/procedure-callingconvention-stack-bank-0.asm
Normal file
@ -0,0 +1,45 @@
|
||||
// Test a procedure with calling convention stack
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
.const STACK_BASE = $103
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
// __register(A) char plus(__zp(2) char a, __register(A) char b)
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 1
|
||||
.const OFFSET_STACK_B = 0
|
||||
.const OFFSET_STACK_RETURN_1 = 1
|
||||
.label a = 2
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_A,x
|
||||
sta.z a
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_B,x
|
||||
// return a+b;
|
||||
clc
|
||||
adc.z a
|
||||
// }
|
||||
tsx
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN_1,x
|
||||
rts
|
||||
}
|
||||
main: {
|
||||
// plus('0', 7)
|
||||
lda #'0'
|
||||
pha
|
||||
lda #7
|
||||
pha
|
||||
jsr plus
|
||||
pla
|
||||
pla
|
||||
// SCREEN[0] = plus('0', 7)
|
||||
sta SCREEN
|
||||
// }
|
||||
rts
|
||||
}
|
24
src/test/ref/procedure-callingconvention-stack-bank-0.cfg
Normal file
24
src/test/ref/procedure-callingconvention-stack-bank-0.cfg
Normal file
@ -0,0 +1,24 @@
|
||||
|
||||
__stackcall char plus(char a , char b)
|
||||
plus: scope:[plus] from
|
||||
[0] plus::a#0 = stackidx(char,plus::OFFSET_STACK_A)
|
||||
[1] plus::b#0 = stackidx(char,plus::OFFSET_STACK_B)
|
||||
[2] plus::return#0 = plus::a#0 + plus::b#0
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
[3] stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#0
|
||||
[4] return
|
||||
to:@return
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[5] stackpush(char) = '0'
|
||||
[6] stackpush(char) = 7
|
||||
[7] callexecute plus
|
||||
sideeffect stackpullpadding(1)
|
||||
[9] main::$0 = stackpull(char)
|
||||
[10] *SCREEN = main::$0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[11] return
|
||||
to:@return
|
350
src/test/ref/procedure-callingconvention-stack-bank-0.log
Normal file
350
src/test/ref/procedure-callingconvention-stack-bank-0.log
Normal file
@ -0,0 +1,350 @@
|
||||
Loading link script "procedure-callingconvention-stack-bank.ld"
|
||||
Adding parameter assignment in __stackcall procedure plus::b = param(plus::b)
|
||||
Adding parameter assignment in __stackcall procedure plus::a = param(plus::a)
|
||||
Calling convention __stackcall adding prepare/execute/finalize for main::$0 = call plus('0', 7)
|
||||
Calling convention STACK_CALL replacing param(plus::a) with stackidx(char,plus::OFFSET_STACK_A)
|
||||
Calling convention STACK_CALL replacing param(plus::b) with stackidx(char,plus::OFFSET_STACK_B)
|
||||
Calling convention STACK_CALL adding stack return stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return
|
||||
Calling convention STACK_CALL adding stack pull main::$0 = stackpull(char)
|
||||
Calling convention STACK_CALL adding stack push stackpush(char) = '0'
|
||||
Calling convention STACK_CALL adding stack push stackpush(char) = 7
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
void main()
|
||||
main: scope:[main] from __start
|
||||
stackpush(char) = '0'
|
||||
stackpush(char) = 7
|
||||
callexecute plus
|
||||
sideeffect stackpullpadding(1)
|
||||
main::$0 = stackpull(char)
|
||||
SCREEN[0] = main::$0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
return
|
||||
to:@return
|
||||
|
||||
__stackcall char plus(char a , char b)
|
||||
plus: scope:[plus] from
|
||||
plus::a#0 = stackidx(char,plus::OFFSET_STACK_A)
|
||||
plus::b#0 = stackidx(char,plus::OFFSET_STACK_B)
|
||||
plus::$0 = plus::a#0 + plus::b#0
|
||||
plus::return#0 = plus::$0
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
plus::return#1 = phi( plus/plus::return#0 )
|
||||
stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#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
|
||||
__constant char * const SCREEN = (char *)$400
|
||||
__constant unsigned int STACK_BASE = $103
|
||||
void __start()
|
||||
void main()
|
||||
char main::$0
|
||||
__stackcall char plus(char a , char b)
|
||||
char plus::$0
|
||||
__constant char plus::OFFSET_STACK_A = 1
|
||||
__constant char plus::OFFSET_STACK_B = 0
|
||||
__constant char plus::OFFSET_STACK_RETURN_1 = 1
|
||||
char plus::a
|
||||
char plus::a#0
|
||||
char plus::b
|
||||
char plus::b#0
|
||||
char plus::return
|
||||
char plus::return#0
|
||||
char plus::return#1
|
||||
|
||||
Adding number conversion cast (unumber) 7 in stackpush(char) = 7
|
||||
Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Inlining cast stackpush(char) = (unumber)7
|
||||
Successful SSA optimization Pass2InlineCast
|
||||
Simplifying constant pointer cast (char *) 1024
|
||||
Simplifying constant integer cast 7
|
||||
Simplifying constant integer cast 0
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (char) 7
|
||||
Finalized unsigned number type (char) 0
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Alias plus::return#0 = plus::$0 plus::return#1
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Simplifying expression containing zero SCREEN in [5] SCREEN[0] = main::$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
|
||||
Finalized unsigned number type (char) 1
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
CALL GRAPH
|
||||
Calls in [main] to plus:7
|
||||
|
||||
Created 0 initial phi equivalence classes
|
||||
Coalesced down to 0 phi equivalence classes
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
|
||||
__stackcall char plus(char a , char b)
|
||||
plus: scope:[plus] from
|
||||
[0] plus::a#0 = stackidx(char,plus::OFFSET_STACK_A)
|
||||
[1] plus::b#0 = stackidx(char,plus::OFFSET_STACK_B)
|
||||
[2] plus::return#0 = plus::a#0 + plus::b#0
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
[3] stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#0
|
||||
[4] return
|
||||
to:@return
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[5] stackpush(char) = '0'
|
||||
[6] stackpush(char) = 7
|
||||
[7] callexecute plus
|
||||
sideeffect stackpullpadding(1)
|
||||
[9] main::$0 = stackpull(char)
|
||||
[10] *SCREEN = main::$0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[11] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
void main()
|
||||
char main::$0 // 4.0
|
||||
__stackcall char plus(char a , char b)
|
||||
char plus::a
|
||||
char plus::a#0 // 11.0
|
||||
char plus::b
|
||||
char plus::b#0 // 22.0
|
||||
char plus::return
|
||||
char plus::return#0 // 22.0
|
||||
|
||||
Initial phi equivalence classes
|
||||
Added variable plus::a#0 to live range equivalence class [ plus::a#0 ]
|
||||
Added variable plus::b#0 to live range equivalence class [ plus::b#0 ]
|
||||
Added variable plus::return#0 to live range equivalence class [ plus::return#0 ]
|
||||
Added variable main::$0 to live range equivalence class [ main::$0 ]
|
||||
Complete equivalence classes
|
||||
[ plus::a#0 ]
|
||||
[ plus::b#0 ]
|
||||
[ plus::return#0 ]
|
||||
[ main::$0 ]
|
||||
Allocated zp[1]:2 [ plus::b#0 ]
|
||||
Allocated zp[1]:3 [ plus::return#0 ]
|
||||
Allocated zp[1]:4 [ plus::a#0 ]
|
||||
Allocated zp[1]:5 [ main::$0 ]
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [0] plus::a#0 = stackidx(char,plus::OFFSET_STACK_A) [ plus::a#0 ] ( plus:7 [ plus::a#0 ] { } ) always clobbers reg byte a reg byte x
|
||||
Statement [1] plus::b#0 = stackidx(char,plus::OFFSET_STACK_B) [ plus::a#0 plus::b#0 ] ( plus:7 [ plus::a#0 plus::b#0 ] { } ) always clobbers reg byte a reg byte x
|
||||
Removing always clobbered register reg byte a as potential for zp[1]:4 [ plus::a#0 ]
|
||||
Removing always clobbered register reg byte x as potential for zp[1]:4 [ plus::a#0 ]
|
||||
Statement [2] plus::return#0 = plus::a#0 + plus::b#0 [ plus::return#0 ] ( plus:7 [ plus::return#0 ] { } ) always clobbers reg byte a
|
||||
Statement [3] stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#0 [ ] ( plus:7 [ ] { } ) always clobbers reg byte x
|
||||
Statement [5] stackpush(char) = '0' [ ] ( [ ] { } ) always clobbers reg byte a
|
||||
Statement [6] stackpush(char) = 7 [ ] ( [ ] { } ) always clobbers reg byte a
|
||||
Statement sideeffect stackpullpadding(1) always clobbers reg byte a
|
||||
Statement [9] main::$0 = stackpull(char) [ main::$0 ] ( [ main::$0 ] { } ) always clobbers reg byte a
|
||||
Statement [0] plus::a#0 = stackidx(char,plus::OFFSET_STACK_A) [ plus::a#0 ] ( plus:7 [ plus::a#0 ] { } ) always clobbers reg byte a reg byte x
|
||||
Statement [1] plus::b#0 = stackidx(char,plus::OFFSET_STACK_B) [ plus::a#0 plus::b#0 ] ( plus:7 [ plus::a#0 plus::b#0 ] { } ) always clobbers reg byte a reg byte x
|
||||
Statement [2] plus::return#0 = plus::a#0 + plus::b#0 [ plus::return#0 ] ( plus:7 [ plus::return#0 ] { } ) always clobbers reg byte a
|
||||
Statement [3] stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#0 [ ] ( plus:7 [ ] { } ) always clobbers reg byte x
|
||||
Statement [5] stackpush(char) = '0' [ ] ( [ ] { } ) always clobbers reg byte a
|
||||
Statement [6] stackpush(char) = 7 [ ] ( [ ] { } ) always clobbers reg byte a
|
||||
Statement sideeffect stackpullpadding(1) always clobbers reg byte a
|
||||
Statement [9] main::$0 = stackpull(char) [ main::$0 ] ( [ main::$0 ] { } ) always clobbers reg byte a
|
||||
Potential registers zp[1]:4 [ plus::a#0 ] : zp[1]:4 , reg byte y ,
|
||||
Potential registers zp[1]:2 [ plus::b#0 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp[1]:3 [ plus::return#0 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp[1]:5 [ main::$0 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [plus] 22: zp[1]:2 [ plus::b#0 ] 22: zp[1]:3 [ plus::return#0 ] 11: zp[1]:4 [ plus::a#0 ]
|
||||
Uplift Scope [main] 4: zp[1]:5 [ main::$0 ]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [plus] best 79 combination reg byte a [ plus::b#0 ] reg byte a [ plus::return#0 ] zp[1]:4 [ plus::a#0 ]
|
||||
Uplifting [main] best 73 combination reg byte a [ main::$0 ]
|
||||
Uplifting [] best 73 combination
|
||||
Attempting to uplift remaining variables inzp[1]:4 [ plus::a#0 ]
|
||||
Uplifting [plus] best 73 combination zp[1]:4 [ plus::a#0 ]
|
||||
Allocated (was zp[1]:4) zp[1]:2 [ plus::a#0 ]
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Test a procedure with calling convention stack
|
||||
// Upstart
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
// Global Constants & labels
|
||||
.const STACK_BASE = $103
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
// plus
|
||||
// __register(A) char plus(__zp(2) char a, __register(A) char b)
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 1
|
||||
.const OFFSET_STACK_B = 0
|
||||
.const OFFSET_STACK_RETURN_1 = 1
|
||||
.label a = 2
|
||||
// [0] plus::a#0 = stackidx(char,plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_A,x
|
||||
sta.z a
|
||||
// [1] plus::b#0 = stackidx(char,plus::OFFSET_STACK_B) -- vbuaa=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_B,x
|
||||
// [2] plus::return#0 = plus::a#0 + plus::b#0 -- vbuaa=vbuz1_plus_vbuaa
|
||||
clc
|
||||
adc.z a
|
||||
jmp __breturn
|
||||
// plus::@return
|
||||
__breturn:
|
||||
// [3] stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
||||
tsx
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN_1,x
|
||||
// [4] return
|
||||
rts
|
||||
}
|
||||
// main
|
||||
main: {
|
||||
// [5] stackpush(char) = '0' -- _stackpushbyte_=vbuc1
|
||||
lda #'0'
|
||||
pha
|
||||
// [6] stackpush(char) = 7 -- _stackpushbyte_=vbuc1
|
||||
lda #7
|
||||
pha
|
||||
// [7] callexecute plus -- call_vprc1
|
||||
jsr plus
|
||||
// sideeffect stackpullpadding(1) -- _stackpullpadding_1
|
||||
pla
|
||||
// [9] main::$0 = stackpull(char) -- vbuaa=_stackpullbyte_
|
||||
pla
|
||||
// [10] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
|
||||
sta SCREEN
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [11] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
__constant unsigned int STACK_BASE = $103
|
||||
void main()
|
||||
char main::$0 // reg byte a 4.0
|
||||
__stackcall char plus(char a , char b)
|
||||
__constant char plus::OFFSET_STACK_A = 1
|
||||
__constant char plus::OFFSET_STACK_B = 0
|
||||
__constant char plus::OFFSET_STACK_RETURN_1 = 1
|
||||
char plus::a
|
||||
char plus::a#0 // a zp[1]:2 11.0
|
||||
char plus::b
|
||||
char plus::b#0 // reg byte a 22.0
|
||||
char plus::return
|
||||
char plus::return#0 // reg byte a 22.0
|
||||
|
||||
zp[1]:2 [ plus::a#0 ]
|
||||
reg byte a [ plus::b#0 ]
|
||||
reg byte a [ plus::return#0 ]
|
||||
reg byte a [ main::$0 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 67
|
||||
|
||||
// File Comments
|
||||
// Test a procedure with calling convention stack
|
||||
// Upstart
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
// Global Constants & labels
|
||||
.const STACK_BASE = $103
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
// plus
|
||||
// __register(A) char plus(__zp(2) char a, __register(A) char b)
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 1
|
||||
.const OFFSET_STACK_B = 0
|
||||
.const OFFSET_STACK_RETURN_1 = 1
|
||||
.label a = 2
|
||||
// [0] plus::a#0 = stackidx(char,plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_A,x
|
||||
sta.z a
|
||||
// [1] plus::b#0 = stackidx(char,plus::OFFSET_STACK_B) -- vbuaa=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_B,x
|
||||
// return a+b;
|
||||
// [2] plus::return#0 = plus::a#0 + plus::b#0 -- vbuaa=vbuz1_plus_vbuaa
|
||||
clc
|
||||
adc.z a
|
||||
// plus::@return
|
||||
// }
|
||||
// [3] stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
||||
tsx
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN_1,x
|
||||
// [4] return
|
||||
rts
|
||||
}
|
||||
// main
|
||||
main: {
|
||||
// plus('0', 7)
|
||||
// [5] stackpush(char) = '0' -- _stackpushbyte_=vbuc1
|
||||
lda #'0'
|
||||
pha
|
||||
// [6] stackpush(char) = 7 -- _stackpushbyte_=vbuc1
|
||||
lda #7
|
||||
pha
|
||||
// [7] callexecute plus -- call_vprc1
|
||||
jsr plus
|
||||
// sideeffect stackpullpadding(1) -- _stackpullpadding_1
|
||||
pla
|
||||
// [9] main::$0 = stackpull(char) -- vbuaa=_stackpullbyte_
|
||||
pla
|
||||
// SCREEN[0] = plus('0', 7)
|
||||
// [10] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
|
||||
sta SCREEN
|
||||
// main::@return
|
||||
// }
|
||||
// [11] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
19
src/test/ref/procedure-callingconvention-stack-bank-0.sym
Normal file
19
src/test/ref/procedure-callingconvention-stack-bank-0.sym
Normal file
@ -0,0 +1,19 @@
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
__constant unsigned int STACK_BASE = $103
|
||||
void main()
|
||||
char main::$0 // reg byte a 4.0
|
||||
__stackcall char plus(char a , char b)
|
||||
__constant char plus::OFFSET_STACK_A = 1
|
||||
__constant char plus::OFFSET_STACK_B = 0
|
||||
__constant char plus::OFFSET_STACK_RETURN_1 = 1
|
||||
char plus::a
|
||||
char plus::a#0 // a zp[1]:2 11.0
|
||||
char plus::b
|
||||
char plus::b#0 // reg byte a 22.0
|
||||
char plus::return
|
||||
char plus::return#0 // reg byte a 22.0
|
||||
|
||||
zp[1]:2 [ plus::a#0 ]
|
||||
reg byte a [ plus::b#0 ]
|
||||
reg byte a [ plus::return#0 ]
|
||||
reg byte a [ main::$0 ]
|
45
src/test/ref/procedure-callingconvention-stack-bank-1.asm
Normal file
45
src/test/ref/procedure-callingconvention-stack-bank-1.asm
Normal file
@ -0,0 +1,45 @@
|
||||
// Test a procedure with calling convention stack
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
.const STACK_BASE = $103
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
// __register(A) char plus(__zp(2) char a, __register(A) char b)
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 1
|
||||
.const OFFSET_STACK_B = 0
|
||||
.const OFFSET_STACK_RETURN_1 = 1
|
||||
.label a = 2
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_A,x
|
||||
sta.z a
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_B,x
|
||||
// return a+b;
|
||||
clc
|
||||
adc.z a
|
||||
// }
|
||||
tsx
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN_1,x
|
||||
rts
|
||||
}
|
||||
main: {
|
||||
// plus('0', 7)
|
||||
lda #'0'
|
||||
pha
|
||||
lda #7
|
||||
pha
|
||||
jsr plus
|
||||
pla
|
||||
pla
|
||||
// SCREEN[0] = plus('0', 7)
|
||||
sta SCREEN
|
||||
// }
|
||||
rts
|
||||
}
|
24
src/test/ref/procedure-callingconvention-stack-bank-1.cfg
Normal file
24
src/test/ref/procedure-callingconvention-stack-bank-1.cfg
Normal file
@ -0,0 +1,24 @@
|
||||
|
||||
__stackcall char plus(char a , char b)
|
||||
plus: scope:[plus] from
|
||||
[0] plus::a#0 = stackidx(char,plus::OFFSET_STACK_A)
|
||||
[1] plus::b#0 = stackidx(char,plus::OFFSET_STACK_B)
|
||||
[2] plus::return#0 = plus::a#0 + plus::b#0
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
[3] stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#0
|
||||
[4] return
|
||||
to:@return
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[5] stackpush(char) = '0'
|
||||
[6] stackpush(char) = 7
|
||||
[7] callexecute plus
|
||||
sideeffect stackpullpadding(1)
|
||||
[9] main::$0 = stackpull(char)
|
||||
[10] *SCREEN = main::$0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[11] return
|
||||
to:@return
|
350
src/test/ref/procedure-callingconvention-stack-bank-1.log
Normal file
350
src/test/ref/procedure-callingconvention-stack-bank-1.log
Normal file
@ -0,0 +1,350 @@
|
||||
Loading link script "procedure-callingconvention-stack-bank.ld"
|
||||
Adding parameter assignment in __stackcall procedure plus::b = param(plus::b)
|
||||
Adding parameter assignment in __stackcall procedure plus::a = param(plus::a)
|
||||
Calling convention __stackcall adding prepare/execute/finalize for main::$0 = call plus('0', 7)
|
||||
Calling convention STACK_CALL replacing param(plus::a) with stackidx(char,plus::OFFSET_STACK_A)
|
||||
Calling convention STACK_CALL replacing param(plus::b) with stackidx(char,plus::OFFSET_STACK_B)
|
||||
Calling convention STACK_CALL adding stack return stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return
|
||||
Calling convention STACK_CALL adding stack pull main::$0 = stackpull(char)
|
||||
Calling convention STACK_CALL adding stack push stackpush(char) = '0'
|
||||
Calling convention STACK_CALL adding stack push stackpush(char) = 7
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
void main()
|
||||
main: scope:[main] from __start
|
||||
stackpush(char) = '0'
|
||||
stackpush(char) = 7
|
||||
callexecute plus
|
||||
sideeffect stackpullpadding(1)
|
||||
main::$0 = stackpull(char)
|
||||
SCREEN[0] = main::$0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
return
|
||||
to:@return
|
||||
|
||||
__stackcall char plus(char a , char b)
|
||||
plus: scope:[plus] from
|
||||
plus::a#0 = stackidx(char,plus::OFFSET_STACK_A)
|
||||
plus::b#0 = stackidx(char,plus::OFFSET_STACK_B)
|
||||
plus::$0 = plus::a#0 + plus::b#0
|
||||
plus::return#0 = plus::$0
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
plus::return#1 = phi( plus/plus::return#0 )
|
||||
stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#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
|
||||
__constant char * const SCREEN = (char *)$400
|
||||
__constant unsigned int STACK_BASE = $103
|
||||
void __start()
|
||||
void main()
|
||||
char main::$0
|
||||
__stackcall char plus(char a , char b)
|
||||
char plus::$0
|
||||
__constant char plus::OFFSET_STACK_A = 1
|
||||
__constant char plus::OFFSET_STACK_B = 0
|
||||
__constant char plus::OFFSET_STACK_RETURN_1 = 1
|
||||
char plus::a
|
||||
char plus::a#0
|
||||
char plus::b
|
||||
char plus::b#0
|
||||
char plus::return
|
||||
char plus::return#0
|
||||
char plus::return#1
|
||||
|
||||
Adding number conversion cast (unumber) 7 in stackpush(char) = 7
|
||||
Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Inlining cast stackpush(char) = (unumber)7
|
||||
Successful SSA optimization Pass2InlineCast
|
||||
Simplifying constant pointer cast (char *) 1024
|
||||
Simplifying constant integer cast 7
|
||||
Simplifying constant integer cast 0
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (char) 7
|
||||
Finalized unsigned number type (char) 0
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Alias plus::return#0 = plus::$0 plus::return#1
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Simplifying expression containing zero SCREEN in [5] SCREEN[0] = main::$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
|
||||
Finalized unsigned number type (char) 1
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
CALL GRAPH
|
||||
Calls in [main] to plus:7
|
||||
|
||||
Created 0 initial phi equivalence classes
|
||||
Coalesced down to 0 phi equivalence classes
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
|
||||
__stackcall char plus(char a , char b)
|
||||
plus: scope:[plus] from
|
||||
[0] plus::a#0 = stackidx(char,plus::OFFSET_STACK_A)
|
||||
[1] plus::b#0 = stackidx(char,plus::OFFSET_STACK_B)
|
||||
[2] plus::return#0 = plus::a#0 + plus::b#0
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
[3] stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#0
|
||||
[4] return
|
||||
to:@return
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[5] stackpush(char) = '0'
|
||||
[6] stackpush(char) = 7
|
||||
[7] callexecute plus
|
||||
sideeffect stackpullpadding(1)
|
||||
[9] main::$0 = stackpull(char)
|
||||
[10] *SCREEN = main::$0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[11] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
void main()
|
||||
char main::$0 // 4.0
|
||||
__stackcall char plus(char a , char b)
|
||||
char plus::a
|
||||
char plus::a#0 // 11.0
|
||||
char plus::b
|
||||
char plus::b#0 // 22.0
|
||||
char plus::return
|
||||
char plus::return#0 // 22.0
|
||||
|
||||
Initial phi equivalence classes
|
||||
Added variable plus::a#0 to live range equivalence class [ plus::a#0 ]
|
||||
Added variable plus::b#0 to live range equivalence class [ plus::b#0 ]
|
||||
Added variable plus::return#0 to live range equivalence class [ plus::return#0 ]
|
||||
Added variable main::$0 to live range equivalence class [ main::$0 ]
|
||||
Complete equivalence classes
|
||||
[ plus::a#0 ]
|
||||
[ plus::b#0 ]
|
||||
[ plus::return#0 ]
|
||||
[ main::$0 ]
|
||||
Allocated zp[1]:2 [ plus::b#0 ]
|
||||
Allocated zp[1]:3 [ plus::return#0 ]
|
||||
Allocated zp[1]:4 [ plus::a#0 ]
|
||||
Allocated zp[1]:5 [ main::$0 ]
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [0] plus::a#0 = stackidx(char,plus::OFFSET_STACK_A) [ plus::a#0 ] ( plus:7 [ plus::a#0 ] { } ) always clobbers reg byte a reg byte x
|
||||
Statement [1] plus::b#0 = stackidx(char,plus::OFFSET_STACK_B) [ plus::a#0 plus::b#0 ] ( plus:7 [ plus::a#0 plus::b#0 ] { } ) always clobbers reg byte a reg byte x
|
||||
Removing always clobbered register reg byte a as potential for zp[1]:4 [ plus::a#0 ]
|
||||
Removing always clobbered register reg byte x as potential for zp[1]:4 [ plus::a#0 ]
|
||||
Statement [2] plus::return#0 = plus::a#0 + plus::b#0 [ plus::return#0 ] ( plus:7 [ plus::return#0 ] { } ) always clobbers reg byte a
|
||||
Statement [3] stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#0 [ ] ( plus:7 [ ] { } ) always clobbers reg byte x
|
||||
Statement [5] stackpush(char) = '0' [ ] ( [ ] { } ) always clobbers reg byte a
|
||||
Statement [6] stackpush(char) = 7 [ ] ( [ ] { } ) always clobbers reg byte a
|
||||
Statement sideeffect stackpullpadding(1) always clobbers reg byte a
|
||||
Statement [9] main::$0 = stackpull(char) [ main::$0 ] ( [ main::$0 ] { } ) always clobbers reg byte a
|
||||
Statement [0] plus::a#0 = stackidx(char,plus::OFFSET_STACK_A) [ plus::a#0 ] ( plus:7 [ plus::a#0 ] { } ) always clobbers reg byte a reg byte x
|
||||
Statement [1] plus::b#0 = stackidx(char,plus::OFFSET_STACK_B) [ plus::a#0 plus::b#0 ] ( plus:7 [ plus::a#0 plus::b#0 ] { } ) always clobbers reg byte a reg byte x
|
||||
Statement [2] plus::return#0 = plus::a#0 + plus::b#0 [ plus::return#0 ] ( plus:7 [ plus::return#0 ] { } ) always clobbers reg byte a
|
||||
Statement [3] stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#0 [ ] ( plus:7 [ ] { } ) always clobbers reg byte x
|
||||
Statement [5] stackpush(char) = '0' [ ] ( [ ] { } ) always clobbers reg byte a
|
||||
Statement [6] stackpush(char) = 7 [ ] ( [ ] { } ) always clobbers reg byte a
|
||||
Statement sideeffect stackpullpadding(1) always clobbers reg byte a
|
||||
Statement [9] main::$0 = stackpull(char) [ main::$0 ] ( [ main::$0 ] { } ) always clobbers reg byte a
|
||||
Potential registers zp[1]:4 [ plus::a#0 ] : zp[1]:4 , reg byte y ,
|
||||
Potential registers zp[1]:2 [ plus::b#0 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp[1]:3 [ plus::return#0 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp[1]:5 [ main::$0 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [plus] 22: zp[1]:2 [ plus::b#0 ] 22: zp[1]:3 [ plus::return#0 ] 11: zp[1]:4 [ plus::a#0 ]
|
||||
Uplift Scope [main] 4: zp[1]:5 [ main::$0 ]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [plus] best 79 combination reg byte a [ plus::b#0 ] reg byte a [ plus::return#0 ] zp[1]:4 [ plus::a#0 ]
|
||||
Uplifting [main] best 73 combination reg byte a [ main::$0 ]
|
||||
Uplifting [] best 73 combination
|
||||
Attempting to uplift remaining variables inzp[1]:4 [ plus::a#0 ]
|
||||
Uplifting [plus] best 73 combination zp[1]:4 [ plus::a#0 ]
|
||||
Allocated (was zp[1]:4) zp[1]:2 [ plus::a#0 ]
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Test a procedure with calling convention stack
|
||||
// Upstart
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
// Global Constants & labels
|
||||
.const STACK_BASE = $103
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
// plus
|
||||
// __register(A) char plus(__zp(2) char a, __register(A) char b)
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 1
|
||||
.const OFFSET_STACK_B = 0
|
||||
.const OFFSET_STACK_RETURN_1 = 1
|
||||
.label a = 2
|
||||
// [0] plus::a#0 = stackidx(char,plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_A,x
|
||||
sta.z a
|
||||
// [1] plus::b#0 = stackidx(char,plus::OFFSET_STACK_B) -- vbuaa=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_B,x
|
||||
// [2] plus::return#0 = plus::a#0 + plus::b#0 -- vbuaa=vbuz1_plus_vbuaa
|
||||
clc
|
||||
adc.z a
|
||||
jmp __breturn
|
||||
// plus::@return
|
||||
__breturn:
|
||||
// [3] stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
||||
tsx
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN_1,x
|
||||
// [4] return
|
||||
rts
|
||||
}
|
||||
// main
|
||||
main: {
|
||||
// [5] stackpush(char) = '0' -- _stackpushbyte_=vbuc1
|
||||
lda #'0'
|
||||
pha
|
||||
// [6] stackpush(char) = 7 -- _stackpushbyte_=vbuc1
|
||||
lda #7
|
||||
pha
|
||||
// [7] callexecute plus -- call_vprc1
|
||||
jsr plus
|
||||
// sideeffect stackpullpadding(1) -- _stackpullpadding_1
|
||||
pla
|
||||
// [9] main::$0 = stackpull(char) -- vbuaa=_stackpullbyte_
|
||||
pla
|
||||
// [10] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
|
||||
sta SCREEN
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [11] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
__constant unsigned int STACK_BASE = $103
|
||||
void main()
|
||||
char main::$0 // reg byte a 4.0
|
||||
__stackcall char plus(char a , char b)
|
||||
__constant char plus::OFFSET_STACK_A = 1
|
||||
__constant char plus::OFFSET_STACK_B = 0
|
||||
__constant char plus::OFFSET_STACK_RETURN_1 = 1
|
||||
char plus::a
|
||||
char plus::a#0 // a zp[1]:2 11.0
|
||||
char plus::b
|
||||
char plus::b#0 // reg byte a 22.0
|
||||
char plus::return
|
||||
char plus::return#0 // reg byte a 22.0
|
||||
|
||||
zp[1]:2 [ plus::a#0 ]
|
||||
reg byte a [ plus::b#0 ]
|
||||
reg byte a [ plus::return#0 ]
|
||||
reg byte a [ main::$0 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 67
|
||||
|
||||
// File Comments
|
||||
// Test a procedure with calling convention stack
|
||||
// Upstart
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
// Global Constants & labels
|
||||
.const STACK_BASE = $103
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
// plus
|
||||
// __register(A) char plus(__zp(2) char a, __register(A) char b)
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 1
|
||||
.const OFFSET_STACK_B = 0
|
||||
.const OFFSET_STACK_RETURN_1 = 1
|
||||
.label a = 2
|
||||
// [0] plus::a#0 = stackidx(char,plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_A,x
|
||||
sta.z a
|
||||
// [1] plus::b#0 = stackidx(char,plus::OFFSET_STACK_B) -- vbuaa=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_B,x
|
||||
// return a+b;
|
||||
// [2] plus::return#0 = plus::a#0 + plus::b#0 -- vbuaa=vbuz1_plus_vbuaa
|
||||
clc
|
||||
adc.z a
|
||||
// plus::@return
|
||||
// }
|
||||
// [3] stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
||||
tsx
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN_1,x
|
||||
// [4] return
|
||||
rts
|
||||
}
|
||||
// main
|
||||
main: {
|
||||
// plus('0', 7)
|
||||
// [5] stackpush(char) = '0' -- _stackpushbyte_=vbuc1
|
||||
lda #'0'
|
||||
pha
|
||||
// [6] stackpush(char) = 7 -- _stackpushbyte_=vbuc1
|
||||
lda #7
|
||||
pha
|
||||
// [7] callexecute plus -- call_vprc1
|
||||
jsr plus
|
||||
// sideeffect stackpullpadding(1) -- _stackpullpadding_1
|
||||
pla
|
||||
// [9] main::$0 = stackpull(char) -- vbuaa=_stackpullbyte_
|
||||
pla
|
||||
// SCREEN[0] = plus('0', 7)
|
||||
// [10] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
|
||||
sta SCREEN
|
||||
// main::@return
|
||||
// }
|
||||
// [11] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
19
src/test/ref/procedure-callingconvention-stack-bank-1.sym
Normal file
19
src/test/ref/procedure-callingconvention-stack-bank-1.sym
Normal file
@ -0,0 +1,19 @@
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
__constant unsigned int STACK_BASE = $103
|
||||
void main()
|
||||
char main::$0 // reg byte a 4.0
|
||||
__stackcall char plus(char a , char b)
|
||||
__constant char plus::OFFSET_STACK_A = 1
|
||||
__constant char plus::OFFSET_STACK_B = 0
|
||||
__constant char plus::OFFSET_STACK_RETURN_1 = 1
|
||||
char plus::a
|
||||
char plus::a#0 // a zp[1]:2 11.0
|
||||
char plus::b
|
||||
char plus::b#0 // reg byte a 22.0
|
||||
char plus::return
|
||||
char plus::return#0 // reg byte a 22.0
|
||||
|
||||
zp[1]:2 [ plus::a#0 ]
|
||||
reg byte a [ plus::b#0 ]
|
||||
reg byte a [ plus::return#0 ]
|
||||
reg byte a [ main::$0 ]
|
74
src/test/ref/procedure-callingconvention-stack-bank-2.asm
Normal file
74
src/test/ref/procedure-callingconvention-stack-bank-2.asm
Normal file
@ -0,0 +1,74 @@
|
||||
// Test a procedure with calling convention stack
|
||||
// A slightly more complex call
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
.const STACK_BASE = $103
|
||||
.label SCREEN = $400
|
||||
.label i = 4
|
||||
.segment Code
|
||||
__start: {
|
||||
// char i = 0
|
||||
lda #0
|
||||
sta.z i
|
||||
jsr main
|
||||
rts
|
||||
}
|
||||
.segment stage
|
||||
// this should give a pragma error during compile, as test is not declared yet.
|
||||
// __register(A) char plus(__zp(2) char a, __register(A) char b)
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 1
|
||||
.const OFFSET_STACK_B = 0
|
||||
.const OFFSET_STACK_RETURN_1 = 1
|
||||
.label a = 2
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_A,x
|
||||
sta.z a
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_B,x
|
||||
// i++;
|
||||
inc.z i
|
||||
// return a+b;
|
||||
clc
|
||||
adc.z a
|
||||
// }
|
||||
tsx
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN_1,x
|
||||
rts
|
||||
}
|
||||
main: {
|
||||
.label a = 3
|
||||
lda #0
|
||||
sta.z a
|
||||
__b1:
|
||||
// char v = a+1
|
||||
ldx.z a
|
||||
inx
|
||||
// char w = plus('0', v)
|
||||
lda #'0'
|
||||
pha
|
||||
txa
|
||||
pha
|
||||
jsr plus
|
||||
pla
|
||||
pla
|
||||
// w+a
|
||||
clc
|
||||
adc.z a
|
||||
// SCREEN[i] = w+a
|
||||
ldy.z i
|
||||
sta SCREEN,y
|
||||
// for(char a:0..1)
|
||||
inc.z a
|
||||
lda #2
|
||||
cmp.z a
|
||||
bne __b1
|
||||
// }
|
||||
rts
|
||||
}
|
48
src/test/ref/procedure-callingconvention-stack-bank-2.cfg
Normal file
48
src/test/ref/procedure-callingconvention-stack-bank-2.cfg
Normal file
@ -0,0 +1,48 @@
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
[0] phi()
|
||||
to:__start::__init1
|
||||
__start::__init1: scope:[__start] from __start
|
||||
[1] i = 0
|
||||
to:__start::@1
|
||||
__start::@1: scope:[__start] from __start::__init1
|
||||
[2] phi()
|
||||
[3] call main
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start::@1
|
||||
[4] return
|
||||
to:@return
|
||||
|
||||
__stackcall char plus(char a , char b)
|
||||
plus: scope:[plus] from
|
||||
[5] plus::a#0 = stackidx(char,plus::OFFSET_STACK_A)
|
||||
[6] plus::b#0 = stackidx(char,plus::OFFSET_STACK_B)
|
||||
[7] i = ++ i
|
||||
[8] plus::return#0 = plus::a#0 + plus::b#0
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
[9] stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#0
|
||||
[10] return
|
||||
to:@return
|
||||
|
||||
void main()
|
||||
main: scope:[main] from __start::@1
|
||||
[11] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@1
|
||||
[12] main::a#2 = phi( main/0, main::@1/main::a#1 )
|
||||
[13] main::v#0 = main::a#2 + 1
|
||||
[14] stackpush(char) = '0'
|
||||
[15] stackpush(char) = main::v#0
|
||||
[16] callexecute plus
|
||||
sideeffect stackpullpadding(1)
|
||||
[18] main::w#0 = stackpull(char)
|
||||
[19] main::$2 = main::w#0 + main::a#2
|
||||
[20] SCREEN[i] = main::$2
|
||||
[21] main::a#1 = ++ main::a#2
|
||||
[22] if(main::a#1!=2) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[23] return
|
||||
to:@return
|
595
src/test/ref/procedure-callingconvention-stack-bank-2.log
Normal file
595
src/test/ref/procedure-callingconvention-stack-bank-2.log
Normal file
@ -0,0 +1,595 @@
|
||||
Loading link script "procedure-callingconvention-stack-bank.ld"
|
||||
Converting variable modified inside __stackcall procedure plus() to load/store i
|
||||
Adding parameter assignment in __stackcall procedure plus::b = param(plus::b)
|
||||
Adding parameter assignment in __stackcall procedure plus::a = param(plus::a)
|
||||
Inlined call call __init
|
||||
Eliminating unused variable with no statement main::$0
|
||||
Eliminating unused variable with no statement main::$1
|
||||
Calling convention __stackcall adding prepare/execute/finalize for main::w = call plus('0', main::v)
|
||||
Calling convention STACK_CALL replacing param(plus::a) with stackidx(char,plus::OFFSET_STACK_A)
|
||||
Calling convention STACK_CALL replacing param(plus::b) with stackidx(char,plus::OFFSET_STACK_B)
|
||||
Calling convention STACK_CALL adding stack return stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return
|
||||
Calling convention STACK_CALL adding stack pull main::w = stackpull(char)
|
||||
Calling convention STACK_CALL adding stack push stackpush(char) = '0'
|
||||
Calling convention STACK_CALL adding stack push stackpush(char) = main::v
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
void main()
|
||||
main: scope:[main] from __start::@1
|
||||
main::a#0 = 0
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@1
|
||||
main::a#2 = phi( main/main::a#0, main::@1/main::a#1 )
|
||||
main::v#0 = main::a#2 + 1
|
||||
stackpush(char) = '0'
|
||||
stackpush(char) = main::v#0
|
||||
callexecute plus
|
||||
sideeffect stackpullpadding(1)
|
||||
main::w#0 = stackpull(char)
|
||||
main::$2 = main::w#0 + main::a#2
|
||||
SCREEN[i] = main::$2
|
||||
main::a#1 = main::a#2 + rangenext(0,1)
|
||||
main::$3 = main::a#1 != rangelast(0,1)
|
||||
if(main::$3) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
__stackcall char plus(char a , char b)
|
||||
plus: scope:[plus] from
|
||||
plus::a#0 = stackidx(char,plus::OFFSET_STACK_A)
|
||||
plus::b#0 = stackidx(char,plus::OFFSET_STACK_B)
|
||||
i = ++ i
|
||||
plus::$0 = plus::a#0 + plus::b#0
|
||||
plus::return#0 = plus::$0
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
plus::return#1 = phi( plus/plus::return#0 )
|
||||
stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#1
|
||||
return
|
||||
to:@return
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
to:__start::__init1
|
||||
__start::__init1: scope:[__start] from __start
|
||||
i = 0
|
||||
to:__start::@1
|
||||
__start::@1: scope:[__start] from __start::__init1
|
||||
call main
|
||||
to:__start::@2
|
||||
__start::@2: scope:[__start] from __start::@1
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start::@2
|
||||
return
|
||||
to:@return
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
__constant char * const SCREEN = (char *)$400
|
||||
__constant unsigned int STACK_BASE = $103
|
||||
void __start()
|
||||
__loadstore char i
|
||||
void main()
|
||||
char main::$2
|
||||
bool main::$3
|
||||
char main::a
|
||||
char main::a#0
|
||||
char main::a#1
|
||||
char main::a#2
|
||||
char main::v
|
||||
char main::v#0
|
||||
char main::w
|
||||
char main::w#0
|
||||
__stackcall char plus(char a , char b)
|
||||
char plus::$0
|
||||
__constant char plus::OFFSET_STACK_A = 1
|
||||
__constant char plus::OFFSET_STACK_B = 0
|
||||
__constant char plus::OFFSET_STACK_RETURN_1 = 1
|
||||
char plus::a
|
||||
char plus::a#0
|
||||
char plus::b
|
||||
char plus::b#0
|
||||
char plus::return
|
||||
char plus::return#0
|
||||
char plus::return#1
|
||||
|
||||
Adding number conversion cast (unumber) 1 in main::v#0 = main::a#2 + 1
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Simplifying constant pointer cast (char *) 1024
|
||||
Simplifying constant integer cast 1
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (char) 1
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Alias plus::return#0 = plus::$0 plus::return#1
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Simple Condition main::$3 [12] if(main::a#1!=rangelast(0,1)) goto main::@1
|
||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||
Constant main::a#0 = 0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Resolved ranged next value [10] main::a#1 = ++ main::a#2 to ++
|
||||
Resolved ranged comparison value [12] if(main::a#1!=rangelast(0,1)) goto main::@1 to 2
|
||||
Adding number conversion cast (unumber) 2 in if(main::a#1!=2) goto main::@1
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Simplifying constant integer cast 2
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (char) 2
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Inlining constant with var siblings main::a#0
|
||||
Constant inlined main::a#0 = 0
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Finalized unsigned number type (char) 1
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Added new block during phi lifting main::@2(between main::@1 and main::@1)
|
||||
Adding NOP phi() at start of __start
|
||||
Adding NOP phi() at start of __start::@1
|
||||
Adding NOP phi() at start of __start::@2
|
||||
Adding NOP phi() at start of main
|
||||
CALL GRAPH
|
||||
Calls in [__start] to main:3
|
||||
Calls in [main] to plus:17
|
||||
|
||||
Created 1 initial phi equivalence classes
|
||||
Coalesced [25] main::a#3 = main::a#1
|
||||
Coalesced down to 1 phi equivalence classes
|
||||
Culled Empty Block label __start::@2
|
||||
Culled Empty Block label main::@2
|
||||
Adding NOP phi() at start of __start
|
||||
Adding NOP phi() at start of __start::@1
|
||||
Adding NOP phi() at start of main
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
[0] phi()
|
||||
to:__start::__init1
|
||||
__start::__init1: scope:[__start] from __start
|
||||
[1] i = 0
|
||||
to:__start::@1
|
||||
__start::@1: scope:[__start] from __start::__init1
|
||||
[2] phi()
|
||||
[3] call main
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start::@1
|
||||
[4] return
|
||||
to:@return
|
||||
|
||||
__stackcall char plus(char a , char b)
|
||||
plus: scope:[plus] from
|
||||
[5] plus::a#0 = stackidx(char,plus::OFFSET_STACK_A)
|
||||
[6] plus::b#0 = stackidx(char,plus::OFFSET_STACK_B)
|
||||
[7] i = ++ i
|
||||
[8] plus::return#0 = plus::a#0 + plus::b#0
|
||||
to:plus::@return
|
||||
plus::@return: scope:[plus] from plus
|
||||
[9] stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#0
|
||||
[10] return
|
||||
to:@return
|
||||
|
||||
void main()
|
||||
main: scope:[main] from __start::@1
|
||||
[11] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@1
|
||||
[12] main::a#2 = phi( main/0, main::@1/main::a#1 )
|
||||
[13] main::v#0 = main::a#2 + 1
|
||||
[14] stackpush(char) = '0'
|
||||
[15] stackpush(char) = main::v#0
|
||||
[16] callexecute plus
|
||||
sideeffect stackpullpadding(1)
|
||||
[18] main::w#0 = stackpull(char)
|
||||
[19] main::$2 = main::w#0 + main::a#2
|
||||
[20] SCREEN[i] = main::$2
|
||||
[21] main::a#1 = ++ main::a#2
|
||||
[22] if(main::a#1!=2) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[23] return
|
||||
to:@return
|
||||
|
||||
null depth in calling loop Loop head: main::@1 tails: main::@1 blocks: main::@1 in scope plus
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
void __start()
|
||||
__loadstore char i // 105.24999999999999
|
||||
void main()
|
||||
char main::$2 // 202.0
|
||||
char main::a
|
||||
char main::a#1 // 151.5
|
||||
char main::a#2 // 44.888888888888886
|
||||
char main::v
|
||||
char main::v#0 // 101.0
|
||||
char main::w
|
||||
char main::w#0 // 202.0
|
||||
__stackcall char plus(char a , char b)
|
||||
char plus::a
|
||||
char plus::a#0 // 667.3333333333334
|
||||
char plus::b
|
||||
char plus::b#0 // 1001.0
|
||||
char plus::return
|
||||
char plus::return#0 // 2002.0
|
||||
|
||||
Initial phi equivalence classes
|
||||
[ main::a#2 main::a#1 ]
|
||||
Added variable i to live range equivalence class [ i ]
|
||||
Added variable plus::a#0 to live range equivalence class [ plus::a#0 ]
|
||||
Added variable plus::b#0 to live range equivalence class [ plus::b#0 ]
|
||||
Added variable plus::return#0 to live range equivalence class [ plus::return#0 ]
|
||||
Added variable main::v#0 to live range equivalence class [ main::v#0 ]
|
||||
Added variable main::w#0 to live range equivalence class [ main::w#0 ]
|
||||
Added variable main::$2 to live range equivalence class [ main::$2 ]
|
||||
Complete equivalence classes
|
||||
[ main::a#2 main::a#1 ]
|
||||
[ i ]
|
||||
[ plus::a#0 ]
|
||||
[ plus::b#0 ]
|
||||
[ plus::return#0 ]
|
||||
[ main::v#0 ]
|
||||
[ main::w#0 ]
|
||||
[ main::$2 ]
|
||||
Allocated zp[1]:2 [ plus::return#0 ]
|
||||
Allocated zp[1]:3 [ plus::b#0 ]
|
||||
Allocated zp[1]:4 [ plus::a#0 ]
|
||||
Allocated zp[1]:5 [ main::w#0 ]
|
||||
Allocated zp[1]:6 [ main::$2 ]
|
||||
Allocated zp[1]:7 [ main::a#2 main::a#1 ]
|
||||
Allocated zp[1]:8 [ i ]
|
||||
Allocated zp[1]:9 [ main::v#0 ]
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [1] i = 0 [ i ] ( [ i ] { } ) always clobbers reg byte a
|
||||
Statement [5] plus::a#0 = stackidx(char,plus::OFFSET_STACK_A) [ i plus::a#0 ] ( main:3::plus:16 [ main::a#2 i plus::a#0 ] { } ) always clobbers reg byte a reg byte x
|
||||
Removing always clobbered register reg byte a as potential for zp[1]:7 [ main::a#2 main::a#1 ]
|
||||
Removing always clobbered register reg byte x as potential for zp[1]:7 [ main::a#2 main::a#1 ]
|
||||
Statement [6] plus::b#0 = stackidx(char,plus::OFFSET_STACK_B) [ i plus::a#0 plus::b#0 ] ( main:3::plus:16 [ main::a#2 i plus::a#0 plus::b#0 ] { } ) always clobbers reg byte a reg byte x
|
||||
Removing always clobbered register reg byte a as potential for zp[1]:4 [ plus::a#0 ]
|
||||
Removing always clobbered register reg byte x as potential for zp[1]:4 [ plus::a#0 ]
|
||||
Statement [8] plus::return#0 = plus::a#0 + plus::b#0 [ i plus::return#0 ] ( main:3::plus:16 [ main::a#2 i plus::return#0 ] { } ) always clobbers reg byte a
|
||||
Statement [9] stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#0 [ i ] ( main:3::plus:16 [ main::a#2 i ] { } ) always clobbers reg byte x
|
||||
Statement [14] stackpush(char) = '0' [ i main::a#2 main::v#0 ] ( main:3 [ i main::a#2 main::v#0 ] { } ) always clobbers reg byte a
|
||||
Removing always clobbered register reg byte a as potential for zp[1]:9 [ main::v#0 ]
|
||||
Statement [15] stackpush(char) = main::v#0 [ i main::a#2 ] ( main:3 [ i main::a#2 ] { } ) always clobbers reg byte a
|
||||
Statement sideeffect stackpullpadding(1) always clobbers reg byte a
|
||||
Statement [18] main::w#0 = stackpull(char) [ i main::a#2 main::w#0 ] ( main:3 [ i main::a#2 main::w#0 ] { } ) always clobbers reg byte a
|
||||
Statement [19] main::$2 = main::w#0 + main::a#2 [ i main::a#2 main::$2 ] ( main:3 [ i main::a#2 main::$2 ] { } ) always clobbers reg byte a
|
||||
Statement [20] SCREEN[i] = main::$2 [ i main::a#2 ] ( main:3 [ i main::a#2 ] { } ) always clobbers reg byte y
|
||||
Removing always clobbered register reg byte y as potential for zp[1]:7 [ main::a#2 main::a#1 ]
|
||||
Statement [22] if(main::a#1!=2) goto main::@1 [ i main::a#1 ] ( main:3 [ i main::a#1 ] { } ) always clobbers reg byte a
|
||||
Statement [1] i = 0 [ i ] ( [ i ] { } ) always clobbers reg byte a
|
||||
Statement [5] plus::a#0 = stackidx(char,plus::OFFSET_STACK_A) [ i plus::a#0 ] ( main:3::plus:16 [ main::a#2 i plus::a#0 ] { } ) always clobbers reg byte a reg byte x
|
||||
Statement [6] plus::b#0 = stackidx(char,plus::OFFSET_STACK_B) [ i plus::a#0 plus::b#0 ] ( main:3::plus:16 [ main::a#2 i plus::a#0 plus::b#0 ] { } ) always clobbers reg byte a reg byte x
|
||||
Statement [8] plus::return#0 = plus::a#0 + plus::b#0 [ i plus::return#0 ] ( main:3::plus:16 [ main::a#2 i plus::return#0 ] { } ) always clobbers reg byte a
|
||||
Statement [9] stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#0 [ i ] ( main:3::plus:16 [ main::a#2 i ] { } ) always clobbers reg byte x
|
||||
Statement [14] stackpush(char) = '0' [ i main::a#2 main::v#0 ] ( main:3 [ i main::a#2 main::v#0 ] { } ) always clobbers reg byte a
|
||||
Statement [15] stackpush(char) = main::v#0 [ i main::a#2 ] ( main:3 [ i main::a#2 ] { } ) always clobbers reg byte a
|
||||
Statement sideeffect stackpullpadding(1) always clobbers reg byte a
|
||||
Statement [18] main::w#0 = stackpull(char) [ i main::a#2 main::w#0 ] ( main:3 [ i main::a#2 main::w#0 ] { } ) always clobbers reg byte a
|
||||
Statement [19] main::$2 = main::w#0 + main::a#2 [ i main::a#2 main::$2 ] ( main:3 [ i main::a#2 main::$2 ] { } ) always clobbers reg byte a
|
||||
Statement [20] SCREEN[i] = main::$2 [ i main::a#2 ] ( main:3 [ i main::a#2 ] { } ) always clobbers reg byte y
|
||||
Statement [22] if(main::a#1!=2) goto main::@1 [ i main::a#1 ] ( main:3 [ i main::a#1 ] { } ) always clobbers reg byte a
|
||||
Potential registers zp[1]:7 [ main::a#2 main::a#1 ] : zp[1]:7 ,
|
||||
Potential registers zp[1]:8 [ i ] : zp[1]:8 ,
|
||||
Potential registers zp[1]:4 [ plus::a#0 ] : zp[1]:4 , reg byte y ,
|
||||
Potential registers zp[1]:3 [ plus::b#0 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp[1]:2 [ plus::return#0 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp[1]:9 [ main::v#0 ] : zp[1]:9 , reg byte x , reg byte y ,
|
||||
Potential registers zp[1]:5 [ main::w#0 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp[1]:6 [ main::$2 ] : zp[1]:6 , reg byte a , reg byte x , reg byte y ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [plus] 2,002: zp[1]:2 [ plus::return#0 ] 1,001: zp[1]:3 [ plus::b#0 ] 667.33: zp[1]:4 [ plus::a#0 ]
|
||||
Uplift Scope [main] 202: zp[1]:5 [ main::w#0 ] 202: zp[1]:6 [ main::$2 ] 196.39: zp[1]:7 [ main::a#2 main::a#1 ] 101: zp[1]:9 [ main::v#0 ]
|
||||
Uplift Scope [] 105.25: zp[1]:8 [ i ]
|
||||
Uplift Scope [__start]
|
||||
|
||||
Uplifting [plus] best 945 combination reg byte a [ plus::return#0 ] reg byte a [ plus::b#0 ] zp[1]:4 [ plus::a#0 ]
|
||||
Uplifting [main] best 785 combination reg byte a [ main::w#0 ] reg byte a [ main::$2 ] zp[1]:7 [ main::a#2 main::a#1 ] reg byte x [ main::v#0 ]
|
||||
Uplifting [] best 785 combination zp[1]:8 [ i ]
|
||||
Uplifting [__start] best 785 combination
|
||||
Attempting to uplift remaining variables inzp[1]:4 [ plus::a#0 ]
|
||||
Uplifting [plus] best 785 combination zp[1]:4 [ plus::a#0 ]
|
||||
Attempting to uplift remaining variables inzp[1]:7 [ main::a#2 main::a#1 ]
|
||||
Uplifting [main] best 785 combination zp[1]:7 [ main::a#2 main::a#1 ]
|
||||
Attempting to uplift remaining variables inzp[1]:8 [ i ]
|
||||
Uplifting [] best 785 combination zp[1]:8 [ i ]
|
||||
Allocated (was zp[1]:4) zp[1]:2 [ plus::a#0 ]
|
||||
Allocated (was zp[1]:7) zp[1]:3 [ main::a#2 main::a#1 ]
|
||||
Allocated (was zp[1]:8) zp[1]:4 [ i ]
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Test a procedure with calling convention stack
|
||||
// A slightly more complex call
|
||||
// Upstart
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
// Global Constants & labels
|
||||
.const STACK_BASE = $103
|
||||
.label SCREEN = $400
|
||||
.label i = 4
|
||||
.segment Code
|
||||
// __start
|
||||
__start: {
|
||||
jmp __init1
|
||||
// __start::__init1
|
||||
__init1:
|
||||
// [1] i = 0 -- vbuz1=vbuc1
|
||||
lda #0
|
||||
sta.z i
|
||||
// [2] phi from __start::__init1 to __start::@1 [phi:__start::__init1->__start::@1]
|
||||
__b1_from___init1:
|
||||
jmp __b1
|
||||
// __start::@1
|
||||
__b1:
|
||||
// [3] call main
|
||||
// [11] phi from __start::@1 to main [phi:__start::@1->main]
|
||||
main_from___b1:
|
||||
jsr main
|
||||
jmp __breturn
|
||||
// __start::@return
|
||||
__breturn:
|
||||
// [4] return
|
||||
rts
|
||||
}
|
||||
.segment stage
|
||||
// plus
|
||||
// this should give a pragma error during compile, as test is not declared yet.
|
||||
// __register(A) char plus(__zp(2) char a, __register(A) char b)
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 1
|
||||
.const OFFSET_STACK_B = 0
|
||||
.const OFFSET_STACK_RETURN_1 = 1
|
||||
.label a = 2
|
||||
// [5] plus::a#0 = stackidx(char,plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_A,x
|
||||
sta.z a
|
||||
// [6] plus::b#0 = stackidx(char,plus::OFFSET_STACK_B) -- vbuaa=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_B,x
|
||||
// [7] i = ++ i -- vbuz1=_inc_vbuz1
|
||||
inc.z i
|
||||
// [8] plus::return#0 = plus::a#0 + plus::b#0 -- vbuaa=vbuz1_plus_vbuaa
|
||||
clc
|
||||
adc.z a
|
||||
jmp __breturn
|
||||
// plus::@return
|
||||
__breturn:
|
||||
// [9] stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
||||
tsx
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN_1,x
|
||||
// [10] return
|
||||
rts
|
||||
}
|
||||
// main
|
||||
main: {
|
||||
.label a = 3
|
||||
// [12] phi from main to main::@1 [phi:main->main::@1]
|
||||
__b1_from_main:
|
||||
// [12] phi main::a#2 = 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
|
||||
lda #0
|
||||
sta.z a
|
||||
jmp __b1
|
||||
// [12] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
|
||||
__b1_from___b1:
|
||||
// [12] phi main::a#2 = main::a#1 [phi:main::@1->main::@1#0] -- register_copy
|
||||
jmp __b1
|
||||
// main::@1
|
||||
__b1:
|
||||
// [13] main::v#0 = main::a#2 + 1 -- vbuxx=vbuz1_plus_1
|
||||
ldx.z a
|
||||
inx
|
||||
// [14] stackpush(char) = '0' -- _stackpushbyte_=vbuc1
|
||||
lda #'0'
|
||||
pha
|
||||
// [15] stackpush(char) = main::v#0 -- _stackpushbyte_=vbuxx
|
||||
txa
|
||||
pha
|
||||
// [16] callexecute plus -- call_vprc1
|
||||
jsr plus
|
||||
// sideeffect stackpullpadding(1) -- _stackpullpadding_1
|
||||
pla
|
||||
// [18] main::w#0 = stackpull(char) -- vbuaa=_stackpullbyte_
|
||||
pla
|
||||
// [19] main::$2 = main::w#0 + main::a#2 -- vbuaa=vbuaa_plus_vbuz1
|
||||
clc
|
||||
adc.z a
|
||||
// [20] SCREEN[i] = main::$2 -- pbuc1_derefidx_vbuz1=vbuaa
|
||||
ldy.z i
|
||||
sta SCREEN,y
|
||||
// [21] main::a#1 = ++ main::a#2 -- vbuz1=_inc_vbuz1
|
||||
inc.z a
|
||||
// [22] if(main::a#1!=2) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
|
||||
lda #2
|
||||
cmp.z a
|
||||
bne __b1_from___b1
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [23] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp __init1
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Replacing label __b1_from___b1 with __b1
|
||||
Removing instruction __b1_from___init1:
|
||||
Removing instruction main_from___b1:
|
||||
Removing instruction __b1_from___b1:
|
||||
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||
Removing instruction __init1:
|
||||
Removing instruction __b1:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __b1_from_main:
|
||||
Removing instruction __breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
Removing instruction jmp __b1
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
__constant unsigned int STACK_BASE = $103
|
||||
void __start()
|
||||
__loadstore char i // zp[1]:4 105.24999999999999
|
||||
void main()
|
||||
char main::$2 // reg byte a 202.0
|
||||
char main::a
|
||||
char main::a#1 // a zp[1]:3 151.5
|
||||
char main::a#2 // a zp[1]:3 44.888888888888886
|
||||
char main::v
|
||||
char main::v#0 // reg byte x 101.0
|
||||
char main::w
|
||||
char main::w#0 // reg byte a 202.0
|
||||
__stackcall char plus(char a , char b)
|
||||
__constant char plus::OFFSET_STACK_A = 1
|
||||
__constant char plus::OFFSET_STACK_B = 0
|
||||
__constant char plus::OFFSET_STACK_RETURN_1 = 1
|
||||
char plus::a
|
||||
char plus::a#0 // a zp[1]:2 667.3333333333334
|
||||
char plus::b
|
||||
char plus::b#0 // reg byte a 1001.0
|
||||
char plus::return
|
||||
char plus::return#0 // reg byte a 2002.0
|
||||
|
||||
zp[1]:3 [ main::a#2 main::a#1 ]
|
||||
zp[1]:4 [ i ]
|
||||
zp[1]:2 [ plus::a#0 ]
|
||||
reg byte a [ plus::b#0 ]
|
||||
reg byte a [ plus::return#0 ]
|
||||
reg byte x [ main::v#0 ]
|
||||
reg byte a [ main::w#0 ]
|
||||
reg byte a [ main::$2 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 656
|
||||
|
||||
// File Comments
|
||||
// Test a procedure with calling convention stack
|
||||
// A slightly more complex call
|
||||
// Upstart
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
// Global Constants & labels
|
||||
.const STACK_BASE = $103
|
||||
.label SCREEN = $400
|
||||
.label i = 4
|
||||
.segment Code
|
||||
// __start
|
||||
__start: {
|
||||
// __start::__init1
|
||||
// char i = 0
|
||||
// [1] i = 0 -- vbuz1=vbuc1
|
||||
lda #0
|
||||
sta.z i
|
||||
// [2] phi from __start::__init1 to __start::@1 [phi:__start::__init1->__start::@1]
|
||||
// __start::@1
|
||||
// [3] call main
|
||||
// [11] phi from __start::@1 to main [phi:__start::@1->main]
|
||||
jsr main
|
||||
// __start::@return
|
||||
// [4] return
|
||||
rts
|
||||
}
|
||||
.segment stage
|
||||
// plus
|
||||
// this should give a pragma error during compile, as test is not declared yet.
|
||||
// __register(A) char plus(__zp(2) char a, __register(A) char b)
|
||||
plus: {
|
||||
.const OFFSET_STACK_A = 1
|
||||
.const OFFSET_STACK_B = 0
|
||||
.const OFFSET_STACK_RETURN_1 = 1
|
||||
.label a = 2
|
||||
// [5] plus::a#0 = stackidx(char,plus::OFFSET_STACK_A) -- vbuz1=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_A,x
|
||||
sta.z a
|
||||
// [6] plus::b#0 = stackidx(char,plus::OFFSET_STACK_B) -- vbuaa=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_B,x
|
||||
// i++;
|
||||
// [7] i = ++ i -- vbuz1=_inc_vbuz1
|
||||
inc.z i
|
||||
// return a+b;
|
||||
// [8] plus::return#0 = plus::a#0 + plus::b#0 -- vbuaa=vbuz1_plus_vbuaa
|
||||
clc
|
||||
adc.z a
|
||||
// plus::@return
|
||||
// }
|
||||
// [9] stackidx(char,plus::OFFSET_STACK_RETURN_1) = plus::return#0 -- _stackidxbyte_vbuc1=vbuaa
|
||||
tsx
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN_1,x
|
||||
// [10] return
|
||||
rts
|
||||
}
|
||||
// main
|
||||
main: {
|
||||
.label a = 3
|
||||
// [12] phi from main to main::@1 [phi:main->main::@1]
|
||||
// [12] phi main::a#2 = 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
|
||||
lda #0
|
||||
sta.z a
|
||||
// [12] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
|
||||
// [12] phi main::a#2 = main::a#1 [phi:main::@1->main::@1#0] -- register_copy
|
||||
// main::@1
|
||||
__b1:
|
||||
// char v = a+1
|
||||
// [13] main::v#0 = main::a#2 + 1 -- vbuxx=vbuz1_plus_1
|
||||
ldx.z a
|
||||
inx
|
||||
// char w = plus('0', v)
|
||||
// [14] stackpush(char) = '0' -- _stackpushbyte_=vbuc1
|
||||
lda #'0'
|
||||
pha
|
||||
// [15] stackpush(char) = main::v#0 -- _stackpushbyte_=vbuxx
|
||||
txa
|
||||
pha
|
||||
// [16] callexecute plus -- call_vprc1
|
||||
jsr plus
|
||||
// sideeffect stackpullpadding(1) -- _stackpullpadding_1
|
||||
pla
|
||||
// [18] main::w#0 = stackpull(char) -- vbuaa=_stackpullbyte_
|
||||
pla
|
||||
// w+a
|
||||
// [19] main::$2 = main::w#0 + main::a#2 -- vbuaa=vbuaa_plus_vbuz1
|
||||
clc
|
||||
adc.z a
|
||||
// SCREEN[i] = w+a
|
||||
// [20] SCREEN[i] = main::$2 -- pbuc1_derefidx_vbuz1=vbuaa
|
||||
ldy.z i
|
||||
sta SCREEN,y
|
||||
// for(char a:0..1)
|
||||
// [21] main::a#1 = ++ main::a#2 -- vbuz1=_inc_vbuz1
|
||||
inc.z a
|
||||
// [22] if(main::a#1!=2) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
|
||||
lda #2
|
||||
cmp.z a
|
||||
bne __b1
|
||||
// main::@return
|
||||
// }
|
||||
// [23] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
32
src/test/ref/procedure-callingconvention-stack-bank-2.sym
Normal file
32
src/test/ref/procedure-callingconvention-stack-bank-2.sym
Normal file
@ -0,0 +1,32 @@
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
__constant unsigned int STACK_BASE = $103
|
||||
void __start()
|
||||
__loadstore char i // zp[1]:4 105.24999999999999
|
||||
void main()
|
||||
char main::$2 // reg byte a 202.0
|
||||
char main::a
|
||||
char main::a#1 // a zp[1]:3 151.5
|
||||
char main::a#2 // a zp[1]:3 44.888888888888886
|
||||
char main::v
|
||||
char main::v#0 // reg byte x 101.0
|
||||
char main::w
|
||||
char main::w#0 // reg byte a 202.0
|
||||
__stackcall char plus(char a , char b)
|
||||
__constant char plus::OFFSET_STACK_A = 1
|
||||
__constant char plus::OFFSET_STACK_B = 0
|
||||
__constant char plus::OFFSET_STACK_RETURN_1 = 1
|
||||
char plus::a
|
||||
char plus::a#0 // a zp[1]:2 667.3333333333334
|
||||
char plus::b
|
||||
char plus::b#0 // reg byte a 1001.0
|
||||
char plus::return
|
||||
char plus::return#0 // reg byte a 2002.0
|
||||
|
||||
zp[1]:3 [ main::a#2 main::a#1 ]
|
||||
zp[1]:4 [ i ]
|
||||
zp[1]:2 [ plus::a#0 ]
|
||||
reg byte a [ plus::b#0 ]
|
||||
reg byte a [ plus::return#0 ]
|
||||
reg byte x [ main::v#0 ]
|
||||
reg byte a [ main::w#0 ]
|
||||
reg byte a [ main::$2 ]
|
74
src/test/ref/procedure-callingconvention-stack-bank-3.asm
Normal file
74
src/test/ref/procedure-callingconvention-stack-bank-3.asm
Normal file
@ -0,0 +1,74 @@
|
||||
// Test a procedure with calling convention stack
|
||||
// Illustrates live range problem with function variable printother::i and global variable val
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
.label SCREEN = $400
|
||||
.label val = 2
|
||||
.segment Code
|
||||
__start: {
|
||||
// char val = 0
|
||||
lda #0
|
||||
sta.z val
|
||||
jsr main
|
||||
rts
|
||||
}
|
||||
printother: {
|
||||
ldx #0
|
||||
__b1:
|
||||
// (SCREEN+40)[i]++;
|
||||
inc SCREEN+$28,x
|
||||
// for(char i:0..5)
|
||||
inx
|
||||
cpx #6
|
||||
bne __b1
|
||||
// }
|
||||
rts
|
||||
}
|
||||
incval: {
|
||||
// val++;
|
||||
inc.z val
|
||||
// }
|
||||
rts
|
||||
}
|
||||
printval: {
|
||||
// SCREEN[0] = val
|
||||
lda.z val
|
||||
sta SCREEN
|
||||
// }
|
||||
rts
|
||||
}
|
||||
ival: {
|
||||
// incval()
|
||||
jsr incval
|
||||
// }
|
||||
rts
|
||||
}
|
||||
pval: {
|
||||
// printval()
|
||||
jsr printval
|
||||
// }
|
||||
rts
|
||||
}
|
||||
.segment stage
|
||||
main: {
|
||||
ldy #0
|
||||
__b1:
|
||||
// pval()
|
||||
jsr pval
|
||||
// printother()
|
||||
jsr printother
|
||||
// ival()
|
||||
jsr ival
|
||||
// for(char i:0..5)
|
||||
iny
|
||||
cpy #6
|
||||
bne __b1
|
||||
// }
|
||||
rts
|
||||
}
|
79
src/test/ref/procedure-callingconvention-stack-bank-3.cfg
Normal file
79
src/test/ref/procedure-callingconvention-stack-bank-3.cfg
Normal file
@ -0,0 +1,79 @@
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
[0] phi()
|
||||
to:__start::__init1
|
||||
__start::__init1: scope:[__start] from __start
|
||||
[1] val = 0
|
||||
to:__start::@1
|
||||
__start::@1: scope:[__start] from __start::__init1
|
||||
[2] phi()
|
||||
[3] callexecute main
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start::@1
|
||||
[4] return
|
||||
to:@return
|
||||
|
||||
__stackcall void printother()
|
||||
printother: scope:[printother] from
|
||||
[5] phi()
|
||||
to:printother::@1
|
||||
printother::@1: scope:[printother] from printother printother::@1
|
||||
[6] printother::i#2 = phi( printother/0, printother::@1/printother::i#1 )
|
||||
[7] (SCREEN+$28)[printother::i#2] = ++ (SCREEN+$28)[printother::i#2]
|
||||
[8] printother::i#1 = ++ printother::i#2
|
||||
[9] if(printother::i#1!=6) goto printother::@1
|
||||
to:printother::@return
|
||||
printother::@return: scope:[printother] from printother::@1
|
||||
[10] return
|
||||
to:@return
|
||||
|
||||
__stackcall void incval()
|
||||
incval: scope:[incval] from
|
||||
[11] val = ++ val
|
||||
to:incval::@return
|
||||
incval::@return: scope:[incval] from incval
|
||||
[12] return
|
||||
to:@return
|
||||
|
||||
__stackcall void printval()
|
||||
printval: scope:[printval] from
|
||||
[13] *SCREEN = val
|
||||
to:printval::@return
|
||||
printval::@return: scope:[printval] from printval
|
||||
[14] return
|
||||
to:@return
|
||||
|
||||
__stackcall void ival()
|
||||
ival: scope:[ival] from
|
||||
[15] phi()
|
||||
[16] callexecute incval
|
||||
to:ival::@return
|
||||
ival::@return: scope:[ival] from ival
|
||||
[17] return
|
||||
to:@return
|
||||
|
||||
__stackcall void pval()
|
||||
pval: scope:[pval] from
|
||||
[18] phi()
|
||||
[19] callexecute printval
|
||||
to:pval::@return
|
||||
pval::@return: scope:[pval] from pval
|
||||
[20] return
|
||||
to:@return
|
||||
|
||||
__stackcall void main()
|
||||
main: scope:[main] from
|
||||
[21] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@1
|
||||
[22] main::i#2 = phi( main/0, main::@1/main::i#1 )
|
||||
[23] callexecute pval
|
||||
[24] callexecute printother
|
||||
[25] callexecute ival
|
||||
[26] main::i#1 = ++ main::i#2
|
||||
[27] if(main::i#1!=6) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[28] return
|
||||
to:@return
|
644
src/test/ref/procedure-callingconvention-stack-bank-3.log
Normal file
644
src/test/ref/procedure-callingconvention-stack-bank-3.log
Normal file
@ -0,0 +1,644 @@
|
||||
Loading link script "procedure-callingconvention-stack-bank.ld"
|
||||
Converting variable modified inside __stackcall procedure main() to load/store val
|
||||
Inlined call call __init
|
||||
Calling convention __stackcall adding prepare/execute/finalize for call pval
|
||||
Calling convention __stackcall adding prepare/execute/finalize for call printother
|
||||
Calling convention __stackcall adding prepare/execute/finalize for call ival
|
||||
Calling convention __stackcall adding prepare/execute/finalize for call printval
|
||||
Calling convention __stackcall adding prepare/execute/finalize for call incval
|
||||
Calling convention __stackcall adding prepare/execute/finalize for call main
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
__stackcall void main()
|
||||
main: scope:[main] from
|
||||
main::i#0 = 0
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@1
|
||||
main::i#2 = phi( main/main::i#0, main::@1/main::i#1 )
|
||||
callexecute pval
|
||||
callexecute printother
|
||||
callexecute ival
|
||||
main::i#1 = main::i#2 + rangenext(0,5)
|
||||
main::$3 = main::i#1 != rangelast(0,5)
|
||||
if(main::$3) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
__stackcall void pval()
|
||||
pval: scope:[pval] from
|
||||
callexecute printval
|
||||
to:pval::@return
|
||||
pval::@return: scope:[pval] from pval
|
||||
return
|
||||
to:@return
|
||||
|
||||
__stackcall void ival()
|
||||
ival: scope:[ival] from
|
||||
callexecute incval
|
||||
to:ival::@return
|
||||
ival::@return: scope:[ival] from ival
|
||||
return
|
||||
to:@return
|
||||
|
||||
__stackcall void printval()
|
||||
printval: scope:[printval] from
|
||||
SCREEN[0] = val
|
||||
to:printval::@return
|
||||
printval::@return: scope:[printval] from printval
|
||||
return
|
||||
to:@return
|
||||
|
||||
__stackcall void incval()
|
||||
incval: scope:[incval] from
|
||||
val = ++ val
|
||||
to:incval::@return
|
||||
incval::@return: scope:[incval] from incval
|
||||
return
|
||||
to:@return
|
||||
|
||||
__stackcall void printother()
|
||||
printother: scope:[printother] from
|
||||
printother::i#0 = 0
|
||||
to:printother::@1
|
||||
printother::@1: scope:[printother] from printother printother::@1
|
||||
printother::i#2 = phi( printother/printother::i#0, printother::@1/printother::i#1 )
|
||||
(SCREEN+$28)[printother::i#2] = ++ (SCREEN+$28)[printother::i#2]
|
||||
printother::i#1 = printother::i#2 + rangenext(0,5)
|
||||
printother::$1 = printother::i#1 != rangelast(0,5)
|
||||
if(printother::$1) goto printother::@1
|
||||
to:printother::@return
|
||||
printother::@return: scope:[printother] from printother::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
to:__start::__init1
|
||||
__start::__init1: scope:[__start] from __start
|
||||
val = 0
|
||||
to:__start::@1
|
||||
__start::@1: scope:[__start] from __start::__init1
|
||||
callexecute main
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
__constant char * const SCREEN = (char *)$400
|
||||
void __start()
|
||||
__stackcall void incval()
|
||||
__stackcall void ival()
|
||||
__stackcall void main()
|
||||
bool main::$3
|
||||
char main::i
|
||||
char main::i#0
|
||||
char main::i#1
|
||||
char main::i#2
|
||||
__stackcall void printother()
|
||||
bool printother::$1
|
||||
char printother::i
|
||||
char printother::i#0
|
||||
char printother::i#1
|
||||
char printother::i#2
|
||||
__stackcall void printval()
|
||||
__stackcall void pval()
|
||||
__loadstore char val
|
||||
|
||||
Adding number conversion cast (unumber) 0 in SCREEN[0] = val
|
||||
Adding number conversion cast (unumber) $28 in (SCREEN+$28)[printother::i#2] = ++ (SCREEN+$28)[printother::i#2]
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Simplifying constant pointer cast (char *) 1024
|
||||
Simplifying constant integer cast 0
|
||||
Simplifying constant integer cast $28
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (char) 0
|
||||
Finalized unsigned number type (char) $28
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Simple Condition main::$3 [7] if(main::i#1!=rangelast(0,5)) goto main::@1
|
||||
Simple Condition printother::$1 [22] if(printother::i#1!=rangelast(0,5)) goto printother::@1
|
||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||
Constant main::i#0 = 0
|
||||
Constant printother::i#0 = 0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Resolved ranged next value [5] main::i#1 = ++ main::i#2 to ++
|
||||
Resolved ranged comparison value [7] if(main::i#1!=rangelast(0,5)) goto main::@1 to 6
|
||||
Resolved ranged next value [20] printother::i#1 = ++ printother::i#2 to ++
|
||||
Resolved ranged comparison value [22] if(printother::i#1!=rangelast(0,5)) goto printother::@1 to 6
|
||||
Simplifying expression containing zero SCREEN in [13] SCREEN[0] = val
|
||||
Successful SSA optimization PassNSimplifyExpressionWithZero
|
||||
Adding number conversion cast (unumber) 6 in if(main::i#1!=6) goto main::@1
|
||||
Adding number conversion cast (unumber) 6 in if(printother::i#1!=6) goto printother::@1
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Simplifying constant integer cast 6
|
||||
Simplifying constant integer cast 6
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (char) 6
|
||||
Finalized unsigned number type (char) 6
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Inlining constant with var siblings main::i#0
|
||||
Inlining constant with var siblings printother::i#0
|
||||
Constant inlined main::i#0 = 0
|
||||
Constant inlined printother::i#0 = 0
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Added new block during phi lifting main::@2(between main::@1 and main::@1)
|
||||
Added new block during phi lifting printother::@2(between printother::@1 and printother::@1)
|
||||
Adding NOP phi() at start of __start
|
||||
Adding NOP phi() at start of __start::@1
|
||||
Adding NOP phi() at start of printother
|
||||
Adding NOP phi() at start of ival
|
||||
Adding NOP phi() at start of pval
|
||||
Adding NOP phi() at start of main
|
||||
CALL GRAPH
|
||||
Calls in [__start] to main:3
|
||||
Calls in [ival] to incval:17
|
||||
Calls in [pval] to printval:20
|
||||
Calls in [main] to pval:24 printother:25 ival:26
|
||||
|
||||
Created 2 initial phi equivalence classes
|
||||
Coalesced [11] printother::i#3 = printother::i#1
|
||||
Coalesced [30] main::i#3 = main::i#1
|
||||
Coalesced down to 2 phi equivalence classes
|
||||
Culled Empty Block label printother::@2
|
||||
Culled Empty Block label main::@2
|
||||
Adding NOP phi() at start of __start
|
||||
Adding NOP phi() at start of __start::@1
|
||||
Adding NOP phi() at start of printother
|
||||
Adding NOP phi() at start of ival
|
||||
Adding NOP phi() at start of pval
|
||||
Adding NOP phi() at start of main
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
[0] phi()
|
||||
to:__start::__init1
|
||||
__start::__init1: scope:[__start] from __start
|
||||
[1] val = 0
|
||||
to:__start::@1
|
||||
__start::@1: scope:[__start] from __start::__init1
|
||||
[2] phi()
|
||||
[3] callexecute main
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start::@1
|
||||
[4] return
|
||||
to:@return
|
||||
|
||||
__stackcall void printother()
|
||||
printother: scope:[printother] from
|
||||
[5] phi()
|
||||
to:printother::@1
|
||||
printother::@1: scope:[printother] from printother printother::@1
|
||||
[6] printother::i#2 = phi( printother/0, printother::@1/printother::i#1 )
|
||||
[7] (SCREEN+$28)[printother::i#2] = ++ (SCREEN+$28)[printother::i#2]
|
||||
[8] printother::i#1 = ++ printother::i#2
|
||||
[9] if(printother::i#1!=6) goto printother::@1
|
||||
to:printother::@return
|
||||
printother::@return: scope:[printother] from printother::@1
|
||||
[10] return
|
||||
to:@return
|
||||
|
||||
__stackcall void incval()
|
||||
incval: scope:[incval] from
|
||||
[11] val = ++ val
|
||||
to:incval::@return
|
||||
incval::@return: scope:[incval] from incval
|
||||
[12] return
|
||||
to:@return
|
||||
|
||||
__stackcall void printval()
|
||||
printval: scope:[printval] from
|
||||
[13] *SCREEN = val
|
||||
to:printval::@return
|
||||
printval::@return: scope:[printval] from printval
|
||||
[14] return
|
||||
to:@return
|
||||
|
||||
__stackcall void ival()
|
||||
ival: scope:[ival] from
|
||||
[15] phi()
|
||||
[16] callexecute incval
|
||||
to:ival::@return
|
||||
ival::@return: scope:[ival] from ival
|
||||
[17] return
|
||||
to:@return
|
||||
|
||||
__stackcall void pval()
|
||||
pval: scope:[pval] from
|
||||
[18] phi()
|
||||
[19] callexecute printval
|
||||
to:pval::@return
|
||||
pval::@return: scope:[pval] from pval
|
||||
[20] return
|
||||
to:@return
|
||||
|
||||
__stackcall void main()
|
||||
main: scope:[main] from
|
||||
[21] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@1
|
||||
[22] main::i#2 = phi( main/0, main::@1/main::i#1 )
|
||||
[23] callexecute pval
|
||||
[24] callexecute printother
|
||||
[25] callexecute ival
|
||||
[26] main::i#1 = ++ main::i#2
|
||||
[27] if(main::i#1!=6) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[28] return
|
||||
to:@return
|
||||
|
||||
null depth in calling loop Loop head: main::@1 tails: main::@1 blocks: main::@1 in scope printother
|
||||
null depth in calling loop Loop head: main::@1 tails: main::@1 blocks: main::@1 in scope ival
|
||||
null depth in calling loop Loop head: main::@1 tails: main::@1 blocks: main::@1 in scope pval
|
||||
null depth in calling loop Loop head: main::@1 tails: main::@1 blocks: main::@1 in scope ival
|
||||
null depth in calling loop Loop head: main::@1 tails: main::@1 blocks: main::@1 in scope pval
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
void __start()
|
||||
__stackcall void incval()
|
||||
__stackcall void ival()
|
||||
__stackcall void main()
|
||||
char main::i
|
||||
char main::i#1 // 151.5
|
||||
char main::i#2 // 50.5
|
||||
__stackcall void printother()
|
||||
char printother::i
|
||||
char printother::i#1 // 15001.5
|
||||
char printother::i#2 // 20002.0
|
||||
__stackcall void printval()
|
||||
__stackcall void pval()
|
||||
__loadstore char val // 1579.2105263157896
|
||||
|
||||
Initial phi equivalence classes
|
||||
[ printother::i#2 printother::i#1 ]
|
||||
[ main::i#2 main::i#1 ]
|
||||
Added variable val to live range equivalence class [ val ]
|
||||
Complete equivalence classes
|
||||
[ printother::i#2 printother::i#1 ]
|
||||
[ main::i#2 main::i#1 ]
|
||||
[ val ]
|
||||
Allocated zp[1]:2 [ printother::i#2 printother::i#1 ]
|
||||
Allocated zp[1]:3 [ val ]
|
||||
Allocated zp[1]:4 [ main::i#2 main::i#1 ]
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [1] val = 0 [ val ] ( [ val ] { } ) always clobbers reg byte a
|
||||
Statement [13] *SCREEN = val [ val ] ( main:3::pval:23::printval:19 [ main::i#2 val ] { } ) always clobbers reg byte a
|
||||
Removing always clobbered register reg byte a as potential for zp[1]:4 [ main::i#2 main::i#1 ]
|
||||
Statement [1] val = 0 [ val ] ( [ val ] { } ) always clobbers reg byte a
|
||||
Statement [13] *SCREEN = val [ val ] ( main:3::pval:23::printval:19 [ main::i#2 val ] { } ) always clobbers reg byte a
|
||||
Potential registers zp[1]:2 [ printother::i#2 printother::i#1 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp[1]:4 [ main::i#2 main::i#1 ] : zp[1]:4 , reg byte x , reg byte y ,
|
||||
Potential registers zp[1]:3 [ val ] : zp[1]:3 ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [printother] 35,003.5: zp[1]:2 [ printother::i#2 printother::i#1 ]
|
||||
Uplift Scope [] 1,579.21: zp[1]:3 [ val ]
|
||||
Uplift Scope [main] 202: zp[1]:4 [ main::i#2 main::i#1 ]
|
||||
Uplift Scope [pval]
|
||||
Uplift Scope [ival]
|
||||
Uplift Scope [printval]
|
||||
Uplift Scope [incval]
|
||||
Uplift Scope [__start]
|
||||
|
||||
Uplifting [printother] best 815 combination reg byte x [ printother::i#2 printother::i#1 ]
|
||||
Uplifting [] best 815 combination zp[1]:3 [ val ]
|
||||
Uplifting [main] best 725 combination reg byte y [ main::i#2 main::i#1 ]
|
||||
Uplifting [pval] best 725 combination
|
||||
Uplifting [ival] best 725 combination
|
||||
Uplifting [printval] best 725 combination
|
||||
Uplifting [incval] best 725 combination
|
||||
Uplifting [__start] best 725 combination
|
||||
Attempting to uplift remaining variables inzp[1]:3 [ val ]
|
||||
Uplifting [] best 725 combination zp[1]:3 [ val ]
|
||||
Allocated (was zp[1]:3) zp[1]:2 [ val ]
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Test a procedure with calling convention stack
|
||||
// Illustrates live range problem with function variable printother::i and global variable val
|
||||
// Upstart
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
// Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
.label val = 2
|
||||
.segment Code
|
||||
// __start
|
||||
__start: {
|
||||
jmp __init1
|
||||
// __start::__init1
|
||||
__init1:
|
||||
// [1] val = 0 -- vbuz1=vbuc1
|
||||
lda #0
|
||||
sta.z val
|
||||
// [2] phi from __start::__init1 to __start::@1 [phi:__start::__init1->__start::@1]
|
||||
__b1_from___init1:
|
||||
jmp __b1
|
||||
// __start::@1
|
||||
__b1:
|
||||
// [3] callexecute main -- call_vprc1
|
||||
jsr main
|
||||
jmp __breturn
|
||||
// __start::@return
|
||||
__breturn:
|
||||
// [4] return
|
||||
rts
|
||||
}
|
||||
// printother
|
||||
printother: {
|
||||
// [6] phi from printother to printother::@1 [phi:printother->printother::@1]
|
||||
__b1_from_printother:
|
||||
// [6] phi printother::i#2 = 0 [phi:printother->printother::@1#0] -- vbuxx=vbuc1
|
||||
ldx #0
|
||||
jmp __b1
|
||||
// [6] phi from printother::@1 to printother::@1 [phi:printother::@1->printother::@1]
|
||||
__b1_from___b1:
|
||||
// [6] phi printother::i#2 = printother::i#1 [phi:printother::@1->printother::@1#0] -- register_copy
|
||||
jmp __b1
|
||||
// printother::@1
|
||||
__b1:
|
||||
// [7] (SCREEN+$28)[printother::i#2] = ++ (SCREEN+$28)[printother::i#2] -- pbuc1_derefidx_vbuxx=_inc_pbuc1_derefidx_vbuxx
|
||||
inc SCREEN+$28,x
|
||||
// [8] printother::i#1 = ++ printother::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
// [9] if(printother::i#1!=6) goto printother::@1 -- vbuxx_neq_vbuc1_then_la1
|
||||
cpx #6
|
||||
bne __b1_from___b1
|
||||
jmp __breturn
|
||||
// printother::@return
|
||||
__breturn:
|
||||
// [10] return
|
||||
rts
|
||||
}
|
||||
// incval
|
||||
incval: {
|
||||
// [11] val = ++ val -- vbuz1=_inc_vbuz1
|
||||
inc.z val
|
||||
jmp __breturn
|
||||
// incval::@return
|
||||
__breturn:
|
||||
// [12] return
|
||||
rts
|
||||
}
|
||||
// printval
|
||||
printval: {
|
||||
// [13] *SCREEN = val -- _deref_pbuc1=vbuz1
|
||||
lda.z val
|
||||
sta SCREEN
|
||||
jmp __breturn
|
||||
// printval::@return
|
||||
__breturn:
|
||||
// [14] return
|
||||
rts
|
||||
}
|
||||
// ival
|
||||
ival: {
|
||||
// [16] callexecute incval -- call_vprc1
|
||||
jsr incval
|
||||
jmp __breturn
|
||||
// ival::@return
|
||||
__breturn:
|
||||
// [17] return
|
||||
rts
|
||||
}
|
||||
// pval
|
||||
pval: {
|
||||
// [19] callexecute printval -- call_vprc1
|
||||
jsr printval
|
||||
jmp __breturn
|
||||
// pval::@return
|
||||
__breturn:
|
||||
// [20] return
|
||||
rts
|
||||
}
|
||||
.segment stage
|
||||
// main
|
||||
main: {
|
||||
// [22] phi from main to main::@1 [phi:main->main::@1]
|
||||
__b1_from_main:
|
||||
// [22] phi main::i#2 = 0 [phi:main->main::@1#0] -- vbuyy=vbuc1
|
||||
ldy #0
|
||||
jmp __b1
|
||||
// [22] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
|
||||
__b1_from___b1:
|
||||
// [22] phi main::i#2 = main::i#1 [phi:main::@1->main::@1#0] -- register_copy
|
||||
jmp __b1
|
||||
// main::@1
|
||||
__b1:
|
||||
// [23] callexecute pval -- call_vprc1
|
||||
jsr pval
|
||||
// [24] callexecute printother -- call_vprc1
|
||||
jsr printother
|
||||
// [25] callexecute ival -- call_vprc1
|
||||
jsr ival
|
||||
// [26] main::i#1 = ++ main::i#2 -- vbuyy=_inc_vbuyy
|
||||
iny
|
||||
// [27] if(main::i#1!=6) goto main::@1 -- vbuyy_neq_vbuc1_then_la1
|
||||
cpy #6
|
||||
bne __b1_from___b1
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [28] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp __init1
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Replacing label __b1_from___b1 with __b1
|
||||
Replacing label __b1_from___b1 with __b1
|
||||
Removing instruction __b1_from___init1:
|
||||
Removing instruction __b1_from___b1:
|
||||
Removing instruction __b1_from___b1:
|
||||
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||
Removing instruction __init1:
|
||||
Removing instruction __b1:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __b1_from_printother:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __b1_from_main:
|
||||
Removing instruction __breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __b1
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
void __start()
|
||||
__stackcall void incval()
|
||||
__stackcall void ival()
|
||||
__stackcall void main()
|
||||
char main::i
|
||||
char main::i#1 // reg byte y 151.5
|
||||
char main::i#2 // reg byte y 50.5
|
||||
__stackcall void printother()
|
||||
char printother::i
|
||||
char printother::i#1 // reg byte x 15001.5
|
||||
char printother::i#2 // reg byte x 20002.0
|
||||
__stackcall void printval()
|
||||
__stackcall void pval()
|
||||
__loadstore char val // zp[1]:2 1579.2105263157896
|
||||
|
||||
reg byte x [ printother::i#2 printother::i#1 ]
|
||||
reg byte y [ main::i#2 main::i#1 ]
|
||||
zp[1]:2 [ val ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 497
|
||||
|
||||
// File Comments
|
||||
// Test a procedure with calling convention stack
|
||||
// Illustrates live range problem with function variable printother::i and global variable val
|
||||
// Upstart
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
// Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
.label val = 2
|
||||
.segment Code
|
||||
// __start
|
||||
__start: {
|
||||
// __start::__init1
|
||||
// char val = 0
|
||||
// [1] val = 0 -- vbuz1=vbuc1
|
||||
lda #0
|
||||
sta.z val
|
||||
// [2] phi from __start::__init1 to __start::@1 [phi:__start::__init1->__start::@1]
|
||||
// __start::@1
|
||||
// [3] callexecute main -- call_vprc1
|
||||
jsr main
|
||||
// __start::@return
|
||||
// [4] return
|
||||
rts
|
||||
}
|
||||
// printother
|
||||
printother: {
|
||||
// [6] phi from printother to printother::@1 [phi:printother->printother::@1]
|
||||
// [6] phi printother::i#2 = 0 [phi:printother->printother::@1#0] -- vbuxx=vbuc1
|
||||
ldx #0
|
||||
// [6] phi from printother::@1 to printother::@1 [phi:printother::@1->printother::@1]
|
||||
// [6] phi printother::i#2 = printother::i#1 [phi:printother::@1->printother::@1#0] -- register_copy
|
||||
// printother::@1
|
||||
__b1:
|
||||
// (SCREEN+40)[i]++;
|
||||
// [7] (SCREEN+$28)[printother::i#2] = ++ (SCREEN+$28)[printother::i#2] -- pbuc1_derefidx_vbuxx=_inc_pbuc1_derefidx_vbuxx
|
||||
inc SCREEN+$28,x
|
||||
// for(char i:0..5)
|
||||
// [8] printother::i#1 = ++ printother::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
// [9] if(printother::i#1!=6) goto printother::@1 -- vbuxx_neq_vbuc1_then_la1
|
||||
cpx #6
|
||||
bne __b1
|
||||
// printother::@return
|
||||
// }
|
||||
// [10] return
|
||||
rts
|
||||
}
|
||||
// incval
|
||||
incval: {
|
||||
// val++;
|
||||
// [11] val = ++ val -- vbuz1=_inc_vbuz1
|
||||
inc.z val
|
||||
// incval::@return
|
||||
// }
|
||||
// [12] return
|
||||
rts
|
||||
}
|
||||
// printval
|
||||
printval: {
|
||||
// SCREEN[0] = val
|
||||
// [13] *SCREEN = val -- _deref_pbuc1=vbuz1
|
||||
lda.z val
|
||||
sta SCREEN
|
||||
// printval::@return
|
||||
// }
|
||||
// [14] return
|
||||
rts
|
||||
}
|
||||
// ival
|
||||
ival: {
|
||||
// incval()
|
||||
// [16] callexecute incval -- call_vprc1
|
||||
jsr incval
|
||||
// ival::@return
|
||||
// }
|
||||
// [17] return
|
||||
rts
|
||||
}
|
||||
// pval
|
||||
pval: {
|
||||
// printval()
|
||||
// [19] callexecute printval -- call_vprc1
|
||||
jsr printval
|
||||
// pval::@return
|
||||
// }
|
||||
// [20] return
|
||||
rts
|
||||
}
|
||||
.segment stage
|
||||
// main
|
||||
main: {
|
||||
// [22] phi from main to main::@1 [phi:main->main::@1]
|
||||
// [22] phi main::i#2 = 0 [phi:main->main::@1#0] -- vbuyy=vbuc1
|
||||
ldy #0
|
||||
// [22] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
|
||||
// [22] phi main::i#2 = main::i#1 [phi:main::@1->main::@1#0] -- register_copy
|
||||
// main::@1
|
||||
__b1:
|
||||
// pval()
|
||||
// [23] callexecute pval -- call_vprc1
|
||||
jsr pval
|
||||
// printother()
|
||||
// [24] callexecute printother -- call_vprc1
|
||||
jsr printother
|
||||
// ival()
|
||||
// [25] callexecute ival -- call_vprc1
|
||||
jsr ival
|
||||
// for(char i:0..5)
|
||||
// [26] main::i#1 = ++ main::i#2 -- vbuyy=_inc_vbuyy
|
||||
iny
|
||||
// [27] if(main::i#1!=6) goto main::@1 -- vbuyy_neq_vbuc1_then_la1
|
||||
cpy #6
|
||||
bne __b1
|
||||
// main::@return
|
||||
// }
|
||||
// [28] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
19
src/test/ref/procedure-callingconvention-stack-bank-3.sym
Normal file
19
src/test/ref/procedure-callingconvention-stack-bank-3.sym
Normal file
@ -0,0 +1,19 @@
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
void __start()
|
||||
__stackcall void incval()
|
||||
__stackcall void ival()
|
||||
__stackcall void main()
|
||||
char main::i
|
||||
char main::i#1 // reg byte y 151.5
|
||||
char main::i#2 // reg byte y 50.5
|
||||
__stackcall void printother()
|
||||
char printother::i
|
||||
char printother::i#1 // reg byte x 15001.5
|
||||
char printother::i#2 // reg byte x 20002.0
|
||||
__stackcall void printval()
|
||||
__stackcall void pval()
|
||||
__loadstore char val // zp[1]:2 1579.2105263157896
|
||||
|
||||
reg byte x [ printother::i#2 printother::i#1 ]
|
||||
reg byte y [ main::i#2 main::i#1 ]
|
||||
zp[1]:2 [ val ]
|
111
src/test/ref/procedure-callingconvention-stack-bank-4.asm
Normal file
111
src/test/ref/procedure-callingconvention-stack-bank-4.asm
Normal file
@ -0,0 +1,111 @@
|
||||
// Test a procedure with calling convention stack
|
||||
// Returning and passing struct values
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
.const OFFSET_STRUCT_POINT_Y = 1
|
||||
.const SIZEOF_STRUCT_POINT = 2
|
||||
.const STACK_BASE = $103
|
||||
.label SCREEN = $400
|
||||
.label idx = 4
|
||||
.segment Code
|
||||
__start: {
|
||||
// char idx = 0
|
||||
lda #0
|
||||
sta.z idx
|
||||
jsr main
|
||||
rts
|
||||
}
|
||||
.segment stage
|
||||
// void print(__zp(2) struct Point p)
|
||||
print: {
|
||||
.const OFFSET_STACK_P = 0
|
||||
.label p = 2
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_P,x
|
||||
sta.z p
|
||||
lda STACK_BASE+OFFSET_STACK_P+1,x
|
||||
sta.z p+1
|
||||
// SCREEN[idx++] = p.x
|
||||
lda.z p
|
||||
ldy.z idx
|
||||
sta SCREEN,y
|
||||
// SCREEN[idx++] = p.x;
|
||||
inc.z idx
|
||||
// SCREEN[idx++] = p.y
|
||||
lda.z p+OFFSET_STRUCT_POINT_Y
|
||||
ldy.z idx
|
||||
sta SCREEN,y
|
||||
// SCREEN[idx++] = p.y;
|
||||
inc.z idx
|
||||
// }
|
||||
rts
|
||||
}
|
||||
// __zp(6) struct Point get(__register(X) char i)
|
||||
get: {
|
||||
.const OFFSET_STACK_I = 0
|
||||
.const OFFSET_STACK_RETURN_0 = 0
|
||||
.label return = 6
|
||||
.label p = 8
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_I,x
|
||||
tax
|
||||
// i/2
|
||||
txa
|
||||
lsr
|
||||
// struct Point p = { i, i/2 }
|
||||
stx.z p
|
||||
sta.z p+OFFSET_STRUCT_POINT_Y
|
||||
// return p;
|
||||
ldy #SIZEOF_STRUCT_POINT
|
||||
!:
|
||||
lda p-1,y
|
||||
sta return-1,y
|
||||
dey
|
||||
bne !-
|
||||
// }
|
||||
tsx
|
||||
lda.z return
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN_0,x
|
||||
lda.z return+1
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN_0+1,x
|
||||
rts
|
||||
}
|
||||
main: {
|
||||
.label p = 2
|
||||
.label i = 5
|
||||
lda #0
|
||||
sta.z i
|
||||
__b1:
|
||||
// for(char i=0;i<5;i++)
|
||||
lda.z i
|
||||
cmp #5
|
||||
bcc __b2
|
||||
// }
|
||||
rts
|
||||
__b2:
|
||||
// struct Point p = get(i)
|
||||
lda.z i
|
||||
pha
|
||||
pha
|
||||
jsr get
|
||||
pla
|
||||
sta.z p
|
||||
pla
|
||||
sta.z p+1
|
||||
// print(p)
|
||||
pha
|
||||
lda.z p
|
||||
pha
|
||||
jsr print
|
||||
pla
|
||||
pla
|
||||
// for(char i=0;i<5;i++)
|
||||
inc.z i
|
||||
jmp __b1
|
||||
}
|
62
src/test/ref/procedure-callingconvention-stack-bank-4.cfg
Normal file
62
src/test/ref/procedure-callingconvention-stack-bank-4.cfg
Normal file
@ -0,0 +1,62 @@
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
[0] phi()
|
||||
to:__start::__init1
|
||||
__start::__init1: scope:[__start] from __start
|
||||
[1] idx = 0
|
||||
to:__start::@1
|
||||
__start::@1: scope:[__start] from __start::__init1
|
||||
[2] phi()
|
||||
[3] callexecute main
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start::@1
|
||||
[4] return
|
||||
to:@return
|
||||
|
||||
__stackcall void print(struct Point p)
|
||||
print: scope:[print] from
|
||||
[5] print::p = stackidx(struct Point,print::OFFSET_STACK_P)
|
||||
[6] SCREEN[idx] = *((char *)&print::p)
|
||||
[7] idx = ++ idx
|
||||
[8] SCREEN[idx] = *((char *)&print::p+OFFSET_STRUCT_POINT_Y)
|
||||
[9] idx = ++ idx
|
||||
to:print::@return
|
||||
print::@return: scope:[print] from print
|
||||
[10] return
|
||||
to:@return
|
||||
|
||||
__stackcall struct Point get(char i)
|
||||
get: scope:[get] from
|
||||
[11] get::i#0 = stackidx(char,get::OFFSET_STACK_I)
|
||||
[12] get::$0 = get::i#0 >> 1
|
||||
[13] *((char *)&get::p) = get::i#0
|
||||
[14] *((char *)&get::p+OFFSET_STRUCT_POINT_Y) = get::$0
|
||||
[15] *(&get::return) = memcpy(*(&get::p), struct Point, SIZEOF_STRUCT_POINT)
|
||||
to:get::@return
|
||||
get::@return: scope:[get] from get
|
||||
[16] stackidx(struct Point,get::OFFSET_STACK_RETURN_0) = get::return
|
||||
[17] return
|
||||
to:@return
|
||||
|
||||
__stackcall void main()
|
||||
main: scope:[main] from
|
||||
[18] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@2
|
||||
[19] main::i#2 = phi( main/0, main::@2/main::i#1 )
|
||||
[20] if(main::i#2<5) goto main::@2
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[21] return
|
||||
to:@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
[22] stackpush(char) = main::i#2
|
||||
sideeffect stackpushpadding(1)
|
||||
[24] callexecute get
|
||||
[25] main::p = stackpull(struct Point)
|
||||
[26] stackpush(struct Point) = main::p
|
||||
[27] callexecute print
|
||||
sideeffect stackpullpadding(2)
|
||||
[29] main::i#1 = ++ main::i#2
|
||||
to:main::@1
|
710
src/test/ref/procedure-callingconvention-stack-bank-4.log
Normal file
710
src/test/ref/procedure-callingconvention-stack-bank-4.log
Normal file
@ -0,0 +1,710 @@
|
||||
Loading link script "procedure-callingconvention-stack-bank.ld"
|
||||
Converting variable modified inside __stackcall procedure main() to load/store idx
|
||||
Adding parameter assignment in __stackcall procedure get::i = param(get::i)
|
||||
Adding parameter assignment in __stackcall procedure print::p = param(print::p)
|
||||
Inlined call call __init
|
||||
Eliminating unused variable with no statement main::$1
|
||||
Calling convention __stackcall adding prepare/execute/finalize for main::p = call get(main::i)
|
||||
Calling convention __stackcall adding prepare/execute/finalize for call print(main::p)
|
||||
Calling convention __stackcall adding prepare/execute/finalize for call main
|
||||
Calling convention STACK_CALL replacing param(get::i) with stackidx(char,get::OFFSET_STACK_I)
|
||||
Calling convention STACK_CALL replacing param(print::p) with stackidx(struct Point,print::OFFSET_STACK_P)
|
||||
Calling convention STACK_CALL adding stack return stackidx(struct Point,get::OFFSET_STACK_RETURN_0) = get::return
|
||||
Calling convention STACK_CALL adding stack pull main::p = stackpull(struct Point)
|
||||
Calling convention STACK_CALL adding stack push stackpush(char) = main::i
|
||||
Calling convention STACK_CALL adding stack push stackpush(struct Point) = main::p
|
||||
Removing C-classic struct-unwound assignment get::p = struct-unwound {*((char *)&get::p+OFFSET_STRUCT_POINT_X), *((char *)&get::p+OFFSET_STRUCT_POINT_Y)}
|
||||
Removing C-classic struct-unwound assignment get::return = struct-unwound {*(&get::return)}
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
__stackcall void main()
|
||||
main: scope:[main] from
|
||||
main::i#0 = 0
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@2
|
||||
main::i#2 = phi( main/main::i#0, main::@2/main::i#1 )
|
||||
main::$0 = main::i#2 < 5
|
||||
if(main::$0) goto main::@2
|
||||
to:main::@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
main::i#3 = phi( main::@1/main::i#2 )
|
||||
stackpush(char) = main::i#3
|
||||
sideeffect stackpushpadding(1)
|
||||
callexecute get
|
||||
main::p = stackpull(struct Point)
|
||||
stackpush(struct Point) = main::p
|
||||
callexecute print
|
||||
sideeffect stackpullpadding(2)
|
||||
main::i#1 = ++ main::i#3
|
||||
to:main::@1
|
||||
main::@return: scope:[main] from main::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
__stackcall struct Point get(char i)
|
||||
get: scope:[get] from
|
||||
get::i#0 = stackidx(char,get::OFFSET_STACK_I)
|
||||
get::$0 = get::i#0 / 2
|
||||
*((char *)&get::p+OFFSET_STRUCT_POINT_X) = get::i#0
|
||||
*((char *)&get::p+OFFSET_STRUCT_POINT_Y) = get::$0
|
||||
*(&get::return) = memcpy(*(&get::p), struct Point, SIZEOF_STRUCT_POINT)
|
||||
to:get::@return
|
||||
get::@return: scope:[get] from get
|
||||
stackidx(struct Point,get::OFFSET_STACK_RETURN_0) = get::return
|
||||
return
|
||||
to:@return
|
||||
|
||||
__stackcall void print(struct Point p)
|
||||
print: scope:[print] from
|
||||
print::p = stackidx(struct Point,print::OFFSET_STACK_P)
|
||||
SCREEN[idx] = *((char *)&print::p+OFFSET_STRUCT_POINT_X)
|
||||
idx = ++ idx
|
||||
SCREEN[idx] = *((char *)&print::p+OFFSET_STRUCT_POINT_Y)
|
||||
idx = ++ idx
|
||||
to:print::@return
|
||||
print::@return: scope:[print] from print
|
||||
return
|
||||
to:@return
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
to:__start::__init1
|
||||
__start::__init1: scope:[__start] from __start
|
||||
idx = 0
|
||||
to:__start::@1
|
||||
__start::@1: scope:[__start] from __start::__init1
|
||||
callexecute main
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
__constant char OFFSET_STRUCT_POINT_X = 0
|
||||
__constant char OFFSET_STRUCT_POINT_Y = 1
|
||||
__constant char * const SCREEN = (char *)$400
|
||||
__constant char SIZEOF_STRUCT_POINT = 2
|
||||
__constant unsigned int STACK_BASE = $103
|
||||
void __start()
|
||||
__stackcall struct Point get(char i)
|
||||
number get::$0
|
||||
__constant char get::OFFSET_STACK_I = 0
|
||||
__constant char get::OFFSET_STACK_RETURN_0 = 0
|
||||
char get::i
|
||||
char get::i#0
|
||||
__loadstore struct Point get::p
|
||||
__loadstore struct Point get::return
|
||||
__loadstore char idx
|
||||
__stackcall void main()
|
||||
bool main::$0
|
||||
char main::i
|
||||
char main::i#0
|
||||
char main::i#1
|
||||
char main::i#2
|
||||
char main::i#3
|
||||
__loadstore struct Point main::p
|
||||
__stackcall void print(struct Point p)
|
||||
__constant char print::OFFSET_STACK_P = 0
|
||||
__loadstore struct Point print::p
|
||||
|
||||
Adding number conversion cast (unumber) 5 in main::$0 = main::i#2 < 5
|
||||
Adding number conversion cast (unumber) 2 in get::$0 = get::i#0 / 2
|
||||
Adding number conversion cast (unumber) get::$0 in get::$0 = get::i#0 / (unumber)2
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Simplifying constant pointer cast (char *) 1024
|
||||
Simplifying constant integer cast 5
|
||||
Simplifying constant integer cast 2
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (char) 5
|
||||
Finalized unsigned number type (char) 2
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Inferred type updated to char in get::$0 = get::i#0 / 2
|
||||
Alias main::i#2 = main::i#3
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Simple Condition main::$0 [3] if(main::i#2<5) goto main::@2
|
||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||
Constant main::i#0 = 0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Simplifying expression containing zero (char *)&get::p in [15] *((char *)&get::p+OFFSET_STRUCT_POINT_X) = get::i#0
|
||||
Simplifying expression containing zero (char *)&print::p in [21] SCREEN[idx] = *((char *)&print::p+OFFSET_STRUCT_POINT_X)
|
||||
Successful SSA optimization PassNSimplifyExpressionWithZero
|
||||
Eliminating unused constant OFFSET_STRUCT_POINT_X
|
||||
Successful SSA optimization PassNEliminateUnusedVars
|
||||
Rewriting division to use shift [12] get::$0 = get::i#0 / 2
|
||||
Successful SSA optimization Pass2MultiplyToShiftRewriting
|
||||
Inlining constant with var siblings main::i#0
|
||||
Constant inlined main::i#0 = 0
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Finalized unsigned number type (char) 1
|
||||
Finalized unsigned number type (char) 2
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Adding NOP phi() at start of __start
|
||||
Adding NOP phi() at start of __start::@1
|
||||
Adding NOP phi() at start of main
|
||||
CALL GRAPH
|
||||
Calls in [__start] to main:3
|
||||
Calls in [main] to get:24 print:27
|
||||
|
||||
Created 1 initial phi equivalence classes
|
||||
Coalesced [30] main::i#4 = main::i#1
|
||||
Coalesced down to 1 phi equivalence classes
|
||||
Adding NOP phi() at start of __start
|
||||
Adding NOP phi() at start of __start::@1
|
||||
Adding NOP phi() at start of main
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
[0] phi()
|
||||
to:__start::__init1
|
||||
__start::__init1: scope:[__start] from __start
|
||||
[1] idx = 0
|
||||
to:__start::@1
|
||||
__start::@1: scope:[__start] from __start::__init1
|
||||
[2] phi()
|
||||
[3] callexecute main
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start::@1
|
||||
[4] return
|
||||
to:@return
|
||||
|
||||
__stackcall void print(struct Point p)
|
||||
print: scope:[print] from
|
||||
[5] print::p = stackidx(struct Point,print::OFFSET_STACK_P)
|
||||
[6] SCREEN[idx] = *((char *)&print::p)
|
||||
[7] idx = ++ idx
|
||||
[8] SCREEN[idx] = *((char *)&print::p+OFFSET_STRUCT_POINT_Y)
|
||||
[9] idx = ++ idx
|
||||
to:print::@return
|
||||
print::@return: scope:[print] from print
|
||||
[10] return
|
||||
to:@return
|
||||
|
||||
__stackcall struct Point get(char i)
|
||||
get: scope:[get] from
|
||||
[11] get::i#0 = stackidx(char,get::OFFSET_STACK_I)
|
||||
[12] get::$0 = get::i#0 >> 1
|
||||
[13] *((char *)&get::p) = get::i#0
|
||||
[14] *((char *)&get::p+OFFSET_STRUCT_POINT_Y) = get::$0
|
||||
[15] *(&get::return) = memcpy(*(&get::p), struct Point, SIZEOF_STRUCT_POINT)
|
||||
to:get::@return
|
||||
get::@return: scope:[get] from get
|
||||
[16] stackidx(struct Point,get::OFFSET_STACK_RETURN_0) = get::return
|
||||
[17] return
|
||||
to:@return
|
||||
|
||||
__stackcall void main()
|
||||
main: scope:[main] from
|
||||
[18] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@2
|
||||
[19] main::i#2 = phi( main/0, main::@2/main::i#1 )
|
||||
[20] if(main::i#2<5) goto main::@2
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[21] return
|
||||
to:@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
[22] stackpush(char) = main::i#2
|
||||
sideeffect stackpushpadding(1)
|
||||
[24] callexecute get
|
||||
[25] main::p = stackpull(struct Point)
|
||||
[26] stackpush(struct Point) = main::p
|
||||
[27] callexecute print
|
||||
sideeffect stackpullpadding(2)
|
||||
[29] main::i#1 = ++ main::i#2
|
||||
to:main::@1
|
||||
|
||||
null depth in calling loop Loop head: main::@1 tails: main::@2 blocks: main::@2 main::@1 in scope print
|
||||
null depth in calling loop Loop head: main::@1 tails: main::@2 blocks: main::@2 main::@1 in scope get
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
void __start()
|
||||
__stackcall struct Point get(char i)
|
||||
char get::$0 // 1001.0
|
||||
char get::i
|
||||
char get::i#0 // 1501.5
|
||||
__loadstore struct Point get::p
|
||||
__loadstore struct Point get::return // 47.666666666666664
|
||||
__loadstore char idx // 316.2105263157895
|
||||
__stackcall void main()
|
||||
char main::i
|
||||
char main::i#1 // 202.0
|
||||
char main::i#2 // 44.888888888888886
|
||||
__loadstore struct Point main::p // 202.0
|
||||
__stackcall void print(struct Point p)
|
||||
__loadstore struct Point print::p // 333.6666666666667
|
||||
|
||||
Initial phi equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
Added variable idx to live range equivalence class [ idx ]
|
||||
Added variable print::p to live range equivalence class [ print::p ]
|
||||
Added variable get::i#0 to live range equivalence class [ get::i#0 ]
|
||||
Added variable get::$0 to live range equivalence class [ get::$0 ]
|
||||
Added variable main::p to live range equivalence class [ main::p ]
|
||||
Added variable get::return to live range equivalence class [ get::return ]
|
||||
Added variable get::p to live range equivalence class [ get::p ]
|
||||
Complete equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
[ idx ]
|
||||
[ print::p ]
|
||||
[ get::i#0 ]
|
||||
[ get::$0 ]
|
||||
[ main::p ]
|
||||
[ get::return ]
|
||||
[ get::p ]
|
||||
Allocated zp[1]:2 [ get::i#0 ]
|
||||
Allocated zp[1]:3 [ get::$0 ]
|
||||
Allocated zp[2]:4 [ print::p ]
|
||||
Allocated zp[1]:6 [ idx ]
|
||||
Allocated zp[1]:7 [ main::i#2 main::i#1 ]
|
||||
Allocated zp[2]:8 [ main::p ]
|
||||
Allocated zp[2]:10 [ get::return ]
|
||||
Allocated zp[2]:12 [ get::p ]
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [1] idx = 0 [ idx get::p get::return ] ( [ idx get::p get::return ] { } ) always clobbers reg byte a
|
||||
Statement [5] print::p = stackidx(struct Point,print::OFFSET_STACK_P) [ idx print::p ] ( main:3::print:27 [ get::p get::return main::i#2 idx print::p ] { } ) always clobbers reg byte a reg byte x
|
||||
Removing always clobbered register reg byte a as potential for zp[1]:7 [ main::i#2 main::i#1 ]
|
||||
Removing always clobbered register reg byte x as potential for zp[1]:7 [ main::i#2 main::i#1 ]
|
||||
Statement [6] SCREEN[idx] = *((char *)&print::p) [ idx print::p ] ( main:3::print:27 [ get::p get::return main::i#2 idx print::p ] { } ) always clobbers reg byte a reg byte y
|
||||
Removing always clobbered register reg byte y as potential for zp[1]:7 [ main::i#2 main::i#1 ]
|
||||
Statement [8] SCREEN[idx] = *((char *)&print::p+OFFSET_STRUCT_POINT_Y) [ idx ] ( main:3::print:27 [ get::p get::return main::i#2 idx ] { } ) always clobbers reg byte a reg byte y
|
||||
Statement [11] get::i#0 = stackidx(char,get::OFFSET_STACK_I) [ get::i#0 get::p get::return ] ( main:3::get:24 [ idx main::i#2 get::i#0 get::p get::return ] { } ) always clobbers reg byte a reg byte x
|
||||
Statement [12] get::$0 = get::i#0 >> 1 [ get::i#0 get::$0 get::p get::return ] ( main:3::get:24 [ idx main::i#2 get::i#0 get::$0 get::p get::return ] { } ) always clobbers reg byte a
|
||||
Removing always clobbered register reg byte a as potential for zp[1]:2 [ get::i#0 ]
|
||||
Statement [15] *(&get::return) = memcpy(*(&get::p), struct Point, SIZEOF_STRUCT_POINT) [ get::p get::return ] ( main:3::get:24 [ idx main::i#2 get::p get::return ] { } ) always clobbers reg byte a reg byte y
|
||||
Statement [16] stackidx(struct Point,get::OFFSET_STACK_RETURN_0) = get::return [ get::p get::return ] ( main:3::get:24 [ idx main::i#2 get::p get::return ] { } ) always clobbers reg byte a reg byte x
|
||||
Statement [20] if(main::i#2<5) goto main::@2 [ idx get::p get::return main::i#2 ] ( main:3 [ idx get::p get::return main::i#2 ] { } ) always clobbers reg byte a
|
||||
Statement [22] stackpush(char) = main::i#2 [ idx get::p get::return main::i#2 ] ( main:3 [ idx get::p get::return main::i#2 ] { } ) always clobbers reg byte a
|
||||
Statement [25] main::p = stackpull(struct Point) [ idx get::p get::return main::i#2 main::p ] ( main:3 [ idx get::p get::return main::i#2 main::p ] { } ) always clobbers reg byte a
|
||||
Statement [26] stackpush(struct Point) = main::p [ idx get::p get::return main::i#2 ] ( main:3 [ idx get::p get::return main::i#2 ] { } ) always clobbers reg byte a
|
||||
Statement sideeffect stackpullpadding(2) always clobbers reg byte a
|
||||
Statement [1] idx = 0 [ idx get::p get::return ] ( [ idx get::p get::return ] { } ) always clobbers reg byte a
|
||||
Statement [5] print::p = stackidx(struct Point,print::OFFSET_STACK_P) [ idx print::p ] ( main:3::print:27 [ get::p get::return main::i#2 idx print::p ] { } ) always clobbers reg byte a reg byte x
|
||||
Statement [6] SCREEN[idx] = *((char *)&print::p) [ idx print::p ] ( main:3::print:27 [ get::p get::return main::i#2 idx print::p ] { } ) always clobbers reg byte a reg byte y
|
||||
Statement [8] SCREEN[idx] = *((char *)&print::p+OFFSET_STRUCT_POINT_Y) [ idx ] ( main:3::print:27 [ get::p get::return main::i#2 idx ] { } ) always clobbers reg byte a reg byte y
|
||||
Statement [11] get::i#0 = stackidx(char,get::OFFSET_STACK_I) [ get::i#0 get::p get::return ] ( main:3::get:24 [ idx main::i#2 get::i#0 get::p get::return ] { } ) always clobbers reg byte a reg byte x
|
||||
Statement [12] get::$0 = get::i#0 >> 1 [ get::i#0 get::$0 get::p get::return ] ( main:3::get:24 [ idx main::i#2 get::i#0 get::$0 get::p get::return ] { } ) always clobbers reg byte a
|
||||
Statement [15] *(&get::return) = memcpy(*(&get::p), struct Point, SIZEOF_STRUCT_POINT) [ get::p get::return ] ( main:3::get:24 [ idx main::i#2 get::p get::return ] { } ) always clobbers reg byte a reg byte y
|
||||
Statement [16] stackidx(struct Point,get::OFFSET_STACK_RETURN_0) = get::return [ get::p get::return ] ( main:3::get:24 [ idx main::i#2 get::p get::return ] { } ) always clobbers reg byte a reg byte x
|
||||
Statement [20] if(main::i#2<5) goto main::@2 [ idx get::p get::return main::i#2 ] ( main:3 [ idx get::p get::return main::i#2 ] { } ) always clobbers reg byte a
|
||||
Statement [22] stackpush(char) = main::i#2 [ idx get::p get::return main::i#2 ] ( main:3 [ idx get::p get::return main::i#2 ] { } ) always clobbers reg byte a
|
||||
Statement [25] main::p = stackpull(struct Point) [ idx get::p get::return main::i#2 main::p ] ( main:3 [ idx get::p get::return main::i#2 main::p ] { } ) always clobbers reg byte a
|
||||
Statement [26] stackpush(struct Point) = main::p [ idx get::p get::return main::i#2 ] ( main:3 [ idx get::p get::return main::i#2 ] { } ) always clobbers reg byte a
|
||||
Statement sideeffect stackpullpadding(2) always clobbers reg byte a
|
||||
Potential registers zp[1]:7 [ main::i#2 main::i#1 ] : zp[1]:7 ,
|
||||
Potential registers zp[1]:6 [ idx ] : zp[1]:6 ,
|
||||
Potential registers zp[2]:4 [ print::p ] : zp[2]:4 ,
|
||||
Potential registers zp[1]:2 [ get::i#0 ] : zp[1]:2 , reg byte x , reg byte y ,
|
||||
Potential registers zp[1]:3 [ get::$0 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp[2]:8 [ main::p ] : zp[2]:8 ,
|
||||
Potential registers zp[2]:10 [ get::return ] : zp[2]:10 ,
|
||||
Potential registers zp[2]:12 [ get::p ] : zp[2]:12 ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [get] 1,501.5: zp[1]:2 [ get::i#0 ] 1,001: zp[1]:3 [ get::$0 ] 47.67: zp[2]:10 [ get::return ] 0: zp[2]:12 [ get::p ]
|
||||
Uplift Scope [main] 246.89: zp[1]:7 [ main::i#2 main::i#1 ] 202: zp[2]:8 [ main::p ]
|
||||
Uplift Scope [print] 333.67: zp[2]:4 [ print::p ]
|
||||
Uplift Scope [] 316.21: zp[1]:6 [ idx ]
|
||||
Uplift Scope [Point]
|
||||
Uplift Scope [__start]
|
||||
|
||||
Uplifting [get] best 993 combination reg byte x [ get::i#0 ] reg byte a [ get::$0 ] zp[2]:10 [ get::return ] zp[2]:12 [ get::p ]
|
||||
Uplifting [main] best 993 combination zp[1]:7 [ main::i#2 main::i#1 ] zp[2]:8 [ main::p ]
|
||||
Uplifting [print] best 993 combination zp[2]:4 [ print::p ]
|
||||
Uplifting [] best 993 combination zp[1]:6 [ idx ]
|
||||
Uplifting [Point] best 993 combination
|
||||
Uplifting [__start] best 993 combination
|
||||
Attempting to uplift remaining variables inzp[1]:6 [ idx ]
|
||||
Uplifting [] best 993 combination zp[1]:6 [ idx ]
|
||||
Attempting to uplift remaining variables inzp[1]:7 [ main::i#2 main::i#1 ]
|
||||
Uplifting [main] best 993 combination zp[1]:7 [ main::i#2 main::i#1 ]
|
||||
Coalescing zero page register [ zp[2]:8 [ main::p ] ] with [ zp[2]:4 [ print::p ] ]
|
||||
Allocated (was zp[2]:8) zp[2]:2 [ main::p print::p ]
|
||||
Allocated (was zp[1]:6) zp[1]:4 [ idx ]
|
||||
Allocated (was zp[1]:7) zp[1]:5 [ main::i#2 main::i#1 ]
|
||||
Allocated (was zp[2]:10) zp[2]:6 [ get::return ]
|
||||
Allocated (was zp[2]:12) zp[2]:8 [ get::p ]
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Test a procedure with calling convention stack
|
||||
// Returning and passing struct values
|
||||
// Upstart
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
// Global Constants & labels
|
||||
.const OFFSET_STRUCT_POINT_Y = 1
|
||||
.const SIZEOF_STRUCT_POINT = 2
|
||||
.const STACK_BASE = $103
|
||||
.label SCREEN = $400
|
||||
.label idx = 4
|
||||
.segment Code
|
||||
// __start
|
||||
__start: {
|
||||
jmp __init1
|
||||
// __start::__init1
|
||||
__init1:
|
||||
// [1] idx = 0 -- vbuz1=vbuc1
|
||||
lda #0
|
||||
sta.z idx
|
||||
// [2] phi from __start::__init1 to __start::@1 [phi:__start::__init1->__start::@1]
|
||||
__b1_from___init1:
|
||||
jmp __b1
|
||||
// __start::@1
|
||||
__b1:
|
||||
// [3] callexecute main -- call_vprc1
|
||||
jsr main
|
||||
jmp __breturn
|
||||
// __start::@return
|
||||
__breturn:
|
||||
// [4] return
|
||||
rts
|
||||
}
|
||||
.segment stage
|
||||
// print
|
||||
// void print(__zp(2) struct Point p)
|
||||
print: {
|
||||
.const OFFSET_STACK_P = 0
|
||||
.label p = 2
|
||||
// [5] print::p = stackidx(struct Point,print::OFFSET_STACK_P) -- vssz1=_stackidxstruct_2_vbuc1
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_P,x
|
||||
sta.z p
|
||||
lda STACK_BASE+OFFSET_STACK_P+1,x
|
||||
sta.z p+1
|
||||
// [6] SCREEN[idx] = *((char *)&print::p) -- pbuc1_derefidx_vbuz1=_deref_pbuc2
|
||||
lda.z p
|
||||
ldy.z idx
|
||||
sta SCREEN,y
|
||||
// [7] idx = ++ idx -- vbuz1=_inc_vbuz1
|
||||
inc.z idx
|
||||
// [8] SCREEN[idx] = *((char *)&print::p+OFFSET_STRUCT_POINT_Y) -- pbuc1_derefidx_vbuz1=_deref_pbuc2
|
||||
lda.z p+OFFSET_STRUCT_POINT_Y
|
||||
ldy.z idx
|
||||
sta SCREEN,y
|
||||
// [9] idx = ++ idx -- vbuz1=_inc_vbuz1
|
||||
inc.z idx
|
||||
jmp __breturn
|
||||
// print::@return
|
||||
__breturn:
|
||||
// [10] return
|
||||
rts
|
||||
}
|
||||
// get
|
||||
// __zp(6) struct Point get(__register(X) char i)
|
||||
get: {
|
||||
.const OFFSET_STACK_I = 0
|
||||
.const OFFSET_STACK_RETURN_0 = 0
|
||||
.label return = 6
|
||||
.label p = 8
|
||||
// [11] get::i#0 = stackidx(char,get::OFFSET_STACK_I) -- vbuxx=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_I,x
|
||||
tax
|
||||
// [12] get::$0 = get::i#0 >> 1 -- vbuaa=vbuxx_ror_1
|
||||
txa
|
||||
lsr
|
||||
// [13] *((char *)&get::p) = get::i#0 -- _deref_pbuc1=vbuxx
|
||||
stx.z p
|
||||
// [14] *((char *)&get::p+OFFSET_STRUCT_POINT_Y) = get::$0 -- _deref_pbuc1=vbuaa
|
||||
sta.z p+OFFSET_STRUCT_POINT_Y
|
||||
// [15] *(&get::return) = memcpy(*(&get::p), struct Point, SIZEOF_STRUCT_POINT) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
|
||||
ldy #SIZEOF_STRUCT_POINT
|
||||
!:
|
||||
lda p-1,y
|
||||
sta return-1,y
|
||||
dey
|
||||
bne !-
|
||||
jmp __breturn
|
||||
// get::@return
|
||||
__breturn:
|
||||
// [16] stackidx(struct Point,get::OFFSET_STACK_RETURN_0) = get::return -- _stackidxstruct_2_vbuc1=vssz1
|
||||
tsx
|
||||
lda.z return
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN_0,x
|
||||
lda.z return+1
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN_0+1,x
|
||||
// [17] return
|
||||
rts
|
||||
}
|
||||
// main
|
||||
main: {
|
||||
.label p = 2
|
||||
.label i = 5
|
||||
// [19] phi from main to main::@1 [phi:main->main::@1]
|
||||
__b1_from_main:
|
||||
// [19] phi main::i#2 = 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
|
||||
lda #0
|
||||
sta.z i
|
||||
jmp __b1
|
||||
// main::@1
|
||||
__b1:
|
||||
// [20] if(main::i#2<5) goto main::@2 -- vbuz1_lt_vbuc1_then_la1
|
||||
lda.z i
|
||||
cmp #5
|
||||
bcc __b2
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [21] return
|
||||
rts
|
||||
// main::@2
|
||||
__b2:
|
||||
// [22] stackpush(char) = main::i#2 -- _stackpushbyte_=vbuz1
|
||||
lda.z i
|
||||
pha
|
||||
// sideeffect stackpushpadding(1) -- _stackpushpadding_1
|
||||
pha
|
||||
// [24] callexecute get -- call_vprc1
|
||||
jsr get
|
||||
// [25] main::p = stackpull(struct Point) -- vssz1=_stackpullstruct_2_
|
||||
pla
|
||||
sta.z p
|
||||
pla
|
||||
sta.z p+1
|
||||
// [26] stackpush(struct Point) = main::p -- _stackpushstruct_2_=vssz1
|
||||
lda.z p+1
|
||||
pha
|
||||
lda.z p
|
||||
pha
|
||||
// [27] callexecute print -- call_vprc1
|
||||
jsr print
|
||||
// sideeffect stackpullpadding(2) -- _stackpullpadding_2
|
||||
pla
|
||||
pla
|
||||
// [29] main::i#1 = ++ main::i#2 -- vbuz1=_inc_vbuz1
|
||||
inc.z i
|
||||
// [19] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
|
||||
__b1_from___b2:
|
||||
// [19] phi main::i#2 = main::i#1 [phi:main::@2->main::@1#0] -- register_copy
|
||||
jmp __b1
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp __init1
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction lda.z p+1
|
||||
Succesful ASM optimization Pass5UnnecesaryLoadElimination
|
||||
Removing instruction __b1_from___init1:
|
||||
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||
Removing instruction __init1:
|
||||
Removing instruction __b1:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __b1_from_main:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __b1_from___b2:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
__constant char OFFSET_STRUCT_POINT_Y = 1
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
__constant char SIZEOF_STRUCT_POINT = 2
|
||||
__constant unsigned int STACK_BASE = $103
|
||||
void __start()
|
||||
__stackcall struct Point get(char i)
|
||||
char get::$0 // reg byte a 1001.0
|
||||
__constant char get::OFFSET_STACK_I = 0
|
||||
__constant char get::OFFSET_STACK_RETURN_0 = 0
|
||||
char get::i
|
||||
char get::i#0 // reg byte x 1501.5
|
||||
__loadstore struct Point get::p // zp[2]:8
|
||||
__loadstore struct Point get::return // zp[2]:6 47.666666666666664
|
||||
__loadstore char idx // zp[1]:4 316.2105263157895
|
||||
__stackcall void main()
|
||||
char main::i
|
||||
char main::i#1 // i zp[1]:5 202.0
|
||||
char main::i#2 // i zp[1]:5 44.888888888888886
|
||||
__loadstore struct Point main::p // zp[2]:2 202.0
|
||||
__stackcall void print(struct Point p)
|
||||
__constant char print::OFFSET_STACK_P = 0
|
||||
__loadstore struct Point print::p // zp[2]:2 333.6666666666667
|
||||
|
||||
zp[1]:5 [ main::i#2 main::i#1 ]
|
||||
zp[1]:4 [ idx ]
|
||||
reg byte x [ get::i#0 ]
|
||||
reg byte a [ get::$0 ]
|
||||
zp[2]:2 [ main::p print::p ]
|
||||
zp[2]:6 [ get::return ]
|
||||
zp[2]:8 [ get::p ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 861
|
||||
|
||||
// File Comments
|
||||
// Test a procedure with calling convention stack
|
||||
// Returning and passing struct values
|
||||
// Upstart
|
||||
.cpu _65c02
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
// Global Constants & labels
|
||||
.const OFFSET_STRUCT_POINT_Y = 1
|
||||
.const SIZEOF_STRUCT_POINT = 2
|
||||
.const STACK_BASE = $103
|
||||
.label SCREEN = $400
|
||||
.label idx = 4
|
||||
.segment Code
|
||||
// __start
|
||||
__start: {
|
||||
// __start::__init1
|
||||
// char idx = 0
|
||||
// [1] idx = 0 -- vbuz1=vbuc1
|
||||
lda #0
|
||||
sta.z idx
|
||||
// [2] phi from __start::__init1 to __start::@1 [phi:__start::__init1->__start::@1]
|
||||
// __start::@1
|
||||
// [3] callexecute main -- call_vprc1
|
||||
jsr main
|
||||
// __start::@return
|
||||
// [4] return
|
||||
rts
|
||||
}
|
||||
.segment stage
|
||||
// print
|
||||
// void print(__zp(2) struct Point p)
|
||||
print: {
|
||||
.const OFFSET_STACK_P = 0
|
||||
.label p = 2
|
||||
// [5] print::p = stackidx(struct Point,print::OFFSET_STACK_P) -- vssz1=_stackidxstruct_2_vbuc1
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_P,x
|
||||
sta.z p
|
||||
lda STACK_BASE+OFFSET_STACK_P+1,x
|
||||
sta.z p+1
|
||||
// SCREEN[idx++] = p.x
|
||||
// [6] SCREEN[idx] = *((char *)&print::p) -- pbuc1_derefidx_vbuz1=_deref_pbuc2
|
||||
lda.z p
|
||||
ldy.z idx
|
||||
sta SCREEN,y
|
||||
// SCREEN[idx++] = p.x;
|
||||
// [7] idx = ++ idx -- vbuz1=_inc_vbuz1
|
||||
inc.z idx
|
||||
// SCREEN[idx++] = p.y
|
||||
// [8] SCREEN[idx] = *((char *)&print::p+OFFSET_STRUCT_POINT_Y) -- pbuc1_derefidx_vbuz1=_deref_pbuc2
|
||||
lda.z p+OFFSET_STRUCT_POINT_Y
|
||||
ldy.z idx
|
||||
sta SCREEN,y
|
||||
// SCREEN[idx++] = p.y;
|
||||
// [9] idx = ++ idx -- vbuz1=_inc_vbuz1
|
||||
inc.z idx
|
||||
// print::@return
|
||||
// }
|
||||
// [10] return
|
||||
rts
|
||||
}
|
||||
// get
|
||||
// __zp(6) struct Point get(__register(X) char i)
|
||||
get: {
|
||||
.const OFFSET_STACK_I = 0
|
||||
.const OFFSET_STACK_RETURN_0 = 0
|
||||
.label return = 6
|
||||
.label p = 8
|
||||
// [11] get::i#0 = stackidx(char,get::OFFSET_STACK_I) -- vbuxx=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_I,x
|
||||
tax
|
||||
// i/2
|
||||
// [12] get::$0 = get::i#0 >> 1 -- vbuaa=vbuxx_ror_1
|
||||
txa
|
||||
lsr
|
||||
// struct Point p = { i, i/2 }
|
||||
// [13] *((char *)&get::p) = get::i#0 -- _deref_pbuc1=vbuxx
|
||||
stx.z p
|
||||
// [14] *((char *)&get::p+OFFSET_STRUCT_POINT_Y) = get::$0 -- _deref_pbuc1=vbuaa
|
||||
sta.z p+OFFSET_STRUCT_POINT_Y
|
||||
// return p;
|
||||
// [15] *(&get::return) = memcpy(*(&get::p), struct Point, SIZEOF_STRUCT_POINT) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
|
||||
ldy #SIZEOF_STRUCT_POINT
|
||||
!:
|
||||
lda p-1,y
|
||||
sta return-1,y
|
||||
dey
|
||||
bne !-
|
||||
// get::@return
|
||||
// }
|
||||
// [16] stackidx(struct Point,get::OFFSET_STACK_RETURN_0) = get::return -- _stackidxstruct_2_vbuc1=vssz1
|
||||
tsx
|
||||
lda.z return
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN_0,x
|
||||
lda.z return+1
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN_0+1,x
|
||||
// [17] return
|
||||
rts
|
||||
}
|
||||
// main
|
||||
main: {
|
||||
.label p = 2
|
||||
.label i = 5
|
||||
// [19] phi from main to main::@1 [phi:main->main::@1]
|
||||
// [19] phi main::i#2 = 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
|
||||
lda #0
|
||||
sta.z i
|
||||
// main::@1
|
||||
__b1:
|
||||
// for(char i=0;i<5;i++)
|
||||
// [20] if(main::i#2<5) goto main::@2 -- vbuz1_lt_vbuc1_then_la1
|
||||
lda.z i
|
||||
cmp #5
|
||||
bcc __b2
|
||||
// main::@return
|
||||
// }
|
||||
// [21] return
|
||||
rts
|
||||
// main::@2
|
||||
__b2:
|
||||
// struct Point p = get(i)
|
||||
// [22] stackpush(char) = main::i#2 -- _stackpushbyte_=vbuz1
|
||||
lda.z i
|
||||
pha
|
||||
// sideeffect stackpushpadding(1) -- _stackpushpadding_1
|
||||
pha
|
||||
// [24] callexecute get -- call_vprc1
|
||||
jsr get
|
||||
// [25] main::p = stackpull(struct Point) -- vssz1=_stackpullstruct_2_
|
||||
pla
|
||||
sta.z p
|
||||
pla
|
||||
sta.z p+1
|
||||
// print(p)
|
||||
// [26] stackpush(struct Point) = main::p -- _stackpushstruct_2_=vssz1
|
||||
pha
|
||||
lda.z p
|
||||
pha
|
||||
// [27] callexecute print -- call_vprc1
|
||||
jsr print
|
||||
// sideeffect stackpullpadding(2) -- _stackpullpadding_2
|
||||
pla
|
||||
pla
|
||||
// for(char i=0;i<5;i++)
|
||||
// [29] main::i#1 = ++ main::i#2 -- vbuz1=_inc_vbuz1
|
||||
inc.z i
|
||||
// [19] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
|
||||
// [19] phi main::i#2 = main::i#1 [phi:main::@2->main::@1#0] -- register_copy
|
||||
jmp __b1
|
||||
}
|
||||
// File Data
|
||||
|
30
src/test/ref/procedure-callingconvention-stack-bank-4.sym
Normal file
30
src/test/ref/procedure-callingconvention-stack-bank-4.sym
Normal file
@ -0,0 +1,30 @@
|
||||
__constant char OFFSET_STRUCT_POINT_Y = 1
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
__constant char SIZEOF_STRUCT_POINT = 2
|
||||
__constant unsigned int STACK_BASE = $103
|
||||
void __start()
|
||||
__stackcall struct Point get(char i)
|
||||
char get::$0 // reg byte a 1001.0
|
||||
__constant char get::OFFSET_STACK_I = 0
|
||||
__constant char get::OFFSET_STACK_RETURN_0 = 0
|
||||
char get::i
|
||||
char get::i#0 // reg byte x 1501.5
|
||||
__loadstore struct Point get::p // zp[2]:8
|
||||
__loadstore struct Point get::return // zp[2]:6 47.666666666666664
|
||||
__loadstore char idx // zp[1]:4 316.2105263157895
|
||||
__stackcall void main()
|
||||
char main::i
|
||||
char main::i#1 // i zp[1]:5 202.0
|
||||
char main::i#2 // i zp[1]:5 44.888888888888886
|
||||
__loadstore struct Point main::p // zp[2]:2 202.0
|
||||
__stackcall void print(struct Point p)
|
||||
__constant char print::OFFSET_STACK_P = 0
|
||||
__loadstore struct Point print::p // zp[2]:2 333.6666666666667
|
||||
|
||||
zp[1]:5 [ main::i#2 main::i#1 ]
|
||||
zp[1]:4 [ idx ]
|
||||
reg byte x [ get::i#0 ]
|
||||
reg byte a [ get::$0 ]
|
||||
zp[2]:2 [ main::p print::p ]
|
||||
zp[2]:6 [ get::return ]
|
||||
zp[2]:8 [ get::p ]
|
50
src/test/ref/procedure-callingconvention-stack-bank-5.asm
Normal file
50
src/test/ref/procedure-callingconvention-stack-bank-5.asm
Normal file
@ -0,0 +1,50 @@
|
||||
// Test a procedure with calling convention stack
|
||||
// Recursion that works (no local variables)
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
.const STACK_BASE = $103
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
// __register(A) char pow2(__register(A) char n)
|
||||
pow2: {
|
||||
.const OFFSET_STACK_N = 0
|
||||
.const OFFSET_STACK_RETURN_0 = 0
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_N,x
|
||||
// if (n == 0)
|
||||
cmp #0
|
||||
beq __b1
|
||||
// n-1
|
||||
sec
|
||||
sbc #1
|
||||
// char c = pow2(n-1)
|
||||
pha
|
||||
jsr pow2
|
||||
pla
|
||||
// return c+c;
|
||||
asl
|
||||
jmp __breturn
|
||||
__b1:
|
||||
lda #1
|
||||
__breturn:
|
||||
// }
|
||||
tsx
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN_0,x
|
||||
rts
|
||||
}
|
||||
main: {
|
||||
// pow2(6)
|
||||
lda #6
|
||||
pha
|
||||
jsr pow2
|
||||
pla
|
||||
// *SCREEN = pow2(6)
|
||||
sta SCREEN
|
||||
// }
|
||||
rts
|
||||
}
|
29
src/test/ref/procedure-callingconvention-stack-bank-5.cfg
Normal file
29
src/test/ref/procedure-callingconvention-stack-bank-5.cfg
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
__stackcall char pow2(char n)
|
||||
pow2: scope:[pow2] from
|
||||
[0] pow2::n#0 = stackidx(char,pow2::OFFSET_STACK_N)
|
||||
[1] if(pow2::n#0==0) goto pow2::@return
|
||||
to:pow2::@1
|
||||
pow2::@1: scope:[pow2] from pow2
|
||||
[2] pow2::$1 = pow2::n#0 - 1
|
||||
[3] stackpush(char) = pow2::$1
|
||||
[4] callexecute pow2
|
||||
[5] pow2::c#0 = stackpull(char)
|
||||
[6] pow2::return#1 = pow2::c#0 + pow2::c#0
|
||||
to:pow2::@return
|
||||
pow2::@return: scope:[pow2] from pow2 pow2::@1
|
||||
[7] pow2::return#2 = phi( pow2/1, pow2::@1/pow2::return#1 )
|
||||
[8] stackidx(char,pow2::OFFSET_STACK_RETURN_0) = pow2::return#2
|
||||
[9] return
|
||||
to:@return
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[10] stackpush(char) = 6
|
||||
[11] callexecute pow2
|
||||
[12] main::$0 = stackpull(char)
|
||||
[13] *SCREEN = main::$0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[14] return
|
||||
to:@return
|
408
src/test/ref/procedure-callingconvention-stack-bank-5.log
Normal file
408
src/test/ref/procedure-callingconvention-stack-bank-5.log
Normal file
@ -0,0 +1,408 @@
|
||||
Loading link script "procedure-callingconvention-stack-bank.ld"
|
||||
Warning! Unknown #pragma platform
|
||||
Adding parameter assignment in __stackcall procedure pow2::n = param(pow2::n)
|
||||
Eliminating unused variable with no statement pow2::$2
|
||||
Calling convention __stackcall adding prepare/execute/finalize for main::$0 = call pow2(6)
|
||||
Calling convention __stackcall adding prepare/execute/finalize for pow2::c = call pow2(pow2::$1)
|
||||
Calling convention STACK_CALL replacing param(pow2::n) with stackidx(char,pow2::OFFSET_STACK_N)
|
||||
Calling convention STACK_CALL adding stack return stackidx(char,pow2::OFFSET_STACK_RETURN_0) = pow2::return
|
||||
Calling convention STACK_CALL adding stack pull main::$0 = stackpull(char)
|
||||
Calling convention STACK_CALL adding stack pull pow2::c = stackpull(char)
|
||||
Calling convention STACK_CALL adding stack push stackpush(char) = 6
|
||||
Calling convention STACK_CALL adding stack push stackpush(char) = pow2::$1
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
void main()
|
||||
main: scope:[main] from __start
|
||||
stackpush(char) = 6
|
||||
callexecute pow2
|
||||
main::$0 = stackpull(char)
|
||||
*SCREEN = main::$0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
return
|
||||
to:@return
|
||||
|
||||
__stackcall char pow2(char n)
|
||||
pow2: scope:[pow2] from
|
||||
pow2::n#0 = stackidx(char,pow2::OFFSET_STACK_N)
|
||||
pow2::$0 = pow2::n#0 == 0
|
||||
if(pow2::$0) goto pow2::@1
|
||||
to:pow2::@2
|
||||
pow2::@1: scope:[pow2] from pow2
|
||||
pow2::return#0 = 1
|
||||
to:pow2::@return
|
||||
pow2::@2: scope:[pow2] from pow2
|
||||
pow2::n#1 = phi( pow2/pow2::n#0 )
|
||||
pow2::$1 = pow2::n#1 - 1
|
||||
stackpush(char) = pow2::$1
|
||||
callexecute pow2
|
||||
pow2::c#0 = stackpull(char)
|
||||
pow2::$3 = pow2::c#0 + pow2::c#0
|
||||
pow2::return#1 = pow2::$3
|
||||
to:pow2::@return
|
||||
pow2::@return: scope:[pow2] from pow2::@1 pow2::@2
|
||||
pow2::return#2 = phi( pow2::@1/pow2::return#0, pow2::@2/pow2::return#1 )
|
||||
stackidx(char,pow2::OFFSET_STACK_RETURN_0) = pow2::return#2
|
||||
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
|
||||
__constant char * const SCREEN = (char *)$400
|
||||
__constant unsigned int STACK_BASE = $103
|
||||
void __start()
|
||||
void main()
|
||||
char main::$0
|
||||
__stackcall char pow2(char n)
|
||||
bool pow2::$0
|
||||
number pow2::$1
|
||||
char pow2::$3
|
||||
__constant char pow2::OFFSET_STACK_N = 0
|
||||
__constant char pow2::OFFSET_STACK_RETURN_0 = 0
|
||||
char pow2::c
|
||||
char pow2::c#0
|
||||
char pow2::n
|
||||
char pow2::n#0
|
||||
char pow2::n#1
|
||||
char pow2::return
|
||||
char pow2::return#0
|
||||
char pow2::return#1
|
||||
char pow2::return#2
|
||||
|
||||
Adding number conversion cast (unumber) 6 in stackpush(char) = 6
|
||||
Adding number conversion cast (unumber) 0 in pow2::$0 = pow2::n#0 == 0
|
||||
Adding number conversion cast (unumber) 1 in pow2::return#0 = 1
|
||||
Adding number conversion cast (unumber) 1 in pow2::$1 = pow2::n#1 - 1
|
||||
Adding number conversion cast (unumber) pow2::$1 in pow2::$1 = pow2::n#1 - (unumber)1
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Inlining cast stackpush(char) = (unumber)6
|
||||
Inlining cast pow2::return#0 = (unumber)1
|
||||
Successful SSA optimization Pass2InlineCast
|
||||
Simplifying constant pointer cast (char *) 1024
|
||||
Simplifying constant integer cast 6
|
||||
Simplifying constant integer cast 0
|
||||
Simplifying constant integer cast 1
|
||||
Simplifying constant integer cast 1
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (char) 6
|
||||
Finalized unsigned number type (char) 0
|
||||
Finalized unsigned number type (char) 1
|
||||
Finalized unsigned number type (char) 1
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Inferred type updated to char in pow2::$1 = pow2::n#1 - 1
|
||||
Alias pow2::n#0 = pow2::n#1
|
||||
Alias pow2::return#1 = pow2::$3
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Simple Condition pow2::$0 [7] if(pow2::n#0==0) goto pow2::@1
|
||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||
Constant pow2::return#0 = 1
|
||||
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 pow2::return#0
|
||||
Constant inlined pow2::return#0 = 1
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Adding NOP phi() at start of pow2::@1
|
||||
CALL GRAPH
|
||||
Calls in [pow2] to pow2:4
|
||||
Calls in [main] to pow2:13
|
||||
|
||||
Created 1 initial phi equivalence classes
|
||||
Coalesced [7] pow2::return#3 = pow2::return#1
|
||||
Coalesced down to 1 phi equivalence classes
|
||||
Culled Empty Block label pow2::@1
|
||||
Renumbering block pow2::@2 to pow2::@1
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
|
||||
__stackcall char pow2(char n)
|
||||
pow2: scope:[pow2] from
|
||||
[0] pow2::n#0 = stackidx(char,pow2::OFFSET_STACK_N)
|
||||
[1] if(pow2::n#0==0) goto pow2::@return
|
||||
to:pow2::@1
|
||||
pow2::@1: scope:[pow2] from pow2
|
||||
[2] pow2::$1 = pow2::n#0 - 1
|
||||
[3] stackpush(char) = pow2::$1
|
||||
[4] callexecute pow2
|
||||
[5] pow2::c#0 = stackpull(char)
|
||||
[6] pow2::return#1 = pow2::c#0 + pow2::c#0
|
||||
to:pow2::@return
|
||||
pow2::@return: scope:[pow2] from pow2 pow2::@1
|
||||
[7] pow2::return#2 = phi( pow2/1, pow2::@1/pow2::return#1 )
|
||||
[8] stackidx(char,pow2::OFFSET_STACK_RETURN_0) = pow2::return#2
|
||||
[9] return
|
||||
to:@return
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[10] stackpush(char) = 6
|
||||
[11] callexecute pow2
|
||||
[12] main::$0 = stackpull(char)
|
||||
[13] *SCREEN = main::$0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[14] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
void main()
|
||||
char main::$0 // 4.0
|
||||
__stackcall char pow2(char n)
|
||||
char pow2::$1 // 22.0
|
||||
char pow2::c
|
||||
char pow2::c#0 // 33.0
|
||||
char pow2::n
|
||||
char pow2::n#0 // 16.5
|
||||
char pow2::return
|
||||
char pow2::return#1 // 22.0
|
||||
char pow2::return#2 // 22.0
|
||||
|
||||
Initial phi equivalence classes
|
||||
[ pow2::return#2 pow2::return#1 ]
|
||||
Added variable pow2::n#0 to live range equivalence class [ pow2::n#0 ]
|
||||
Added variable pow2::$1 to live range equivalence class [ pow2::$1 ]
|
||||
Added variable pow2::c#0 to live range equivalence class [ pow2::c#0 ]
|
||||
Added variable main::$0 to live range equivalence class [ main::$0 ]
|
||||
Complete equivalence classes
|
||||
[ pow2::return#2 pow2::return#1 ]
|
||||
[ pow2::n#0 ]
|
||||
[ pow2::$1 ]
|
||||
[ pow2::c#0 ]
|
||||
[ main::$0 ]
|
||||
Allocated zp[1]:2 [ pow2::return#2 pow2::return#1 ]
|
||||
Allocated zp[1]:3 [ pow2::c#0 ]
|
||||
Allocated zp[1]:4 [ pow2::$1 ]
|
||||
Allocated zp[1]:5 [ pow2::n#0 ]
|
||||
Allocated zp[1]:6 [ main::$0 ]
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [0] pow2::n#0 = stackidx(char,pow2::OFFSET_STACK_N) [ pow2::n#0 ] ( pow2:11 [ pow2::n#0 ] { } ) always clobbers reg byte a reg byte x
|
||||
Statement [5] pow2::c#0 = stackpull(char) [ pow2::c#0 ] ( pow2:11 [ pow2::c#0 ] { } ) always clobbers reg byte a
|
||||
Statement [6] pow2::return#1 = pow2::c#0 + pow2::c#0 [ pow2::return#1 ] ( pow2:11 [ pow2::return#1 ] { } ) always clobbers reg byte a
|
||||
Statement [8] stackidx(char,pow2::OFFSET_STACK_RETURN_0) = pow2::return#2 [ ] ( pow2:11 [ ] { } ) always clobbers reg byte x
|
||||
Statement [10] stackpush(char) = 6 [ ] ( [ ] { } ) always clobbers reg byte a
|
||||
Statement [12] main::$0 = stackpull(char) [ main::$0 ] ( [ main::$0 ] { } ) always clobbers reg byte a
|
||||
Potential registers zp[1]:2 [ pow2::return#2 pow2::return#1 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp[1]:5 [ pow2::n#0 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp[1]:4 [ pow2::$1 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp[1]:3 [ pow2::c#0 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp[1]:6 [ main::$0 ] : zp[1]:6 , reg byte a , reg byte x , reg byte y ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [pow2] 44: zp[1]:2 [ pow2::return#2 pow2::return#1 ] 33: zp[1]:3 [ pow2::c#0 ] 22: zp[1]:4 [ pow2::$1 ] 16.5: zp[1]:5 [ pow2::n#0 ]
|
||||
Uplift Scope [main] 4: zp[1]:6 [ main::$0 ]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [pow2] best 87 combination reg byte a [ pow2::return#2 pow2::return#1 ] reg byte a [ pow2::c#0 ] reg byte a [ pow2::$1 ] reg byte a [ pow2::n#0 ]
|
||||
Limited combination testing to 100 combinations of 256 possible.
|
||||
Uplifting [main] best 81 combination reg byte a [ main::$0 ]
|
||||
Uplifting [] best 81 combination
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Test a procedure with calling convention stack
|
||||
// Recursion that works (no local variables)
|
||||
// Upstart
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
// Global Constants & labels
|
||||
.const STACK_BASE = $103
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
// pow2
|
||||
// __register(A) char pow2(__register(A) char n)
|
||||
pow2: {
|
||||
.const OFFSET_STACK_N = 0
|
||||
.const OFFSET_STACK_RETURN_0 = 0
|
||||
// [0] pow2::n#0 = stackidx(char,pow2::OFFSET_STACK_N) -- vbuaa=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_N,x
|
||||
// [1] if(pow2::n#0==0) goto pow2::@return -- vbuaa_eq_0_then_la1
|
||||
cmp #0
|
||||
beq __breturn_from_pow2
|
||||
jmp __b1
|
||||
// pow2::@1
|
||||
__b1:
|
||||
// [2] pow2::$1 = pow2::n#0 - 1 -- vbuaa=vbuaa_minus_1
|
||||
sec
|
||||
sbc #1
|
||||
// [3] stackpush(char) = pow2::$1 -- _stackpushbyte_=vbuaa
|
||||
pha
|
||||
// [4] callexecute pow2 -- call_vprc1
|
||||
jsr pow2
|
||||
// [5] pow2::c#0 = stackpull(char) -- vbuaa=_stackpullbyte_
|
||||
pla
|
||||
// [6] pow2::return#1 = pow2::c#0 + pow2::c#0 -- vbuaa=vbuaa_plus_vbuaa
|
||||
asl
|
||||
// [7] phi from pow2::@1 to pow2::@return [phi:pow2::@1->pow2::@return]
|
||||
__breturn_from___b1:
|
||||
// [7] phi pow2::return#2 = pow2::return#1 [phi:pow2::@1->pow2::@return#0] -- register_copy
|
||||
jmp __breturn
|
||||
// [7] phi from pow2 to pow2::@return [phi:pow2->pow2::@return]
|
||||
__breturn_from_pow2:
|
||||
// [7] phi pow2::return#2 = 1 [phi:pow2->pow2::@return#0] -- vbuaa=vbuc1
|
||||
lda #1
|
||||
jmp __breturn
|
||||
// pow2::@return
|
||||
__breturn:
|
||||
// [8] stackidx(char,pow2::OFFSET_STACK_RETURN_0) = pow2::return#2 -- _stackidxbyte_vbuc1=vbuaa
|
||||
tsx
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN_0,x
|
||||
// [9] return
|
||||
rts
|
||||
}
|
||||
// main
|
||||
main: {
|
||||
// [10] stackpush(char) = 6 -- _stackpushbyte_=vbuc1
|
||||
lda #6
|
||||
pha
|
||||
// [11] callexecute pow2 -- call_vprc1
|
||||
jsr pow2
|
||||
// [12] main::$0 = stackpull(char) -- vbuaa=_stackpullbyte_
|
||||
pla
|
||||
// [13] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
|
||||
sta SCREEN
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [14] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction __b1:
|
||||
Removing instruction __breturn_from___b1:
|
||||
Removing instruction __breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
Relabelling long label __breturn_from_pow2 to __b1
|
||||
Succesful ASM optimization Pass5RelabelLongLabels
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
__constant unsigned int STACK_BASE = $103
|
||||
void main()
|
||||
char main::$0 // reg byte a 4.0
|
||||
__stackcall char pow2(char n)
|
||||
char pow2::$1 // reg byte a 22.0
|
||||
__constant char pow2::OFFSET_STACK_N = 0
|
||||
__constant char pow2::OFFSET_STACK_RETURN_0 = 0
|
||||
char pow2::c
|
||||
char pow2::c#0 // reg byte a 33.0
|
||||
char pow2::n
|
||||
char pow2::n#0 // reg byte a 16.5
|
||||
char pow2::return
|
||||
char pow2::return#1 // reg byte a 22.0
|
||||
char pow2::return#2 // reg byte a 22.0
|
||||
|
||||
reg byte a [ pow2::return#2 pow2::return#1 ]
|
||||
reg byte a [ pow2::n#0 ]
|
||||
reg byte a [ pow2::$1 ]
|
||||
reg byte a [ pow2::c#0 ]
|
||||
reg byte a [ main::$0 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 72
|
||||
|
||||
// File Comments
|
||||
// Test a procedure with calling convention stack
|
||||
// Recursion that works (no local variables)
|
||||
// Upstart
|
||||
.segmentdef Program [segments="Basic, Code, Data, stage, platform"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef stage [start=$0400, min=$0400, max=$07FF, align=$100]
|
||||
.segmentdef platform [start=$C000, min=$C000, max=$C7FF, align=$100]
|
||||
|
||||
// Global Constants & labels
|
||||
.const STACK_BASE = $103
|
||||
.label SCREEN = $400
|
||||
.segment stage
|
||||
// pow2
|
||||
// __register(A) char pow2(__register(A) char n)
|
||||
pow2: {
|
||||
.const OFFSET_STACK_N = 0
|
||||
.const OFFSET_STACK_RETURN_0 = 0
|
||||
// [0] pow2::n#0 = stackidx(char,pow2::OFFSET_STACK_N) -- vbuaa=_stackidxbyte_vbuc1
|
||||
tsx
|
||||
lda STACK_BASE+OFFSET_STACK_N,x
|
||||
// if (n == 0)
|
||||
// [1] if(pow2::n#0==0) goto pow2::@return -- vbuaa_eq_0_then_la1
|
||||
cmp #0
|
||||
beq __b1
|
||||
// pow2::@1
|
||||
// n-1
|
||||
// [2] pow2::$1 = pow2::n#0 - 1 -- vbuaa=vbuaa_minus_1
|
||||
sec
|
||||
sbc #1
|
||||
// char c = pow2(n-1)
|
||||
// [3] stackpush(char) = pow2::$1 -- _stackpushbyte_=vbuaa
|
||||
pha
|
||||
// [4] callexecute pow2 -- call_vprc1
|
||||
jsr pow2
|
||||
// [5] pow2::c#0 = stackpull(char) -- vbuaa=_stackpullbyte_
|
||||
pla
|
||||
// return c+c;
|
||||
// [6] pow2::return#1 = pow2::c#0 + pow2::c#0 -- vbuaa=vbuaa_plus_vbuaa
|
||||
asl
|
||||
// [7] phi from pow2::@1 to pow2::@return [phi:pow2::@1->pow2::@return]
|
||||
// [7] phi pow2::return#2 = pow2::return#1 [phi:pow2::@1->pow2::@return#0] -- register_copy
|
||||
jmp __breturn
|
||||
// [7] phi from pow2 to pow2::@return [phi:pow2->pow2::@return]
|
||||
__b1:
|
||||
// [7] phi pow2::return#2 = 1 [phi:pow2->pow2::@return#0] -- vbuaa=vbuc1
|
||||
lda #1
|
||||
// pow2::@return
|
||||
__breturn:
|
||||
// }
|
||||
// [8] stackidx(char,pow2::OFFSET_STACK_RETURN_0) = pow2::return#2 -- _stackidxbyte_vbuc1=vbuaa
|
||||
tsx
|
||||
sta STACK_BASE+OFFSET_STACK_RETURN_0,x
|
||||
// [9] return
|
||||
rts
|
||||
}
|
||||
// main
|
||||
main: {
|
||||
// pow2(6)
|
||||
// [10] stackpush(char) = 6 -- _stackpushbyte_=vbuc1
|
||||
lda #6
|
||||
pha
|
||||
// [11] callexecute pow2 -- call_vprc1
|
||||
jsr pow2
|
||||
// [12] main::$0 = stackpull(char) -- vbuaa=_stackpullbyte_
|
||||
pla
|
||||
// *SCREEN = pow2(6)
|
||||
// [13] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
|
||||
sta SCREEN
|
||||
// main::@return
|
||||
// }
|
||||
// [14] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
21
src/test/ref/procedure-callingconvention-stack-bank-5.sym
Normal file
21
src/test/ref/procedure-callingconvention-stack-bank-5.sym
Normal file
@ -0,0 +1,21 @@
|
||||
__constant char * const SCREEN = (char *) 1024
|
||||
__constant unsigned int STACK_BASE = $103
|
||||
void main()
|
||||
char main::$0 // reg byte a 4.0
|
||||
__stackcall char pow2(char n)
|
||||
char pow2::$1 // reg byte a 22.0
|
||||
__constant char pow2::OFFSET_STACK_N = 0
|
||||
__constant char pow2::OFFSET_STACK_RETURN_0 = 0
|
||||
char pow2::c
|
||||
char pow2::c#0 // reg byte a 33.0
|
||||
char pow2::n
|
||||
char pow2::n#0 // reg byte a 16.5
|
||||
char pow2::return
|
||||
char pow2::return#1 // reg byte a 22.0
|
||||
char pow2::return#2 // reg byte a 22.0
|
||||
|
||||
reg byte a [ pow2::return#2 pow2::return#1 ]
|
||||
reg byte a [ pow2::n#0 ]
|
||||
reg byte a [ pow2::$1 ]
|
||||
reg byte a [ pow2::c#0 ]
|
||||
reg byte a [ main::$0 ]
|
Loading…
Reference in New Issue
Block a user