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

Added all functions that become pointers as separate thread heads.

This commit is contained in:
jespergravgaard 2019-04-04 20:45:52 +02:00
parent 10dd5e4c7b
commit 64b3a07ee6
8 changed files with 732 additions and 7 deletions

View File

@ -26,7 +26,7 @@ public class Pass4ZeroPageCoalesce extends Pass2Base {
public void coalesce() { public void coalesce() {
LinkedHashSet<String> unknownFragments = new LinkedHashSet<>(); LinkedHashSet<String> unknownFragments = new LinkedHashSet<>();
LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet = getProgram().getLiveRangeEquivalenceClassSet(); LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet = getProgram().getLiveRangeEquivalenceClassSet();
Collection<ScopeRef> threads = getThreadHeads(getSymbols()); Collection<ScopeRef> threads = getThreadHeads(getProgram());
boolean change; boolean change;
do { do {
change = coalesce(liveRangeEquivalenceClassSet, threads, unknownFragments); change = coalesce(liveRangeEquivalenceClassSet, threads, unknownFragments);
@ -47,15 +47,16 @@ public class Pass4ZeroPageCoalesce extends Pass2Base {
* *
* @return The threads. * @return The threads.
*/ */
public static Collection<ScopeRef> getThreadHeads(ProgramScope programScope) { public static Collection<ScopeRef> getThreadHeads(Program program) {
ArrayList<ScopeRef> threadHeads = new ArrayList<>(); ArrayList<ScopeRef> threadHeads = new ArrayList<>();
Collection<Procedure> procedures = programScope.getAllProcedures(true); Collection<Procedure> procedures = program.getScope().getAllProcedures(true);
for(Procedure procedure : procedures) { for(Procedure procedure : procedures) {
if(procedure.getInterruptType() != null) {
threadHeads.add(procedure.getRef());
}
if(procedure.getFullName().equals(SymbolRef.MAIN_PROC_NAME)) { if(procedure.getFullName().equals(SymbolRef.MAIN_PROC_NAME)) {
threadHeads.add(procedure.getRef()); threadHeads.add(procedure.getRef());
continue;
}
if(Pass2ConstantIdentification.isAddressOfUsed(procedure.getRef(), program)) {
threadHeads.add(procedure.getRef());
} }
} }
return threadHeads; return threadHeads;

View File

@ -20,7 +20,7 @@ public class Pass4ZeroPageCoalesceAssignment extends Pass2Base {
public void coalesce() { public void coalesce() {
CoalesceVarScores coalesceVarScores = new CoalesceVarScores(getProgram()); CoalesceVarScores coalesceVarScores = new CoalesceVarScores(getProgram());
LinkedHashSet<String> unknownFragments = new LinkedHashSet<>(); LinkedHashSet<String> unknownFragments = new LinkedHashSet<>();
Collection<ScopeRef> threadHeads = Pass4ZeroPageCoalesce.getThreadHeads(getSymbols()); Collection<ScopeRef> threadHeads = Pass4ZeroPageCoalesce.getThreadHeads(getProgram());
boolean change; boolean change;
do { do {

View File

@ -32,6 +32,11 @@ public class TestPrograms {
public TestPrograms() { public TestPrograms() {
} }
@Test
public void testFunctionPointerNoargCall6() throws IOException, URISyntaxException {
compileAndCompare("function-pointer-noarg-call-6");
}
@Test @Test
public void testFunctionPointerNoargCall5() throws IOException, URISyntaxException { public void testFunctionPointerNoargCall5() throws IOException, URISyntaxException {
compileAndCompare("function-pointer-noarg-call-5"); compileAndCompare("function-pointer-noarg-call-5");

View File

@ -0,0 +1,16 @@
// Tests calling into a function pointer with local variables
void main() {
void()* cls = &fn1;
for(byte* cols = $d800; cols<$d800+1000;cols++) {
(*cls)();
cols++;
}
}
void fn1() {
for(byte* screen=$400;screen<$400+1000;screen++)
(*screen)++;
}

View File

@ -0,0 +1,57 @@
// Tests calling into a function pointer with local variables
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
main: {
.label cls = fn1
.label cols = 2
lda #<$d800
sta cols
lda #>$d800
sta cols+1
b1:
jsr cls
inc cols
bne !+
inc cols+1
!:
inc cols
bne !+
inc cols+1
!:
lda cols+1
cmp #>$d800+$3e8
bcc b1
bne !+
lda cols
cmp #<$d800+$3e8
bcc b1
!:
rts
}
fn1: {
.label screen = 4
lda #<$400
sta screen
lda #>$400
sta screen+1
b1:
ldy #0
lda (screen),y
clc
adc #1
sta (screen),y
inc screen
bne !+
inc screen+1
!:
lda screen+1
cmp #>$400+$3e8
bcc b1
bne !+
lda screen
cmp #<$400+$3e8
bcc b1
!:
rts
}

View File

@ -0,0 +1,34 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@1
[5] (byte*) main::cols#3 ← phi( main/((byte*))(word/dword/signed dword) $d800 main::@1/(byte*) main::cols#2 )
[6] call *((const void()*) main::cls#0)
[7] (byte*) main::cols#1 ← ++ (byte*) main::cols#3
[8] (byte*) main::cols#2 ← ++ (byte*) main::cols#1
[9] if((byte*) main::cols#2<(word/dword/signed dword) $d800+(word/signed word/dword/signed dword) $3e8) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[10] return
to:@return
fn1: scope:[fn1] from
[11] phi()
to:fn1::@1
fn1::@1: scope:[fn1] from fn1 fn1::@1
[12] (byte*) fn1::screen#2 ← phi( fn1/((byte*))(word/signed word/dword/signed dword) $400 fn1::@1/(byte*) fn1::screen#1 )
[13] *((byte*) fn1::screen#2) ← ++ *((byte*) fn1::screen#2)
[14] (byte*) fn1::screen#1 ← ++ (byte*) fn1::screen#2
[15] if((byte*) fn1::screen#1<(word/signed word/dword/signed dword) $400+(word/signed word/dword/signed dword) $3e8) goto fn1::@1
to:fn1::@return
fn1::@return: scope:[fn1] from fn1::@1
[16] return
to:@return

View File

@ -0,0 +1,591 @@
Resolved forward reference fn1 to (void()) fn1()
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@2
main: scope:[main] from @2
(void()*~) main::$0 ← & (void()) fn1()
(void()*) main::cls#0 ← (void()*~) main::$0
(byte*) main::cols#0 ← ((byte*)) (word/dword/signed dword) $d800
to:main::@1
main::@1: scope:[main] from main main::@1
(byte*) main::cols#3 ← phi( main/(byte*) main::cols#0 main::@1/(byte*) main::cols#2 )
(void()*) main::cls#1 ← phi( main/(void()*) main::cls#0 main::@1/(void()*) main::cls#1 )
call *((void()*) main::cls#1)
(byte*) main::cols#1 ← ++ (byte*) main::cols#3
(byte*) main::cols#2 ← ++ (byte*) main::cols#1
(word/dword/signed dword~) main::$2 ← (word/dword/signed dword) $d800 + (word/signed word/dword/signed dword) $3e8
(bool~) main::$3 ← (byte*) main::cols#2 < (word/dword/signed dword~) main::$2
if((bool~) main::$3) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
return
to:@return
fn1: scope:[fn1] from
(byte*) fn1::screen#0 ← ((byte*)) (word/signed word/dword/signed dword) $400
to:fn1::@1
fn1::@1: scope:[fn1] from fn1 fn1::@1
(byte*) fn1::screen#2 ← phi( fn1/(byte*) fn1::screen#0 fn1::@1/(byte*) fn1::screen#1 )
*((byte*) fn1::screen#2) ← ++ *((byte*) fn1::screen#2)
(byte*) fn1::screen#1 ← ++ (byte*) fn1::screen#2
(word/signed word/dword/signed dword~) fn1::$0 ← (word/signed word/dword/signed dword) $400 + (word/signed word/dword/signed dword) $3e8
(bool~) fn1::$1 ← (byte*) fn1::screen#1 < (word/signed word/dword/signed dword~) fn1::$0
if((bool~) fn1::$1) goto fn1::@1
to:fn1::@return
fn1::@return: scope:[fn1] from fn1::@1
return
to:@return
@2: scope:[] from @begin
call main
to:@3
@3: scope:[] from @2
to:@end
@end: scope:[] from @3
SYMBOL TABLE SSA
(label) @2
(label) @3
(label) @begin
(label) @end
(void()) fn1()
(word/signed word/dword/signed dword~) fn1::$0
(bool~) fn1::$1
(label) fn1::@1
(label) fn1::@return
(byte*) fn1::screen
(byte*) fn1::screen#0
(byte*) fn1::screen#1
(byte*) fn1::screen#2
(void()) main()
(void()*~) main::$0
(word/dword/signed dword~) main::$2
(bool~) main::$3
(label) main::@1
(label) main::@return
(void()*) main::cls
(void()*) main::cls#0
(void()*) main::cls#1
(byte*) main::cols
(byte*) main::cols#0
(byte*) main::cols#1
(byte*) main::cols#2
(byte*) main::cols#3
Culled Empty Block (label) @3
Successful SSA optimization Pass2CullEmptyBlocks
Alias (void()*) main::cls#0 = (void()*~) main::$0
Successful SSA optimization Pass2AliasElimination
Self Phi Eliminated (void()*) main::cls#1
Successful SSA optimization Pass2SelfPhiElimination
Redundant Phi (void()*) main::cls#1 (void()*) main::cls#0
Successful SSA optimization Pass2RedundantPhiElimination
Simple Condition (bool~) main::$3 [9] if((byte*) main::cols#2<(word/dword/signed dword~) main::$2) goto main::@1
Simple Condition (bool~) fn1::$1 [17] if((byte*) fn1::screen#1<(word/signed word/dword/signed dword~) fn1::$0) goto fn1::@1
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const void()*) main::cls#0 = &fn1
Constant (const byte*) main::cols#0 = ((byte*))$d800
Constant (const word/dword/signed dword) main::$2 = $d800+$3e8
Constant (const byte*) fn1::screen#0 = ((byte*))$400
Constant (const word/signed word/dword/signed dword) fn1::$0 = $400+$3e8
Successful SSA optimization Pass2ConstantIdentification
Inlining constant with var siblings (const byte*) main::cols#0
Inlining constant with var siblings (const byte*) fn1::screen#0
Constant inlined fn1::screen#0 = ((byte*))(word/signed word/dword/signed dword) $400
Constant inlined fn1::$0 = (word/signed word/dword/signed dword) $400+(word/signed word/dword/signed dword) $3e8
Constant inlined main::$2 = (word/dword/signed dword) $d800+(word/signed word/dword/signed dword) $3e8
Constant inlined main::cols#0 = ((byte*))(word/dword/signed dword) $d800
Successful SSA optimization Pass2ConstantInlining
Added new block during phi lifting main::@3(between main::@1 and main::@1)
Added new block during phi lifting fn1::@3(between fn1::@1 and fn1::@1)
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @2
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
Adding NOP phi() at start of fn1
CALL GRAPH
Calls in [] to main:2
Created 2 initial phi equivalence classes
Coalesced [11] main::cols#4 ← main::cols#2
Coalesced [18] fn1::screen#3 ← fn1::screen#1
Coalesced down to 2 phi equivalence classes
Culled Empty Block (label) main::@3
Culled Empty Block (label) fn1::@3
Renumbering block @2 to @1
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
Adding NOP phi() at start of fn1
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@1
[5] (byte*) main::cols#3 ← phi( main/((byte*))(word/dword/signed dword) $d800 main::@1/(byte*) main::cols#2 )
[6] call *((const void()*) main::cls#0)
[7] (byte*) main::cols#1 ← ++ (byte*) main::cols#3
[8] (byte*) main::cols#2 ← ++ (byte*) main::cols#1
[9] if((byte*) main::cols#2<(word/dword/signed dword) $d800+(word/signed word/dword/signed dword) $3e8) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[10] return
to:@return
fn1: scope:[fn1] from
[11] phi()
to:fn1::@1
fn1::@1: scope:[fn1] from fn1 fn1::@1
[12] (byte*) fn1::screen#2 ← phi( fn1/((byte*))(word/signed word/dword/signed dword) $400 fn1::@1/(byte*) fn1::screen#1 )
[13] *((byte*) fn1::screen#2) ← ++ *((byte*) fn1::screen#2)
[14] (byte*) fn1::screen#1 ← ++ (byte*) fn1::screen#2
[15] if((byte*) fn1::screen#1<(word/signed word/dword/signed dword) $400+(word/signed word/dword/signed dword) $3e8) goto fn1::@1
to:fn1::@return
fn1::@return: scope:[fn1] from fn1::@1
[16] return
to:@return
VARIABLE REGISTER WEIGHTS
(void()) fn1()
(byte*) fn1::screen
(byte*) fn1::screen#1 16.5
(byte*) fn1::screen#2 22.0
(void()) main()
(void()*) main::cls
(byte*) main::cols
(byte*) main::cols#1 22.0
(byte*) main::cols#2 16.5
(byte*) main::cols#3 11.0
Initial phi equivalence classes
[ main::cols#3 main::cols#2 ]
[ fn1::screen#2 fn1::screen#1 ]
Added variable main::cols#1 to zero page equivalence class [ main::cols#1 ]
Complete equivalence classes
[ main::cols#3 main::cols#2 ]
[ fn1::screen#2 fn1::screen#1 ]
[ main::cols#1 ]
Allocated zp ZP_WORD:2 [ main::cols#3 main::cols#2 ]
Allocated zp ZP_WORD:4 [ fn1::screen#2 fn1::screen#1 ]
Allocated zp ZP_WORD:6 [ main::cols#1 ]
INITIAL ASM
//SEG0 File Comments
// Tests calling into a function pointer with local variables
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//SEG3 @begin
bbegin:
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG5 @1
b1:
//SEG6 [2] call main
//SEG7 [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG9 @end
bend:
//SEG10 main
main: {
.label cls = fn1
.label cols = 6
.label cols_2 = 2
.label cols_3 = 2
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
//SEG12 [5] phi (byte*) main::cols#3 = ((byte*))(word/dword/signed dword) $d800 [phi:main->main::@1#0] -- pbuz1=pbuc1
lda #<$d800
sta cols_3
lda #>$d800
sta cols_3+1
jmp b1
//SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
b1_from_b1:
//SEG14 [5] phi (byte*) main::cols#3 = (byte*) main::cols#2 [phi:main::@1->main::@1#0] -- register_copy
jmp b1
//SEG15 main::@1
b1:
//SEG16 [6] call *((const void()*) main::cls#0)
jsr cls
//SEG17 [7] (byte*) main::cols#1 ← ++ (byte*) main::cols#3 -- pbuz1=_inc_pbuz2
lda cols_3
clc
adc #1
sta cols
lda cols_3+1
adc #0
sta cols+1
//SEG18 [8] (byte*) main::cols#2 ← ++ (byte*) main::cols#1 -- pbuz1=_inc_pbuz2
lda cols
clc
adc #1
sta cols_2
lda cols+1
adc #0
sta cols_2+1
//SEG19 [9] if((byte*) main::cols#2<(word/dword/signed dword) $d800+(word/signed word/dword/signed dword) $3e8) goto main::@1 -- pbuz1_lt_vwuc1_then_la1
lda cols_2+1
cmp #>$d800+$3e8
bcc b1_from_b1
bne !+
lda cols_2
cmp #<$d800+$3e8
bcc b1_from_b1
!:
jmp breturn
//SEG20 main::@return
breturn:
//SEG21 [10] return
rts
}
//SEG22 fn1
fn1: {
.label screen = 4
//SEG23 [12] phi from fn1 to fn1::@1 [phi:fn1->fn1::@1]
b1_from_fn1:
//SEG24 [12] phi (byte*) fn1::screen#2 = ((byte*))(word/signed word/dword/signed dword) $400 [phi:fn1->fn1::@1#0] -- pbuz1=pbuc1
lda #<$400
sta screen
lda #>$400
sta screen+1
jmp b1
//SEG25 [12] phi from fn1::@1 to fn1::@1 [phi:fn1::@1->fn1::@1]
b1_from_b1:
//SEG26 [12] phi (byte*) fn1::screen#2 = (byte*) fn1::screen#1 [phi:fn1::@1->fn1::@1#0] -- register_copy
jmp b1
//SEG27 fn1::@1
b1:
//SEG28 [13] *((byte*) fn1::screen#2) ← ++ *((byte*) fn1::screen#2) -- _deref_pbuz1=_inc__deref_pbuz1
ldy #0
lda (screen),y
clc
adc #1
ldy #0
sta (screen),y
//SEG29 [14] (byte*) fn1::screen#1 ← ++ (byte*) fn1::screen#2 -- pbuz1=_inc_pbuz1
inc screen
bne !+
inc screen+1
!:
//SEG30 [15] if((byte*) fn1::screen#1<(word/signed word/dword/signed dword) $400+(word/signed word/dword/signed dword) $3e8) goto fn1::@1 -- pbuz1_lt_vwuc1_then_la1
lda screen+1
cmp #>$400+$3e8
bcc b1_from_b1
bne !+
lda screen
cmp #<$400+$3e8
bcc b1_from_b1
!:
jmp breturn
//SEG31 fn1::@return
breturn:
//SEG32 [16] return
rts
}
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [7] (byte*) main::cols#1 ← ++ (byte*) main::cols#3 [ main::cols#1 ] ( main:2 [ main::cols#1 ] ) always clobbers reg byte a
Statement [8] (byte*) main::cols#2 ← ++ (byte*) main::cols#1 [ main::cols#2 ] ( main:2 [ main::cols#2 ] ) always clobbers reg byte a
Statement [9] if((byte*) main::cols#2<(word/dword/signed dword) $d800+(word/signed word/dword/signed dword) $3e8) goto main::@1 [ main::cols#2 ] ( main:2 [ main::cols#2 ] ) always clobbers reg byte a
Statement [13] *((byte*) fn1::screen#2) ← ++ *((byte*) fn1::screen#2) [ fn1::screen#2 ] ( ) always clobbers reg byte a reg byte y
Statement [15] if((byte*) fn1::screen#1<(word/signed word/dword/signed dword) $400+(word/signed word/dword/signed dword) $3e8) goto fn1::@1 [ fn1::screen#1 ] ( ) always clobbers reg byte a
Potential registers zp ZP_WORD:2 [ main::cols#3 main::cols#2 ] : zp ZP_WORD:2 ,
Potential registers zp ZP_WORD:4 [ fn1::screen#2 fn1::screen#1 ] : zp ZP_WORD:4 ,
Potential registers zp ZP_WORD:6 [ main::cols#1 ] : zp ZP_WORD:6 ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 27.5: zp ZP_WORD:2 [ main::cols#3 main::cols#2 ] 22: zp ZP_WORD:6 [ main::cols#1 ]
Uplift Scope [fn1] 38.5: zp ZP_WORD:4 [ fn1::screen#2 fn1::screen#1 ]
Uplift Scope []
Uplifting [main] best 1494 combination zp ZP_WORD:2 [ main::cols#3 main::cols#2 ] zp ZP_WORD:6 [ main::cols#1 ]
Uplifting [fn1] best 1494 combination zp ZP_WORD:4 [ fn1::screen#2 fn1::screen#1 ]
Uplifting [] best 1494 combination
Coalescing zero page register with common assignment [ zp ZP_WORD:2 [ main::cols#3 main::cols#2 ] ] with [ zp ZP_WORD:6 [ main::cols#1 ] ] - score: 2
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Tests calling into a function pointer with local variables
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//SEG3 @begin
bbegin:
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG5 @1
b1:
//SEG6 [2] call main
//SEG7 [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG9 @end
bend:
//SEG10 main
main: {
.label cls = fn1
.label cols = 2
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
//SEG12 [5] phi (byte*) main::cols#3 = ((byte*))(word/dword/signed dword) $d800 [phi:main->main::@1#0] -- pbuz1=pbuc1
lda #<$d800
sta cols
lda #>$d800
sta cols+1
jmp b1
//SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
b1_from_b1:
//SEG14 [5] phi (byte*) main::cols#3 = (byte*) main::cols#2 [phi:main::@1->main::@1#0] -- register_copy
jmp b1
//SEG15 main::@1
b1:
//SEG16 [6] call *((const void()*) main::cls#0)
jsr cls
//SEG17 [7] (byte*) main::cols#1 ← ++ (byte*) main::cols#3 -- pbuz1=_inc_pbuz1
inc cols
bne !+
inc cols+1
!:
//SEG18 [8] (byte*) main::cols#2 ← ++ (byte*) main::cols#1 -- pbuz1=_inc_pbuz1
inc cols
bne !+
inc cols+1
!:
//SEG19 [9] if((byte*) main::cols#2<(word/dword/signed dword) $d800+(word/signed word/dword/signed dword) $3e8) goto main::@1 -- pbuz1_lt_vwuc1_then_la1
lda cols+1
cmp #>$d800+$3e8
bcc b1_from_b1
bne !+
lda cols
cmp #<$d800+$3e8
bcc b1_from_b1
!:
jmp breturn
//SEG20 main::@return
breturn:
//SEG21 [10] return
rts
}
//SEG22 fn1
fn1: {
.label screen = 4
//SEG23 [12] phi from fn1 to fn1::@1 [phi:fn1->fn1::@1]
b1_from_fn1:
//SEG24 [12] phi (byte*) fn1::screen#2 = ((byte*))(word/signed word/dword/signed dword) $400 [phi:fn1->fn1::@1#0] -- pbuz1=pbuc1
lda #<$400
sta screen
lda #>$400
sta screen+1
jmp b1
//SEG25 [12] phi from fn1::@1 to fn1::@1 [phi:fn1::@1->fn1::@1]
b1_from_b1:
//SEG26 [12] phi (byte*) fn1::screen#2 = (byte*) fn1::screen#1 [phi:fn1::@1->fn1::@1#0] -- register_copy
jmp b1
//SEG27 fn1::@1
b1:
//SEG28 [13] *((byte*) fn1::screen#2) ← ++ *((byte*) fn1::screen#2) -- _deref_pbuz1=_inc__deref_pbuz1
ldy #0
lda (screen),y
clc
adc #1
ldy #0
sta (screen),y
//SEG29 [14] (byte*) fn1::screen#1 ← ++ (byte*) fn1::screen#2 -- pbuz1=_inc_pbuz1
inc screen
bne !+
inc screen+1
!:
//SEG30 [15] if((byte*) fn1::screen#1<(word/signed word/dword/signed dword) $400+(word/signed word/dword/signed dword) $3e8) goto fn1::@1 -- pbuz1_lt_vwuc1_then_la1
lda screen+1
cmp #>$400+$3e8
bcc b1_from_b1
bne !+
lda screen
cmp #<$400+$3e8
bcc b1_from_b1
!:
jmp breturn
//SEG31 fn1::@return
breturn:
//SEG32 [16] return
rts
}
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp b1
Removing instruction jmp breturn
Removing instruction jmp b1
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction ldy #0
Succesful ASM optimization Pass5UnnecesaryLoadElimination
Replacing label b1_from_b1 with b1
Replacing label b1_from_b1 with b1
Replacing label b1_from_b1 with b1
Replacing label b1_from_b1 with b1
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction main_from_b1:
Removing instruction bend_from_b1:
Removing instruction b1_from_b1:
Removing instruction b1_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction b1_from_main:
Removing instruction breturn:
Removing instruction b1_from_fn1:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction jmp b1
Removing instruction jmp b1
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(void()) fn1()
(label) fn1::@1
(label) fn1::@return
(byte*) fn1::screen
(byte*) fn1::screen#1 screen zp ZP_WORD:4 16.5
(byte*) fn1::screen#2 screen zp ZP_WORD:4 22.0
(void()) main()
(label) main::@1
(label) main::@return
(void()*) main::cls
(const void()*) main::cls#0 cls = &(void()) fn1()
(byte*) main::cols
(byte*) main::cols#1 cols zp ZP_WORD:2 22.0
(byte*) main::cols#2 cols zp ZP_WORD:2 16.5
(byte*) main::cols#3 cols zp ZP_WORD:2 11.0
zp ZP_WORD:2 [ main::cols#3 main::cols#2 main::cols#1 ]
zp ZP_WORD:4 [ fn1::screen#2 fn1::screen#1 ]
FINAL ASSEMBLER
Score: 1172
//SEG0 File Comments
// Tests calling into a function pointer with local variables
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//SEG3 @begin
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
//SEG5 @1
//SEG6 [2] call main
//SEG7 [4] phi from @1 to main [phi:@1->main]
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
//SEG9 @end
//SEG10 main
main: {
.label cls = fn1
.label cols = 2
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
//SEG12 [5] phi (byte*) main::cols#3 = ((byte*))(word/dword/signed dword) $d800 [phi:main->main::@1#0] -- pbuz1=pbuc1
lda #<$d800
sta cols
lda #>$d800
sta cols+1
//SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
//SEG14 [5] phi (byte*) main::cols#3 = (byte*) main::cols#2 [phi:main::@1->main::@1#0] -- register_copy
//SEG15 main::@1
b1:
//SEG16 [6] call *((const void()*) main::cls#0)
jsr cls
//SEG17 [7] (byte*) main::cols#1 ← ++ (byte*) main::cols#3 -- pbuz1=_inc_pbuz1
inc cols
bne !+
inc cols+1
!:
//SEG18 [8] (byte*) main::cols#2 ← ++ (byte*) main::cols#1 -- pbuz1=_inc_pbuz1
inc cols
bne !+
inc cols+1
!:
//SEG19 [9] if((byte*) main::cols#2<(word/dword/signed dword) $d800+(word/signed word/dword/signed dword) $3e8) goto main::@1 -- pbuz1_lt_vwuc1_then_la1
lda cols+1
cmp #>$d800+$3e8
bcc b1
bne !+
lda cols
cmp #<$d800+$3e8
bcc b1
!:
//SEG20 main::@return
//SEG21 [10] return
rts
}
//SEG22 fn1
fn1: {
.label screen = 4
//SEG23 [12] phi from fn1 to fn1::@1 [phi:fn1->fn1::@1]
//SEG24 [12] phi (byte*) fn1::screen#2 = ((byte*))(word/signed word/dword/signed dword) $400 [phi:fn1->fn1::@1#0] -- pbuz1=pbuc1
lda #<$400
sta screen
lda #>$400
sta screen+1
//SEG25 [12] phi from fn1::@1 to fn1::@1 [phi:fn1::@1->fn1::@1]
//SEG26 [12] phi (byte*) fn1::screen#2 = (byte*) fn1::screen#1 [phi:fn1::@1->fn1::@1#0] -- register_copy
//SEG27 fn1::@1
b1:
//SEG28 [13] *((byte*) fn1::screen#2) ← ++ *((byte*) fn1::screen#2) -- _deref_pbuz1=_inc__deref_pbuz1
ldy #0
lda (screen),y
clc
adc #1
sta (screen),y
//SEG29 [14] (byte*) fn1::screen#1 ← ++ (byte*) fn1::screen#2 -- pbuz1=_inc_pbuz1
inc screen
bne !+
inc screen+1
!:
//SEG30 [15] if((byte*) fn1::screen#1<(word/signed word/dword/signed dword) $400+(word/signed word/dword/signed dword) $3e8) goto fn1::@1 -- pbuz1_lt_vwuc1_then_la1
lda screen+1
cmp #>$400+$3e8
bcc b1
bne !+
lda screen
cmp #<$400+$3e8
bcc b1
!:
//SEG31 fn1::@return
//SEG32 [16] return
rts
}

View File

@ -0,0 +1,21 @@
(label) @1
(label) @begin
(label) @end
(void()) fn1()
(label) fn1::@1
(label) fn1::@return
(byte*) fn1::screen
(byte*) fn1::screen#1 screen zp ZP_WORD:4 16.5
(byte*) fn1::screen#2 screen zp ZP_WORD:4 22.0
(void()) main()
(label) main::@1
(label) main::@return
(void()*) main::cls
(const void()*) main::cls#0 cls = &(void()) fn1()
(byte*) main::cols
(byte*) main::cols#1 cols zp ZP_WORD:2 22.0
(byte*) main::cols#2 cols zp ZP_WORD:2 16.5
(byte*) main::cols#3 cols zp ZP_WORD:2 11.0
zp ZP_WORD:2 [ main::cols#3 main::cols#2 main::cols#1 ]
zp ZP_WORD:4 [ fn1::screen#2 fn1::screen#1 ]