1
0
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:
Flight_Control 2023-04-04 19:36:11 +02:00
parent 4706611564
commit 5bd84e7812
69 changed files with 8979 additions and 45 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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)

View File

@ -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.

View 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]

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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) {

View 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]

View File

@ -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'

View File

@ -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'

View File

@ -457,7 +457,7 @@ dtvSetCpuBankSegment1: {
// asm
.byte $32, $dd
lda.z $ff
.byte $32, $00
.byte $32, 0
// }
rts
}

View File

@ -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

View File

@ -365,7 +365,7 @@ dtvSetCpuBankSegment1: {
// asm
.byte $32, $dd
lda.z $ff
.byte $32, $00
.byte $32, 0
// }
rts
}

View File

@ -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

View 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
}

View 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

View 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

View 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

View 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
}

View 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

View 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

View 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

View 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
}

View 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

View 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

View 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

View 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
}

View 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

View 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

View 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

View 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
}

View 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

View 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

View 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

View 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
}

View 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

File diff suppressed because it is too large Load Diff

View 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 ]

View 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
}

View 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

View 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

View 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 ]

View 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
}

View 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

View 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

View 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 ]

View 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
}

View 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

View 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

View 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 ]

View 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
}

View 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

View 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

View 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 ]

View 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
}

View 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

View 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

View 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 ]

View 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
}

View 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

View 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

View 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 ]