mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-27 19:50:10 +00:00
Optimized live ranges by statement idx in PassNLiveRangeVariables. Added example of how to use segments to compile code meant for transfer to zeropage.
This commit is contained in:
parent
33c39bfd52
commit
7fb7d3acf6
@ -33,6 +33,14 @@ public class LiveRange {
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying statement intervals
|
||||
* @return The intervals
|
||||
*/
|
||||
public List<LiveInterval> getIntervals() {
|
||||
return intervals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an index to the live range
|
||||
*
|
||||
|
@ -78,8 +78,55 @@ public class LiveRangeVariables {
|
||||
return liveRanges.get(variable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of variable live ranges
|
||||
* @return The number of variable live ranges
|
||||
*/
|
||||
public int size() {
|
||||
return liveRanges.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get variable live ranges by statement index. Usable for quick access if you plan to iterate many statements.
|
||||
* @return variable live ranges by statement index
|
||||
*/
|
||||
public LiveRangeVariablesByStatement getLiveRangeVariablesByStatement() {
|
||||
LiveRangeVariablesByStatement liveRangeVariablesByStatement = new LiveRangeVariablesByStatement();
|
||||
for(Map.Entry<VariableRef, LiveRange> variableRefLiveRangeEntry : liveRanges.entrySet()) {
|
||||
VariableRef variableRef = variableRefLiveRangeEntry.getKey();
|
||||
LiveRange liveRange = variableRefLiveRangeEntry.getValue();
|
||||
for(LiveRange.LiveInterval liveInterval : liveRange.getIntervals()) {
|
||||
for(int stmtIdx = liveInterval.getFirstStatementIdx(); stmtIdx<= liveInterval.getLastStatementIdx(); stmtIdx++) {
|
||||
liveRangeVariablesByStatement.addAlive(stmtIdx, variableRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
return liveRangeVariablesByStatement;
|
||||
}
|
||||
|
||||
/** Variable live ranges by statement index. Usable for quick access if you plan to iterate many statements. */
|
||||
public static class LiveRangeVariablesByStatement {
|
||||
|
||||
private ArrayList<List<VariableRef>> aliveByStatementIdx;
|
||||
|
||||
public LiveRangeVariablesByStatement() {
|
||||
this.aliveByStatementIdx = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void addAlive(int statementIdx, VariableRef variableRef) {
|
||||
while(statementIdx>=aliveByStatementIdx.size()) {
|
||||
aliveByStatementIdx.add(new ArrayList<>());
|
||||
}
|
||||
List<VariableRef> variableRefs = aliveByStatementIdx.get(statementIdx);
|
||||
variableRefs.add(variableRef);
|
||||
}
|
||||
|
||||
|
||||
public List<VariableRef> getAlive(int statementIdx) {
|
||||
if(statementIdx>=aliveByStatementIdx.size())
|
||||
return new ArrayList<>();
|
||||
return aliveByStatementIdx.get(statementIdx);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -80,9 +80,10 @@ public class PassNCalcLiveRangeVariables extends PassNCalcBase<LiveRangeVariable
|
||||
private boolean calculateLiveRanges(LiveRangeVariables liveRanges) {
|
||||
VariableReferenceInfos referenceInfo = getProgram().getVariableReferenceInfos();
|
||||
boolean modified = false;
|
||||
LiveRangeVariables.LiveRangeVariablesByStatement liveRangeVariablesByStatement = liveRanges.getLiveRangeVariablesByStatement();
|
||||
for(ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) {
|
||||
for(Statement stmt : block.getStatements()) {
|
||||
List<VariableRef> aliveNextStmt = liveRanges.getAlive(stmt.getIndex());
|
||||
List<VariableRef> aliveNextStmt = liveRangeVariablesByStatement.getAlive(stmt.getIndex());
|
||||
Collection<VariableRef> definedNextStmt = referenceInfo.getDefinedVars(stmt);
|
||||
initLiveRange(liveRanges, definedNextStmt);
|
||||
Collection<PreviousStatement> previousStmts = getPreviousStatements(stmt);
|
||||
|
@ -36,6 +36,13 @@ public class TestPrograms {
|
||||
public TestPrograms() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZpCode() throws IOException, URISyntaxException {
|
||||
compileAndCompare("examples/zpcode/zpcode");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Fix parameter type problem - https://gitlab.com/camelot/kickc/issues/299
|
||||
/*
|
||||
@Test
|
||||
|
46
src/test/kc/examples/zpcode/zpcode.kc
Normal file
46
src/test/kc/examples/zpcode/zpcode.kc
Normal file
@ -0,0 +1,46 @@
|
||||
// Example showing how to use KickAsm segments to compile meant to be transfered to zeropage before execution.
|
||||
// The linker-file defines the ZpCode segment to be on zeropage and does not include it directly in the PRG-file (by excluding it from the Program segment).
|
||||
// Instead the compiled code is added as an array of bytes in "normal" memory - and transferred to zeropage at the start of the program
|
||||
|
||||
#pragma link("zpcode.ld")
|
||||
|
||||
char* RASTER = 0xd012;
|
||||
char* BGCOL = 0xd020;
|
||||
|
||||
void main() {
|
||||
asm { sei }
|
||||
// Transfer ZP-code to zeropage
|
||||
char* zpCode = (char*)&zpLoop;
|
||||
for(char i=0;i<20;i++)
|
||||
zpCode[i] = zpCodeData[i];
|
||||
|
||||
while(true) {
|
||||
while(*RASTER!=0xff) {}
|
||||
// Call code in normal memory
|
||||
loop();
|
||||
// Call code on zeropage
|
||||
zpLoop();
|
||||
*BGCOL = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Code in "normal" memory
|
||||
void loop() {
|
||||
for(char i:0..100) {
|
||||
(*BGCOL)--;
|
||||
}
|
||||
}
|
||||
|
||||
// Array containing the zeropage code to be transferred to zeropage before execution
|
||||
char[] zpCodeData = kickasm {{
|
||||
.segmentout [segments="ZpCode"]
|
||||
}};
|
||||
|
||||
// Code that will be placed on zeropage
|
||||
// It won't be output to the PRG-file directly because it is not included in the Program segment in the linker-file.
|
||||
#pragma code_seg(ZpCode)
|
||||
void zpLoop() {
|
||||
for(char i:0..100) {
|
||||
(*BGCOL)++;
|
||||
}
|
||||
}
|
9
src/test/kc/examples/zpcode/zpcode.ld
Normal file
9
src/test/kc/examples/zpcode/zpcode.ld
Normal file
@ -0,0 +1,9 @@
|
||||
.file [name="%O.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$0810]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef ZpCode [start=$80]
|
||||
.segment Basic
|
||||
:BasicUpstart(main)
|
||||
|
64
src/test/ref/examples/zpcode/zpcode.asm
Normal file
64
src/test/ref/examples/zpcode/zpcode.asm
Normal file
@ -0,0 +1,64 @@
|
||||
// Example showing how to use KickAsm segments to compile meant to be transfered to zeropage before execution.
|
||||
// The linker-file defines the ZpCode segment to be on zeropage and does not include it directly in the PRG-file (by excluding it from the Program segment).
|
||||
// Instead the compiled code is added as an array of bytes in "normal" memory - and transferred to zeropage at the start of the program
|
||||
.file [name="zpcode.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$0810]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef ZpCode [start=$80]
|
||||
.segment Basic
|
||||
:BasicUpstart(main)
|
||||
|
||||
|
||||
.label RASTER = $d012
|
||||
.label BGCOL = $d020
|
||||
.segment Code
|
||||
main: {
|
||||
.label zpCode = zpLoop
|
||||
sei
|
||||
ldx #0
|
||||
b1:
|
||||
cpx #$14
|
||||
bcc b2
|
||||
b3:
|
||||
lda #$ff
|
||||
cmp RASTER
|
||||
bne b3
|
||||
jsr loop
|
||||
jsr zpLoop
|
||||
lda #0
|
||||
sta BGCOL
|
||||
jmp b3
|
||||
b2:
|
||||
lda zpCodeData,x
|
||||
sta zpCode,x
|
||||
inx
|
||||
jmp b1
|
||||
}
|
||||
.segment ZpCode
|
||||
zpLoop: {
|
||||
ldx #0
|
||||
b1:
|
||||
inc BGCOL
|
||||
inx
|
||||
cpx #$65
|
||||
bne b1
|
||||
rts
|
||||
}
|
||||
.segment Code
|
||||
// Code in "normal" memory
|
||||
loop: {
|
||||
ldx #0
|
||||
b1:
|
||||
dec BGCOL
|
||||
inx
|
||||
cpx #$65
|
||||
bne b1
|
||||
rts
|
||||
}
|
||||
.segment Data
|
||||
// Array containing the zeropage code to be transferred to zeropage before execution
|
||||
zpCodeData:
|
||||
.segmentout [segments="ZpCode"]
|
||||
|
58
src/test/ref/examples/zpcode/zpcode.cfg
Normal file
58
src/test/ref/examples/zpcode/zpcode.cfg
Normal file
@ -0,0 +1,58 @@
|
||||
@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
|
||||
asm { sei }
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@2
|
||||
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
|
||||
[6] if((byte) main::i#2<(byte) $14) goto main::@2
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::@3 main::@6
|
||||
[7] if(*((const byte*) RASTER#0)!=(byte) $ff) goto main::@3
|
||||
to:main::@4
|
||||
main::@4: scope:[main] from main::@3
|
||||
[8] phi()
|
||||
[9] call loop
|
||||
to:main::@5
|
||||
main::@5: scope:[main] from main::@4
|
||||
[10] phi()
|
||||
[11] call zpLoop
|
||||
to:main::@6
|
||||
main::@6: scope:[main] from main::@5
|
||||
[12] *((const byte*) BGCOL#0) ← (byte) 0
|
||||
to:main::@3
|
||||
main::@2: scope:[main] from main::@1
|
||||
[13] *((const byte*) main::zpCode#0 + (byte) main::i#2) ← *((const byte[]) zpCodeData#0 + (byte) main::i#2)
|
||||
[14] (byte) main::i#1 ← ++ (byte) main::i#2
|
||||
to:main::@1
|
||||
zpLoop: scope:[zpLoop] from main::@5
|
||||
[15] phi()
|
||||
to:zpLoop::@1
|
||||
zpLoop::@1: scope:[zpLoop] from zpLoop zpLoop::@1
|
||||
[16] (byte) zpLoop::i#2 ← phi( zpLoop/(byte) 0 zpLoop::@1/(byte) zpLoop::i#1 )
|
||||
[17] *((const byte*) BGCOL#0) ← ++ *((const byte*) BGCOL#0)
|
||||
[18] (byte) zpLoop::i#1 ← ++ (byte) zpLoop::i#2
|
||||
[19] if((byte) zpLoop::i#1!=(byte) $65) goto zpLoop::@1
|
||||
to:zpLoop::@return
|
||||
zpLoop::@return: scope:[zpLoop] from zpLoop::@1
|
||||
[20] return
|
||||
to:@return
|
||||
loop: scope:[loop] from main::@4
|
||||
[21] phi()
|
||||
to:loop::@1
|
||||
loop::@1: scope:[loop] from loop loop::@1
|
||||
[22] (byte) loop::i#2 ← phi( loop/(byte) 0 loop::@1/(byte) loop::i#1 )
|
||||
[23] *((const byte*) BGCOL#0) ← -- *((const byte*) BGCOL#0)
|
||||
[24] (byte) loop::i#1 ← ++ (byte) loop::i#2
|
||||
[25] if((byte) loop::i#1!=(byte) $65) goto loop::@1
|
||||
to:loop::@return
|
||||
loop::@return: scope:[loop] from loop::@1
|
||||
[26] return
|
||||
to:@return
|
922
src/test/ref/examples/zpcode/zpcode.log
Normal file
922
src/test/ref/examples/zpcode/zpcode.log
Normal file
@ -0,0 +1,922 @@
|
||||
Loading link script "zpcode.ld"
|
||||
Resolved forward reference zpLoop to (void()) zpLoop()
|
||||
Resolved forward reference zpCodeData to (byte[]) zpCodeData
|
||||
Identified constant variable (byte*) RASTER
|
||||
Identified constant variable (byte*) BGCOL
|
||||
Culled Empty Block (label) main::@4
|
||||
Culled Empty Block (label) main::@3
|
||||
Culled Empty Block (label) main::@5
|
||||
Culled Empty Block (label) main::@6
|
||||
Culled Empty Block (label) main::@8
|
||||
Culled Empty Block (label) main::@17
|
||||
Culled Empty Block (label) main::@9
|
||||
Culled Empty Block (label) main::@18
|
||||
Culled Empty Block (label) main::@11
|
||||
Culled Empty Block (label) main::@13
|
||||
Culled Empty Block (label) main::@14
|
||||
Culled Empty Block (label) main::@15
|
||||
Culled Empty Block (label) main::@16
|
||||
Culled Empty Block (label) @1
|
||||
Culled Empty Block (label) loop::@2
|
||||
Culled Empty Block (label) zpLoop::@2
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
@begin: scope:[] from
|
||||
(byte*) RASTER#0 ← ((byte*)) (number) $d012
|
||||
(byte*) BGCOL#0 ← ((byte*)) (number) $d020
|
||||
to:@2
|
||||
main: scope:[main] from @3
|
||||
asm { sei }
|
||||
(void()*~) main::$0 ← & (void()) zpLoop()
|
||||
(byte*~) main::$1 ← ((byte*)) (void()*~) main::$0
|
||||
(byte*) main::zpCode#0 ← (byte*~) main::$1
|
||||
(byte) main::i#0 ← (number) 0
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@2
|
||||
(byte*) main::zpCode#2 ← phi( main/(byte*) main::zpCode#0 main::@2/(byte*) main::zpCode#1 )
|
||||
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 )
|
||||
(bool~) main::$2 ← (byte) main::i#2 < (number) $14
|
||||
if((bool~) main::$2) goto main::@2
|
||||
to:main::@7
|
||||
main::@2: scope:[main] from main::@1
|
||||
(byte*) main::zpCode#1 ← phi( main::@1/(byte*) main::zpCode#2 )
|
||||
(byte) main::i#3 ← phi( main::@1/(byte) main::i#2 )
|
||||
*((byte*) main::zpCode#1 + (byte) main::i#3) ← *((byte[]) zpCodeData#0 + (byte) main::i#3)
|
||||
(byte) main::i#1 ← ++ (byte) main::i#3
|
||||
to:main::@1
|
||||
main::@7: scope:[main] from main::@1 main::@20
|
||||
if(true) goto main::@10
|
||||
to:main::@return
|
||||
main::@10: scope:[main] from main::@10 main::@7
|
||||
(bool~) main::$3 ← *((byte*) RASTER#0) != (number) $ff
|
||||
if((bool~) main::$3) goto main::@10
|
||||
to:main::@12
|
||||
main::@12: scope:[main] from main::@10
|
||||
call loop
|
||||
to:main::@19
|
||||
main::@19: scope:[main] from main::@12
|
||||
call zpLoop
|
||||
to:main::@20
|
||||
main::@20: scope:[main] from main::@19
|
||||
*((byte*) BGCOL#0) ← (number) 0
|
||||
to:main::@7
|
||||
main::@return: scope:[main] from main::@7
|
||||
return
|
||||
to:@return
|
||||
loop: scope:[loop] from main::@12
|
||||
(byte) loop::i#0 ← (byte) 0
|
||||
to:loop::@1
|
||||
loop::@1: scope:[loop] from loop loop::@1
|
||||
(byte) loop::i#2 ← phi( loop/(byte) loop::i#0 loop::@1/(byte) loop::i#1 )
|
||||
*((byte*) BGCOL#0) ← -- *((byte*) BGCOL#0)
|
||||
(byte) loop::i#1 ← (byte) loop::i#2 + rangenext(0,$64)
|
||||
(bool~) loop::$1 ← (byte) loop::i#1 != rangelast(0,$64)
|
||||
if((bool~) loop::$1) goto loop::@1
|
||||
to:loop::@return
|
||||
loop::@return: scope:[loop] from loop::@1
|
||||
return
|
||||
to:@return
|
||||
@2: scope:[] from @begin
|
||||
(byte[]) zpCodeData#0 ← kickasm {{ .segmentout [segments="ZpCode"]
|
||||
}}
|
||||
to:@3
|
||||
zpLoop: scope:[zpLoop] from main::@19
|
||||
(byte) zpLoop::i#0 ← (byte) 0
|
||||
to:zpLoop::@1
|
||||
zpLoop::@1: scope:[zpLoop] from zpLoop zpLoop::@1
|
||||
(byte) zpLoop::i#2 ← phi( zpLoop/(byte) zpLoop::i#0 zpLoop::@1/(byte) zpLoop::i#1 )
|
||||
*((byte*) BGCOL#0) ← ++ *((byte*) BGCOL#0)
|
||||
(byte) zpLoop::i#1 ← (byte) zpLoop::i#2 + rangenext(0,$64)
|
||||
(bool~) zpLoop::$1 ← (byte) zpLoop::i#1 != rangelast(0,$64)
|
||||
if((bool~) zpLoop::$1) goto zpLoop::@1
|
||||
to:zpLoop::@return
|
||||
zpLoop::@return: scope:[zpLoop] from zpLoop::@1
|
||||
return
|
||||
to:@return
|
||||
@3: scope:[] from @2
|
||||
call main
|
||||
to:@4
|
||||
@4: scope:[] from @3
|
||||
to:@end
|
||||
@end: scope:[] from @4
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
(label) @2
|
||||
(label) @3
|
||||
(label) @4
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(byte*) BGCOL
|
||||
(byte*) BGCOL#0
|
||||
(byte*) RASTER
|
||||
(byte*) RASTER#0
|
||||
(void()) loop()
|
||||
(bool~) loop::$1
|
||||
(label) loop::@1
|
||||
(label) loop::@return
|
||||
(byte) loop::i
|
||||
(byte) loop::i#0
|
||||
(byte) loop::i#1
|
||||
(byte) loop::i#2
|
||||
(void()) main()
|
||||
(void()*~) main::$0
|
||||
(byte*~) main::$1
|
||||
(bool~) main::$2
|
||||
(bool~) main::$3
|
||||
(label) main::@1
|
||||
(label) main::@10
|
||||
(label) main::@12
|
||||
(label) main::@19
|
||||
(label) main::@2
|
||||
(label) main::@20
|
||||
(label) main::@7
|
||||
(label) main::@return
|
||||
(byte) main::i
|
||||
(byte) main::i#0
|
||||
(byte) main::i#1
|
||||
(byte) main::i#2
|
||||
(byte) main::i#3
|
||||
(byte*) main::zpCode
|
||||
(byte*) main::zpCode#0
|
||||
(byte*) main::zpCode#1
|
||||
(byte*) main::zpCode#2
|
||||
(byte[]) zpCodeData
|
||||
(byte[]) zpCodeData#0
|
||||
(void()) zpLoop()
|
||||
(bool~) zpLoop::$1
|
||||
(label) zpLoop::@1
|
||||
(label) zpLoop::@return
|
||||
(byte) zpLoop::i
|
||||
(byte) zpLoop::i#0
|
||||
(byte) zpLoop::i#1
|
||||
(byte) zpLoop::i#2
|
||||
|
||||
Adding number conversion cast (unumber) 0 in (byte) main::i#0 ← (number) 0
|
||||
Adding number conversion cast (unumber) $14 in (bool~) main::$2 ← (byte) main::i#2 < (number) $14
|
||||
Adding number conversion cast (unumber) $ff in (bool~) main::$3 ← *((byte*) RASTER#0) != (number) $ff
|
||||
Adding number conversion cast (unumber) 0 in *((byte*) BGCOL#0) ← (number) 0
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Inlining cast (byte*) RASTER#0 ← (byte*)(number) $d012
|
||||
Inlining cast (byte*) BGCOL#0 ← (byte*)(number) $d020
|
||||
Inlining cast (byte*~) main::$1 ← (byte*)(void()*~) main::$0
|
||||
Inlining cast (byte) main::i#0 ← (unumber)(number) 0
|
||||
Inlining cast *((byte*) BGCOL#0) ← (unumber)(number) 0
|
||||
Successful SSA optimization Pass2InlineCast
|
||||
Simplifying constant pointer cast (byte*) 53266
|
||||
Simplifying constant pointer cast (byte*) 53280
|
||||
Simplifying constant integer cast 0
|
||||
Simplifying constant integer cast $14
|
||||
Simplifying constant integer cast $ff
|
||||
Simplifying constant integer cast 0
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (byte) 0
|
||||
Finalized unsigned number type (byte) $14
|
||||
Finalized unsigned number type (byte) $ff
|
||||
Finalized unsigned number type (byte) 0
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Alias (byte*) main::zpCode#0 = (byte*~) main::$1
|
||||
Alias (byte) main::i#2 = (byte) main::i#3
|
||||
Alias (byte*) main::zpCode#1 = (byte*) main::zpCode#2
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Identical Phi Values (byte*) main::zpCode#1 (byte*) main::zpCode#0
|
||||
Successful SSA optimization Pass2IdenticalPhiElimination
|
||||
Simple Condition (bool~) main::$2 [9] if((byte) main::i#2<(byte) $14) goto main::@2
|
||||
Simple Condition (bool~) main::$3 [15] if(*((byte*) RASTER#0)!=(byte) $ff) goto main::@10
|
||||
Simple Condition (bool~) loop::$1 [25] if((byte) loop::i#1!=rangelast(0,$64)) goto loop::@1
|
||||
Simple Condition (bool~) zpLoop::$1 [33] if((byte) zpLoop::i#1!=rangelast(0,$64)) goto zpLoop::@1
|
||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||
Constant right-side identified [3] (void()*~) main::$0 ← & (void()) zpLoop()
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant (const byte*) RASTER#0 = (byte*) 53266
|
||||
Constant (const byte*) BGCOL#0 = (byte*) 53280
|
||||
Constant (const void()*) main::$0 = &zpLoop
|
||||
Constant (const byte) main::i#0 = 0
|
||||
Constant (const byte) loop::i#0 = 0
|
||||
Constant (const byte[]) zpCodeData#0 = kickasm {{ .segmentout [segments="ZpCode"]
|
||||
}}
|
||||
Constant (const byte) zpLoop::i#0 = 0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Constant value identified (byte*)main::$0 in [4] (byte*) main::zpCode#0 ← (byte*)(const void()*) main::$0
|
||||
Successful SSA optimization Pass2ConstantValues
|
||||
if() condition always true - replacing block destination [13] if(true) goto main::@10
|
||||
Successful SSA optimization Pass2ConstantIfs
|
||||
Resolved ranged next value [23] loop::i#1 ← ++ loop::i#2 to ++
|
||||
Resolved ranged comparison value [25] if(loop::i#1!=rangelast(0,$64)) goto loop::@1 to (number) $65
|
||||
Resolved ranged next value [31] zpLoop::i#1 ← ++ zpLoop::i#2 to ++
|
||||
Resolved ranged comparison value [33] if(zpLoop::i#1!=rangelast(0,$64)) goto zpLoop::@1 to (number) $65
|
||||
Removing unused block main::@return
|
||||
Successful SSA optimization Pass2EliminateUnusedBlocks
|
||||
Adding number conversion cast (unumber) $65 in if((byte) loop::i#1!=(number) $65) goto loop::@1
|
||||
Adding number conversion cast (unumber) $65 in if((byte) zpLoop::i#1!=(number) $65) goto zpLoop::@1
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Simplifying constant integer cast $65
|
||||
Simplifying constant integer cast $65
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (byte) $65
|
||||
Finalized unsigned number type (byte) $65
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Constant (const byte*) main::zpCode#0 = (byte*)main::$0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Inlining constant with var siblings (const byte) main::i#0
|
||||
Inlining constant with var siblings (const byte) loop::i#0
|
||||
Inlining constant with var siblings (const byte) zpLoop::i#0
|
||||
Constant inlined main::i#0 = (byte) 0
|
||||
Constant inlined loop::i#0 = (byte) 0
|
||||
Constant inlined zpLoop::i#0 = (byte) 0
|
||||
Constant inlined main::$0 = &(void()) zpLoop()
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Added new block during phi lifting loop::@3(between loop::@1 and loop::@1)
|
||||
Added new block during phi lifting zpLoop::@3(between zpLoop::@1 and zpLoop::@1)
|
||||
Adding NOP phi() at start of @begin
|
||||
Adding NOP phi() at start of @2
|
||||
Adding NOP phi() at start of @3
|
||||
Adding NOP phi() at start of @4
|
||||
Adding NOP phi() at start of @end
|
||||
Adding NOP phi() at start of main::@7
|
||||
Adding NOP phi() at start of main::@12
|
||||
Adding NOP phi() at start of main::@19
|
||||
Adding NOP phi() at start of zpLoop
|
||||
Adding NOP phi() at start of loop
|
||||
CALL GRAPH
|
||||
Calls in [] to main:3
|
||||
Calls in [main] to loop:12 zpLoop:14
|
||||
|
||||
Created 3 initial phi equivalence classes
|
||||
Coalesced [18] main::i#4 ← main::i#1
|
||||
Coalesced [25] zpLoop::i#3 ← zpLoop::i#1
|
||||
Coalesced [32] loop::i#3 ← loop::i#1
|
||||
Coalesced down to 3 phi equivalence classes
|
||||
Culled Empty Block (label) @2
|
||||
Culled Empty Block (label) @4
|
||||
Culled Empty Block (label) main::@7
|
||||
Culled Empty Block (label) zpLoop::@3
|
||||
Culled Empty Block (label) loop::@3
|
||||
Renumbering block @3 to @1
|
||||
Renumbering block main::@10 to main::@3
|
||||
Renumbering block main::@12 to main::@4
|
||||
Renumbering block main::@19 to main::@5
|
||||
Renumbering block main::@20 to main::@6
|
||||
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::@4
|
||||
Adding NOP phi() at start of main::@5
|
||||
Adding NOP phi() at start of zpLoop
|
||||
Adding NOP phi() at start of loop
|
||||
|
||||
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
|
||||
asm { sei }
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@2
|
||||
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
|
||||
[6] if((byte) main::i#2<(byte) $14) goto main::@2
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::@3 main::@6
|
||||
[7] if(*((const byte*) RASTER#0)!=(byte) $ff) goto main::@3
|
||||
to:main::@4
|
||||
main::@4: scope:[main] from main::@3
|
||||
[8] phi()
|
||||
[9] call loop
|
||||
to:main::@5
|
||||
main::@5: scope:[main] from main::@4
|
||||
[10] phi()
|
||||
[11] call zpLoop
|
||||
to:main::@6
|
||||
main::@6: scope:[main] from main::@5
|
||||
[12] *((const byte*) BGCOL#0) ← (byte) 0
|
||||
to:main::@3
|
||||
main::@2: scope:[main] from main::@1
|
||||
[13] *((const byte*) main::zpCode#0 + (byte) main::i#2) ← *((const byte[]) zpCodeData#0 + (byte) main::i#2)
|
||||
[14] (byte) main::i#1 ← ++ (byte) main::i#2
|
||||
to:main::@1
|
||||
zpLoop: scope:[zpLoop] from main::@5
|
||||
[15] phi()
|
||||
to:zpLoop::@1
|
||||
zpLoop::@1: scope:[zpLoop] from zpLoop zpLoop::@1
|
||||
[16] (byte) zpLoop::i#2 ← phi( zpLoop/(byte) 0 zpLoop::@1/(byte) zpLoop::i#1 )
|
||||
[17] *((const byte*) BGCOL#0) ← ++ *((const byte*) BGCOL#0)
|
||||
[18] (byte) zpLoop::i#1 ← ++ (byte) zpLoop::i#2
|
||||
[19] if((byte) zpLoop::i#1!=(byte) $65) goto zpLoop::@1
|
||||
to:zpLoop::@return
|
||||
zpLoop::@return: scope:[zpLoop] from zpLoop::@1
|
||||
[20] return
|
||||
to:@return
|
||||
loop: scope:[loop] from main::@4
|
||||
[21] phi()
|
||||
to:loop::@1
|
||||
loop::@1: scope:[loop] from loop loop::@1
|
||||
[22] (byte) loop::i#2 ← phi( loop/(byte) 0 loop::@1/(byte) loop::i#1 )
|
||||
[23] *((const byte*) BGCOL#0) ← -- *((const byte*) BGCOL#0)
|
||||
[24] (byte) loop::i#1 ← ++ (byte) loop::i#2
|
||||
[25] if((byte) loop::i#1!=(byte) $65) goto loop::@1
|
||||
to:loop::@return
|
||||
loop::@return: scope:[loop] from loop::@1
|
||||
[26] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(byte*) BGCOL
|
||||
(byte*) RASTER
|
||||
(void()) loop()
|
||||
(byte) loop::i
|
||||
(byte) loop::i#1 151.5
|
||||
(byte) loop::i#2 101.0
|
||||
(void()) main()
|
||||
(byte) main::i
|
||||
(byte) main::i#1 22.0
|
||||
(byte) main::i#2 18.333333333333332
|
||||
(byte*) main::zpCode
|
||||
(byte[]) zpCodeData
|
||||
(void()) zpLoop()
|
||||
(byte) zpLoop::i
|
||||
(byte) zpLoop::i#1 151.5
|
||||
(byte) zpLoop::i#2 101.0
|
||||
|
||||
Initial phi equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
[ zpLoop::i#2 zpLoop::i#1 ]
|
||||
[ loop::i#2 loop::i#1 ]
|
||||
Complete equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
[ zpLoop::i#2 zpLoop::i#1 ]
|
||||
[ loop::i#2 loop::i#1 ]
|
||||
Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
|
||||
Allocated zp ZP_BYTE:3 [ zpLoop::i#2 zpLoop::i#1 ]
|
||||
Allocated zp ZP_BYTE:4 [ loop::i#2 loop::i#1 ]
|
||||
|
||||
INITIAL ASM
|
||||
Target platform is custom
|
||||
// File Comments
|
||||
// Example showing how to use KickAsm segments to compile meant to be transfered to zeropage before execution.
|
||||
// The linker-file defines the ZpCode segment to be on zeropage and does not include it directly in the PRG-file (by excluding it from the Program segment).
|
||||
// Instead the compiled code is added as an array of bytes in "normal" memory - and transferred to zeropage at the start of the program
|
||||
// Upstart
|
||||
.file [name="zpcode.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$0810]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef ZpCode [start=$80]
|
||||
.segment Basic
|
||||
:BasicUpstart(main)
|
||||
|
||||
|
||||
// Global Constants & labels
|
||||
.label RASTER = $d012
|
||||
.label BGCOL = $d020
|
||||
// @begin
|
||||
bbegin:
|
||||
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
b1_from_bbegin:
|
||||
jmp b1
|
||||
// @1
|
||||
b1:
|
||||
// [2] call main
|
||||
jsr main
|
||||
// [3] phi from @1 to @end [phi:@1->@end]
|
||||
bend_from_b1:
|
||||
jmp bend
|
||||
// @end
|
||||
bend:
|
||||
.segment Code
|
||||
// main
|
||||
main: {
|
||||
.label zpCode = zpLoop
|
||||
.label i = 2
|
||||
// asm { sei }
|
||||
sei
|
||||
// [5] phi from main to main::@1 [phi:main->main::@1]
|
||||
b1_from_main:
|
||||
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
|
||||
lda #0
|
||||
sta.z i
|
||||
jmp b1
|
||||
// main::@1
|
||||
b1:
|
||||
// [6] if((byte) main::i#2<(byte) $14) goto main::@2 -- vbuz1_lt_vbuc1_then_la1
|
||||
lda.z i
|
||||
cmp #$14
|
||||
bcc b2
|
||||
jmp b3
|
||||
// main::@3
|
||||
b3:
|
||||
// [7] if(*((const byte*) RASTER#0)!=(byte) $ff) goto main::@3 -- _deref_pbuc1_neq_vbuc2_then_la1
|
||||
lda #$ff
|
||||
cmp RASTER
|
||||
bne b3
|
||||
// [8] phi from main::@3 to main::@4 [phi:main::@3->main::@4]
|
||||
b4_from_b3:
|
||||
jmp b4
|
||||
// main::@4
|
||||
b4:
|
||||
// [9] call loop
|
||||
// [21] phi from main::@4 to loop [phi:main::@4->loop]
|
||||
loop_from_b4:
|
||||
jsr loop
|
||||
// [10] phi from main::@4 to main::@5 [phi:main::@4->main::@5]
|
||||
b5_from_b4:
|
||||
jmp b5
|
||||
// main::@5
|
||||
b5:
|
||||
// [11] call zpLoop
|
||||
// [15] phi from main::@5 to zpLoop [phi:main::@5->zpLoop]
|
||||
zpLoop_from_b5:
|
||||
jsr zpLoop
|
||||
jmp b6
|
||||
// main::@6
|
||||
b6:
|
||||
// [12] *((const byte*) BGCOL#0) ← (byte) 0 -- _deref_pbuc1=vbuc2
|
||||
lda #0
|
||||
sta BGCOL
|
||||
jmp b3
|
||||
// main::@2
|
||||
b2:
|
||||
// [13] *((const byte*) main::zpCode#0 + (byte) main::i#2) ← *((const byte[]) zpCodeData#0 + (byte) main::i#2) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_vbuz1
|
||||
ldy.z i
|
||||
lda zpCodeData,y
|
||||
sta zpCode,y
|
||||
// [14] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
|
||||
inc.z i
|
||||
// [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
|
||||
b1_from_b2:
|
||||
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
|
||||
jmp b1
|
||||
}
|
||||
.segment ZpCode
|
||||
// zpLoop
|
||||
zpLoop: {
|
||||
.label i = 3
|
||||
// [16] phi from zpLoop to zpLoop::@1 [phi:zpLoop->zpLoop::@1]
|
||||
b1_from_zpLoop:
|
||||
// [16] phi (byte) zpLoop::i#2 = (byte) 0 [phi:zpLoop->zpLoop::@1#0] -- vbuz1=vbuc1
|
||||
lda #0
|
||||
sta.z i
|
||||
jmp b1
|
||||
// [16] phi from zpLoop::@1 to zpLoop::@1 [phi:zpLoop::@1->zpLoop::@1]
|
||||
b1_from_b1:
|
||||
// [16] phi (byte) zpLoop::i#2 = (byte) zpLoop::i#1 [phi:zpLoop::@1->zpLoop::@1#0] -- register_copy
|
||||
jmp b1
|
||||
// zpLoop::@1
|
||||
b1:
|
||||
// [17] *((const byte*) BGCOL#0) ← ++ *((const byte*) BGCOL#0) -- _deref_pbuc1=_inc__deref_pbuc1
|
||||
inc BGCOL
|
||||
// [18] (byte) zpLoop::i#1 ← ++ (byte) zpLoop::i#2 -- vbuz1=_inc_vbuz1
|
||||
inc.z i
|
||||
// [19] if((byte) zpLoop::i#1!=(byte) $65) goto zpLoop::@1 -- vbuz1_neq_vbuc1_then_la1
|
||||
lda #$65
|
||||
cmp.z i
|
||||
bne b1_from_b1
|
||||
jmp breturn
|
||||
// zpLoop::@return
|
||||
breturn:
|
||||
// [20] return
|
||||
rts
|
||||
}
|
||||
.segment Code
|
||||
// loop
|
||||
// Code in "normal" memory
|
||||
loop: {
|
||||
.label i = 4
|
||||
// [22] phi from loop to loop::@1 [phi:loop->loop::@1]
|
||||
b1_from_loop:
|
||||
// [22] phi (byte) loop::i#2 = (byte) 0 [phi:loop->loop::@1#0] -- vbuz1=vbuc1
|
||||
lda #0
|
||||
sta.z i
|
||||
jmp b1
|
||||
// [22] phi from loop::@1 to loop::@1 [phi:loop::@1->loop::@1]
|
||||
b1_from_b1:
|
||||
// [22] phi (byte) loop::i#2 = (byte) loop::i#1 [phi:loop::@1->loop::@1#0] -- register_copy
|
||||
jmp b1
|
||||
// loop::@1
|
||||
b1:
|
||||
// [23] *((const byte*) BGCOL#0) ← -- *((const byte*) BGCOL#0) -- _deref_pbuc1=_dec__deref_pbuc1
|
||||
dec BGCOL
|
||||
// [24] (byte) loop::i#1 ← ++ (byte) loop::i#2 -- vbuz1=_inc_vbuz1
|
||||
inc.z i
|
||||
// [25] if((byte) loop::i#1!=(byte) $65) goto loop::@1 -- vbuz1_neq_vbuc1_then_la1
|
||||
lda #$65
|
||||
cmp.z i
|
||||
bne b1_from_b1
|
||||
jmp breturn
|
||||
// loop::@return
|
||||
breturn:
|
||||
// [26] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
.segment Data
|
||||
// Array containing the zeropage code to be transferred to zeropage before execution
|
||||
zpCodeData:
|
||||
.segmentout [segments="ZpCode"]
|
||||
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [7] if(*((const byte*) RASTER#0)!=(byte) $ff) goto main::@3 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Statement [12] *((const byte*) BGCOL#0) ← (byte) 0 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Statement [13] *((const byte*) main::zpCode#0 + (byte) main::i#2) ← *((const byte[]) zpCodeData#0 + (byte) main::i#2) [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
|
||||
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
|
||||
Statement [7] if(*((const byte*) RASTER#0)!=(byte) $ff) goto main::@3 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Statement [12] *((const byte*) BGCOL#0) ← (byte) 0 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Statement [13] *((const byte*) main::zpCode#0 + (byte) main::i#2) ← *((const byte[]) zpCodeData#0 + (byte) main::i#2) [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
|
||||
Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y ,
|
||||
Potential registers zp ZP_BYTE:3 [ zpLoop::i#2 zpLoop::i#1 ] : zp ZP_BYTE:3 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp ZP_BYTE:4 [ loop::i#2 loop::i#1 ] : zp ZP_BYTE:4 , reg byte a , reg byte x , reg byte y ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [loop] 252.5: zp ZP_BYTE:4 [ loop::i#2 loop::i#1 ]
|
||||
Uplift Scope [zpLoop] 252.5: zp ZP_BYTE:3 [ zpLoop::i#2 zpLoop::i#1 ]
|
||||
Uplift Scope [main] 40.33: zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [loop] best 7031 combination reg byte x [ loop::i#2 loop::i#1 ]
|
||||
Uplifting [zpLoop] best 6131 combination reg byte x [ zpLoop::i#2 zpLoop::i#1 ]
|
||||
Uplifting [main] best 6011 combination reg byte x [ main::i#2 main::i#1 ]
|
||||
Uplifting [] best 6011 combination
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Example showing how to use KickAsm segments to compile meant to be transfered to zeropage before execution.
|
||||
// The linker-file defines the ZpCode segment to be on zeropage and does not include it directly in the PRG-file (by excluding it from the Program segment).
|
||||
// Instead the compiled code is added as an array of bytes in "normal" memory - and transferred to zeropage at the start of the program
|
||||
// Upstart
|
||||
.file [name="zpcode.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$0810]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef ZpCode [start=$80]
|
||||
.segment Basic
|
||||
:BasicUpstart(main)
|
||||
|
||||
|
||||
// Global Constants & labels
|
||||
.label RASTER = $d012
|
||||
.label BGCOL = $d020
|
||||
// @begin
|
||||
bbegin:
|
||||
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
b1_from_bbegin:
|
||||
jmp b1
|
||||
// @1
|
||||
b1:
|
||||
// [2] call main
|
||||
jsr main
|
||||
// [3] phi from @1 to @end [phi:@1->@end]
|
||||
bend_from_b1:
|
||||
jmp bend
|
||||
// @end
|
||||
bend:
|
||||
.segment Code
|
||||
// main
|
||||
main: {
|
||||
.label zpCode = zpLoop
|
||||
// asm { sei }
|
||||
sei
|
||||
// [5] phi from main to main::@1 [phi:main->main::@1]
|
||||
b1_from_main:
|
||||
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
|
||||
ldx #0
|
||||
jmp b1
|
||||
// main::@1
|
||||
b1:
|
||||
// [6] if((byte) main::i#2<(byte) $14) goto main::@2 -- vbuxx_lt_vbuc1_then_la1
|
||||
cpx #$14
|
||||
bcc b2
|
||||
jmp b3
|
||||
// main::@3
|
||||
b3:
|
||||
// [7] if(*((const byte*) RASTER#0)!=(byte) $ff) goto main::@3 -- _deref_pbuc1_neq_vbuc2_then_la1
|
||||
lda #$ff
|
||||
cmp RASTER
|
||||
bne b3
|
||||
// [8] phi from main::@3 to main::@4 [phi:main::@3->main::@4]
|
||||
b4_from_b3:
|
||||
jmp b4
|
||||
// main::@4
|
||||
b4:
|
||||
// [9] call loop
|
||||
// [21] phi from main::@4 to loop [phi:main::@4->loop]
|
||||
loop_from_b4:
|
||||
jsr loop
|
||||
// [10] phi from main::@4 to main::@5 [phi:main::@4->main::@5]
|
||||
b5_from_b4:
|
||||
jmp b5
|
||||
// main::@5
|
||||
b5:
|
||||
// [11] call zpLoop
|
||||
// [15] phi from main::@5 to zpLoop [phi:main::@5->zpLoop]
|
||||
zpLoop_from_b5:
|
||||
jsr zpLoop
|
||||
jmp b6
|
||||
// main::@6
|
||||
b6:
|
||||
// [12] *((const byte*) BGCOL#0) ← (byte) 0 -- _deref_pbuc1=vbuc2
|
||||
lda #0
|
||||
sta BGCOL
|
||||
jmp b3
|
||||
// main::@2
|
||||
b2:
|
||||
// [13] *((const byte*) main::zpCode#0 + (byte) main::i#2) ← *((const byte[]) zpCodeData#0 + (byte) main::i#2) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_vbuxx
|
||||
lda zpCodeData,x
|
||||
sta zpCode,x
|
||||
// [14] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
// [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
|
||||
b1_from_b2:
|
||||
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
|
||||
jmp b1
|
||||
}
|
||||
.segment ZpCode
|
||||
// zpLoop
|
||||
zpLoop: {
|
||||
// [16] phi from zpLoop to zpLoop::@1 [phi:zpLoop->zpLoop::@1]
|
||||
b1_from_zpLoop:
|
||||
// [16] phi (byte) zpLoop::i#2 = (byte) 0 [phi:zpLoop->zpLoop::@1#0] -- vbuxx=vbuc1
|
||||
ldx #0
|
||||
jmp b1
|
||||
// [16] phi from zpLoop::@1 to zpLoop::@1 [phi:zpLoop::@1->zpLoop::@1]
|
||||
b1_from_b1:
|
||||
// [16] phi (byte) zpLoop::i#2 = (byte) zpLoop::i#1 [phi:zpLoop::@1->zpLoop::@1#0] -- register_copy
|
||||
jmp b1
|
||||
// zpLoop::@1
|
||||
b1:
|
||||
// [17] *((const byte*) BGCOL#0) ← ++ *((const byte*) BGCOL#0) -- _deref_pbuc1=_inc__deref_pbuc1
|
||||
inc BGCOL
|
||||
// [18] (byte) zpLoop::i#1 ← ++ (byte) zpLoop::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
// [19] if((byte) zpLoop::i#1!=(byte) $65) goto zpLoop::@1 -- vbuxx_neq_vbuc1_then_la1
|
||||
cpx #$65
|
||||
bne b1_from_b1
|
||||
jmp breturn
|
||||
// zpLoop::@return
|
||||
breturn:
|
||||
// [20] return
|
||||
rts
|
||||
}
|
||||
.segment Code
|
||||
// loop
|
||||
// Code in "normal" memory
|
||||
loop: {
|
||||
// [22] phi from loop to loop::@1 [phi:loop->loop::@1]
|
||||
b1_from_loop:
|
||||
// [22] phi (byte) loop::i#2 = (byte) 0 [phi:loop->loop::@1#0] -- vbuxx=vbuc1
|
||||
ldx #0
|
||||
jmp b1
|
||||
// [22] phi from loop::@1 to loop::@1 [phi:loop::@1->loop::@1]
|
||||
b1_from_b1:
|
||||
// [22] phi (byte) loop::i#2 = (byte) loop::i#1 [phi:loop::@1->loop::@1#0] -- register_copy
|
||||
jmp b1
|
||||
// loop::@1
|
||||
b1:
|
||||
// [23] *((const byte*) BGCOL#0) ← -- *((const byte*) BGCOL#0) -- _deref_pbuc1=_dec__deref_pbuc1
|
||||
dec BGCOL
|
||||
// [24] (byte) loop::i#1 ← ++ (byte) loop::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
// [25] if((byte) loop::i#1!=(byte) $65) goto loop::@1 -- vbuxx_neq_vbuc1_then_la1
|
||||
cpx #$65
|
||||
bne b1_from_b1
|
||||
jmp breturn
|
||||
// loop::@return
|
||||
breturn:
|
||||
// [26] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
.segment Data
|
||||
// Array containing the zeropage code to be transferred to zeropage before execution
|
||||
zpCodeData:
|
||||
.segmentout [segments="ZpCode"]
|
||||
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp b1
|
||||
Removing instruction jmp bend
|
||||
Removing instruction jmp b1
|
||||
Removing instruction jmp b3
|
||||
Removing instruction jmp b4
|
||||
Removing instruction jmp b5
|
||||
Removing instruction jmp b6
|
||||
Removing instruction jmp b1
|
||||
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_bbegin:
|
||||
Removing instruction b1:
|
||||
Removing instruction bend_from_b1:
|
||||
Removing instruction b4_from_b3:
|
||||
Removing instruction loop_from_b4:
|
||||
Removing instruction b5_from_b4:
|
||||
Removing instruction zpLoop_from_b5:
|
||||
Removing instruction b1_from_b1:
|
||||
Removing instruction b1_from_b1:
|
||||
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||
Removing instruction bbegin:
|
||||
Removing instruction bend:
|
||||
Removing instruction b1_from_main:
|
||||
Removing instruction b4:
|
||||
Removing instruction b5:
|
||||
Removing instruction b6:
|
||||
Removing instruction b1_from_b2:
|
||||
Removing instruction b1_from_zpLoop:
|
||||
Removing instruction breturn:
|
||||
Removing instruction b1_from_loop:
|
||||
Removing instruction breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
Removing instruction jsr main
|
||||
Succesful ASM optimization Pass5SkipBegin
|
||||
Removing instruction jmp b1
|
||||
Removing instruction jmp b1
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(byte*) BGCOL
|
||||
(const byte*) BGCOL#0 BGCOL = (byte*) 53280
|
||||
(byte*) RASTER
|
||||
(const byte*) RASTER#0 RASTER = (byte*) 53266
|
||||
(void()) loop()
|
||||
(label) loop::@1
|
||||
(label) loop::@return
|
||||
(byte) loop::i
|
||||
(byte) loop::i#1 reg byte x 151.5
|
||||
(byte) loop::i#2 reg byte x 101.0
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@3
|
||||
(label) main::@4
|
||||
(label) main::@5
|
||||
(label) main::@6
|
||||
(byte) main::i
|
||||
(byte) main::i#1 reg byte x 22.0
|
||||
(byte) main::i#2 reg byte x 18.333333333333332
|
||||
(byte*) main::zpCode
|
||||
(const byte*) main::zpCode#0 zpCode = (byte*)&(void()) zpLoop()
|
||||
(byte[]) zpCodeData
|
||||
(const byte[]) zpCodeData#0 zpCodeData = kickasm {{ .segmentout [segments="ZpCode"]
|
||||
}}
|
||||
(void()) zpLoop()
|
||||
(label) zpLoop::@1
|
||||
(label) zpLoop::@return
|
||||
(byte) zpLoop::i
|
||||
(byte) zpLoop::i#1 reg byte x 151.5
|
||||
(byte) zpLoop::i#2 reg byte x 101.0
|
||||
|
||||
reg byte x [ main::i#2 main::i#1 ]
|
||||
reg byte x [ zpLoop::i#2 zpLoop::i#1 ]
|
||||
reg byte x [ loop::i#2 loop::i#1 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 4076
|
||||
|
||||
// File Comments
|
||||
// Example showing how to use KickAsm segments to compile meant to be transfered to zeropage before execution.
|
||||
// The linker-file defines the ZpCode segment to be on zeropage and does not include it directly in the PRG-file (by excluding it from the Program segment).
|
||||
// Instead the compiled code is added as an array of bytes in "normal" memory - and transferred to zeropage at the start of the program
|
||||
// Upstart
|
||||
.file [name="zpcode.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$0810]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segmentdef ZpCode [start=$80]
|
||||
.segment Basic
|
||||
:BasicUpstart(main)
|
||||
|
||||
|
||||
// Global Constants & labels
|
||||
.label RASTER = $d012
|
||||
.label BGCOL = $d020
|
||||
// @begin
|
||||
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
// @1
|
||||
// [2] call main
|
||||
// [3] phi from @1 to @end [phi:@1->@end]
|
||||
// @end
|
||||
.segment Code
|
||||
// main
|
||||
main: {
|
||||
.label zpCode = zpLoop
|
||||
// asm
|
||||
// asm { sei }
|
||||
sei
|
||||
// [5] phi from main to main::@1 [phi:main->main::@1]
|
||||
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
|
||||
ldx #0
|
||||
// main::@1
|
||||
b1:
|
||||
// for(char i=0;i<20;i++)
|
||||
// [6] if((byte) main::i#2<(byte) $14) goto main::@2 -- vbuxx_lt_vbuc1_then_la1
|
||||
cpx #$14
|
||||
bcc b2
|
||||
// main::@3
|
||||
b3:
|
||||
// while(*RASTER!=0xff)
|
||||
// [7] if(*((const byte*) RASTER#0)!=(byte) $ff) goto main::@3 -- _deref_pbuc1_neq_vbuc2_then_la1
|
||||
lda #$ff
|
||||
cmp RASTER
|
||||
bne b3
|
||||
// [8] phi from main::@3 to main::@4 [phi:main::@3->main::@4]
|
||||
// main::@4
|
||||
// loop()
|
||||
// [9] call loop
|
||||
// [21] phi from main::@4 to loop [phi:main::@4->loop]
|
||||
jsr loop
|
||||
// [10] phi from main::@4 to main::@5 [phi:main::@4->main::@5]
|
||||
// main::@5
|
||||
// zpLoop()
|
||||
// [11] call zpLoop
|
||||
// [15] phi from main::@5 to zpLoop [phi:main::@5->zpLoop]
|
||||
jsr zpLoop
|
||||
// main::@6
|
||||
// *BGCOL = 0
|
||||
// [12] *((const byte*) BGCOL#0) ← (byte) 0 -- _deref_pbuc1=vbuc2
|
||||
lda #0
|
||||
sta BGCOL
|
||||
jmp b3
|
||||
// main::@2
|
||||
b2:
|
||||
// zpCode[i] = zpCodeData[i]
|
||||
// [13] *((const byte*) main::zpCode#0 + (byte) main::i#2) ← *((const byte[]) zpCodeData#0 + (byte) main::i#2) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_vbuxx
|
||||
lda zpCodeData,x
|
||||
sta zpCode,x
|
||||
// for(char i=0;i<20;i++)
|
||||
// [14] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
// [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
|
||||
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
|
||||
jmp b1
|
||||
}
|
||||
.segment ZpCode
|
||||
// zpLoop
|
||||
zpLoop: {
|
||||
// [16] phi from zpLoop to zpLoop::@1 [phi:zpLoop->zpLoop::@1]
|
||||
// [16] phi (byte) zpLoop::i#2 = (byte) 0 [phi:zpLoop->zpLoop::@1#0] -- vbuxx=vbuc1
|
||||
ldx #0
|
||||
// [16] phi from zpLoop::@1 to zpLoop::@1 [phi:zpLoop::@1->zpLoop::@1]
|
||||
// [16] phi (byte) zpLoop::i#2 = (byte) zpLoop::i#1 [phi:zpLoop::@1->zpLoop::@1#0] -- register_copy
|
||||
// zpLoop::@1
|
||||
b1:
|
||||
// (*BGCOL)++;
|
||||
// [17] *((const byte*) BGCOL#0) ← ++ *((const byte*) BGCOL#0) -- _deref_pbuc1=_inc__deref_pbuc1
|
||||
inc BGCOL
|
||||
// for(char i:0..100)
|
||||
// [18] (byte) zpLoop::i#1 ← ++ (byte) zpLoop::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
// [19] if((byte) zpLoop::i#1!=(byte) $65) goto zpLoop::@1 -- vbuxx_neq_vbuc1_then_la1
|
||||
cpx #$65
|
||||
bne b1
|
||||
// zpLoop::@return
|
||||
// }
|
||||
// [20] return
|
||||
rts
|
||||
}
|
||||
.segment Code
|
||||
// loop
|
||||
// Code in "normal" memory
|
||||
loop: {
|
||||
// [22] phi from loop to loop::@1 [phi:loop->loop::@1]
|
||||
// [22] phi (byte) loop::i#2 = (byte) 0 [phi:loop->loop::@1#0] -- vbuxx=vbuc1
|
||||
ldx #0
|
||||
// [22] phi from loop::@1 to loop::@1 [phi:loop::@1->loop::@1]
|
||||
// [22] phi (byte) loop::i#2 = (byte) loop::i#1 [phi:loop::@1->loop::@1#0] -- register_copy
|
||||
// loop::@1
|
||||
b1:
|
||||
// (*BGCOL)--;
|
||||
// [23] *((const byte*) BGCOL#0) ← -- *((const byte*) BGCOL#0) -- _deref_pbuc1=_dec__deref_pbuc1
|
||||
dec BGCOL
|
||||
// for(char i:0..100)
|
||||
// [24] (byte) loop::i#1 ← ++ (byte) loop::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
// [25] if((byte) loop::i#1!=(byte) $65) goto loop::@1 -- vbuxx_neq_vbuc1_then_la1
|
||||
cpx #$65
|
||||
bne b1
|
||||
// loop::@return
|
||||
// }
|
||||
// [26] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
.segment Data
|
||||
// Array containing the zeropage code to be transferred to zeropage before execution
|
||||
zpCodeData:
|
||||
.segmentout [segments="ZpCode"]
|
||||
|
||||
|
38
src/test/ref/examples/zpcode/zpcode.sym
Normal file
38
src/test/ref/examples/zpcode/zpcode.sym
Normal file
@ -0,0 +1,38 @@
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(byte*) BGCOL
|
||||
(const byte*) BGCOL#0 BGCOL = (byte*) 53280
|
||||
(byte*) RASTER
|
||||
(const byte*) RASTER#0 RASTER = (byte*) 53266
|
||||
(void()) loop()
|
||||
(label) loop::@1
|
||||
(label) loop::@return
|
||||
(byte) loop::i
|
||||
(byte) loop::i#1 reg byte x 151.5
|
||||
(byte) loop::i#2 reg byte x 101.0
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@3
|
||||
(label) main::@4
|
||||
(label) main::@5
|
||||
(label) main::@6
|
||||
(byte) main::i
|
||||
(byte) main::i#1 reg byte x 22.0
|
||||
(byte) main::i#2 reg byte x 18.333333333333332
|
||||
(byte*) main::zpCode
|
||||
(const byte*) main::zpCode#0 zpCode = (byte*)&(void()) zpLoop()
|
||||
(byte[]) zpCodeData
|
||||
(const byte[]) zpCodeData#0 zpCodeData = kickasm {{ .segmentout [segments="ZpCode"]
|
||||
}}
|
||||
(void()) zpLoop()
|
||||
(label) zpLoop::@1
|
||||
(label) zpLoop::@return
|
||||
(byte) zpLoop::i
|
||||
(byte) zpLoop::i#1 reg byte x 151.5
|
||||
(byte) zpLoop::i#2 reg byte x 101.0
|
||||
|
||||
reg byte x [ main::i#2 main::i#1 ]
|
||||
reg byte x [ zpLoop::i#2 zpLoop::i#1 ]
|
||||
reg byte x [ loop::i#2 loop::i#1 ]
|
Loading…
Reference in New Issue
Block a user