1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-11-23 23:32:55 +00:00

Improved target platform handling.

This commit is contained in:
Jesper Gravgaard 2019-08-09 16:11:28 +02:00
parent 8f0b9c886f
commit 313d45fd03
15 changed files with 908 additions and 18 deletions

View File

@ -137,6 +137,9 @@ public class Compiler {
}
public Program compile(String fileName) {
if(fileName.endsWith(".kc")) {
fileName = fileName.substring(0, fileName.length()-3);
}
program.setFileName(fileName);
program.setStatementSequence(new StatementSequence());
try {

View File

@ -11,7 +11,9 @@ public enum TargetPlatform {
/** 6502 assembler (with no upstart code.)*/
ASM6502("asm6502"),
/** 6502 assembler (with no upstart code.)*/
ASM6502_SEGMENTS("asm6502_segments");
ASM6502_SEGMENTS("asm6502_segments"),
/** Custom target platform specified in a separate linker file passed using -T option or using #pragma link() */
CUSTOM("custom");
/** The default target platform. */
public static final TargetPlatform DEFAULT = C64BASIC;

View File

@ -14,6 +14,7 @@ import dk.camelot64.kickc.model.types.*;
import dk.camelot64.kickc.model.values.*;
import dk.camelot64.kickc.passes.calcs.PassNCalcVariableReferenceInfos;
import java.io.File;
import java.util.*;
/**
@ -77,23 +78,15 @@ public class Pass4CodeGeneration {
asm.startChunk(currentScope, null, "File Comments");
generateComments(asm, program.getFileComments());
Number programPc;
if(program.getProgramPc() != null) {
programPc = program.getProgramPc();
} else {
if(TargetPlatform.C64BASIC.equals(program.getTargetPlatform())) {
programPc = 0x080d;
} else {
programPc = 0x2000;
}
}
String outputPrgPath = new File(program.getFileName()).getName()+".prg";
asm.startChunk(currentScope, null, "Upstart");
Number programPc = program.getProgramPc();
if(TargetPlatform.C64BASIC_SEGMENTS.equals(program.getTargetPlatform())) {
useSegments = true;
currentCodeSegmentName = "Code";
currentDataSegmentName = "Data";
asm.addLine(new AsmFile(program.getFileName() + ".prg").param("type", "\"prg\"").param("segments", "\"Program\""));
if(programPc==null) programPc = 0x080d;
asm.addLine(new AsmFile(outputPrgPath).param("type", "\"prg\"").param("segments", "\"Program\""));
asm.addLine(new AsmSegmentDef("Program").param("segments", "\"Basic,Code,Data\""));
asm.addLine(new AsmSegmentDef("Basic").param("start", "$0801"));
asm.addLine(new AsmSegmentDef("Code").param("start", AsmFormat.getAsmNumber(programPc)));
@ -101,22 +94,29 @@ public class Pass4CodeGeneration {
asm.addLine(new AsmSegment("Basic"));
asm.addLine(new AsmBasicUpstart("bbegin"));
setCurrentSegment(currentCodeSegmentName, asm);
} else if(TargetPlatform.C64BASIC.equals(program.getTargetPlatform())) {
useSegments = false;
if(programPc==null) programPc = 0x080d;
asm.addLine(new AsmSetPc("Basic", AsmFormat.getAsmNumber(0x0801)));
asm.addLine(new AsmBasicUpstart("bbegin"));
asm.addLine(new AsmSetPc("Program", AsmFormat.getAsmNumber(programPc)));
} else if(TargetPlatform.ASM6502_SEGMENTS.equals(program.getTargetPlatform())) {
useSegments = true;
currentCodeSegmentName = "Code";
currentDataSegmentName = "Data";
asm.addLine(new AsmFile(program.getFileName() + ".prg").param("type", "\"prg\"").param("segments", "\"Program\""));
if(programPc==null) programPc = 0x2000;
asm.addLine(new AsmFile(outputPrgPath).param("type", "\"prg\"").param("segments", "\"Program\""));
asm.addLine(new AsmSegmentDef("Program").param("segments", "\"Code,Data\""));
asm.addLine(new AsmSegmentDef("Code").param("start", AsmFormat.getAsmNumber(programPc)));
asm.addLine(new AsmSegmentDef("Data").param("startAfter", "\"Code\""));
setCurrentSegment(currentCodeSegmentName, asm);
} else if(TargetPlatform.ASM6502.equals(program.getTargetPlatform())) {
useSegments = false;
if(programPc==null) programPc = 0x2000;
asm.addLine(new AsmSetPc("Program", AsmFormat.getAsmNumber(programPc)));
} else if(TargetPlatform.C64BASIC.equals(program.getTargetPlatform())) {
useSegments = false;
asm.addLine(new AsmSetPc("Basic", AsmFormat.getAsmNumber(0x0801)));
asm.addLine(new AsmBasicUpstart("bbegin"));
} else if(TargetPlatform.CUSTOM.equals(program.getTargetPlatform())) {
useSegments = true;
if(programPc==null) programPc = 0x2000;
asm.addLine(new AsmSetPc("Program", AsmFormat.getAsmNumber(programPc)));
}

View File

@ -106,6 +106,16 @@ public class TestPrograms {
compileAndCompare("platform-asm6502");
}
@Test
public void testPlatformC64BasicSegments() throws IOException, URISyntaxException {
compileAndCompare("platform-c64basic_segments");
}
@Test
public void testPlatformAsm6502Segments() throws IOException, URISyntaxException {
compileAndCompare("platform-asm6502_segments");
}
@Test
public void testEuclid2() throws IOException, URISyntaxException {
compileAndCompare("euclid-3");

View File

@ -0,0 +1,10 @@
// Tests the target platform ASM6502_SEGMENTS
#pragma target(asm6502_segments)
unsigned char[10] TABLE;
void main() {
for(char i=0;i<10;i++)
TABLE[i] = i;
}

View File

@ -0,0 +1,10 @@
// Tests the target platform C64BASIC_SEGMENTS
#pragma target(c64basic_segments)
unsigned char[10] TABLE;
void main() {
for(char i=0;i<10;i++)
TABLE[i] = i;
}

View File

@ -0,0 +1,18 @@
// Tests the target platform ASM6502_SEGMENTS
.file [ name="platform-asm6502_segments.prg",type="prg",segments="Program" ]
.segmentdef Program [ segments="Code,Data" ]
.segmentdef Code [ start=$2000 ]
.segmentdef Data [ startAfter="Code" ]
.segment Code
main: {
ldx #0
b2:
txa
sta TABLE,x
inx
cpx #$a
bcc b2
rts
}
.segment Data
TABLE: .fill $a, 0

View File

@ -0,0 +1,23 @@
@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::@2
main::@2: scope:[main] from main main::@1
[5] (byte) main::i#4 ← phi( main::@1/(byte) main::i#1 main/(byte) 0 )
[6] *((const byte[$a]) TABLE#0 + (byte) main::i#4) ← (byte) main::i#4
[7] (byte) main::i#1 ← ++ (byte) main::i#4
to:main::@1
main::@1: scope:[main] from main::@2
[8] if((byte) main::i#1<(byte) $a) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[9] return
to:@return

View File

@ -0,0 +1,365 @@
Culled Empty Block (label) main::@4
Culled Empty Block (label) main::@3
Culled Empty Block (label) main::@5
Culled Empty Block (label) main::@6
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte[$a]) TABLE#0 ← { fill( $a, 0) }
to:@1
main: scope:[main] from @1
(byte) main::i#0 ← (number) 0
to:main::@1
main::@1: scope:[main] from main main::@2
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 )
(bool~) main::$0 ← (byte) main::i#2 < (number) $a
if((bool~) main::$0) goto main::@2
to:main::@return
main::@2: scope:[main] from main::@1
(byte) main::i#3 ← phi( main::@1/(byte) main::i#2 )
*((byte[$a]) TABLE#0 + (byte) main::i#3) ← (byte) main::i#3
(byte) main::i#1 ← ++ (byte) main::i#3
to:main::@1
main::@return: scope:[main] from main::@1
return
to:@return
@1: scope:[] from @begin
call main
to:@2
@2: scope:[] from @1
to:@end
@end: scope:[] from @2
SYMBOL TABLE SSA
(label) @1
(label) @2
(label) @begin
(label) @end
(byte[$a]) TABLE
(byte[$a]) TABLE#0
(void()) main()
(bool~) main::$0
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
(byte) main::i#3
Adding number conversion cast (unumber) 0 in (byte) main::i#0 ← (number) 0
Adding number conversion cast (unumber) $a in (bool~) main::$0 ← (byte) main::i#2 < (number) $a
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (byte) main::i#0 ← (unumber)(number) 0
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast 0
Simplifying constant integer cast $a
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) $a
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias (byte) main::i#2 = (byte) main::i#3
Successful SSA optimization Pass2AliasElimination
Simple Condition (bool~) main::$0 [4] if((byte) main::i#2<(byte) $a) goto main::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant right-side identified [0] (byte[$a]) TABLE#0 ← { fill( $a, 0) }
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte[$a]) TABLE#0 = { fill( $a, 0) }
Constant (const byte) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Successful SSA optimization Pass2LoopHeadConstantIdentification
Alias (byte) main::i#1 = (byte) main::i#2
Successful SSA optimization Pass2AliasElimination
Identical Phi Values (byte) main::i#5 (const byte) main::i#0
Successful SSA optimization Pass2IdenticalPhiElimination
if() condition always true - replacing block destination [9] if((const byte) main::i#0<(byte) $a) goto main::@2
Successful SSA optimization Pass2ConstantIfs
Inlining constant with var siblings (const byte) main::i#0
Constant inlined main::i#0 = (byte) 0
Successful SSA optimization Pass2ConstantInlining
Added new block during phi lifting main::@7(between main::@1 and main::@2)
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
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 main::@1_1
CALL GRAPH
Calls in [] to main:2
Created 1 initial phi equivalence classes
Coalesced [12] main::i#6 ← main::i#1
Coalesced down to 1 phi equivalence classes
Culled Empty Block (label) @2
Culled Empty Block (label) main::@1_1
Culled Empty Block (label) main::@7
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
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::@2
main::@2: scope:[main] from main main::@1
[5] (byte) main::i#4 ← phi( main::@1/(byte) main::i#1 main/(byte) 0 )
[6] *((const byte[$a]) TABLE#0 + (byte) main::i#4) ← (byte) main::i#4
[7] (byte) main::i#1 ← ++ (byte) main::i#4
to:main::@1
main::@1: scope:[main] from main::@2
[8] if((byte) main::i#1<(byte) $a) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[9] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte[$a]) TABLE
(void()) main()
(byte) main::i
(byte) main::i#1 16.5
(byte) main::i#4 22.0
Initial phi equivalence classes
[ main::i#4 main::i#1 ]
Complete equivalence classes
[ main::i#4 main::i#1 ]
Allocated zp ZP_BYTE:2 [ main::i#4 main::i#1 ]
INITIAL ASM
Target platform is asm6502_segments
// File Comments
// Tests the target platform ASM6502_SEGMENTS
// Upstart
.file [ name="platform-asm6502_segments.prg",type="prg",segments="Program" ]
.segmentdef Program [ segments="Code,Data" ]
.segmentdef Code [ start=$2000 ]
.segmentdef Data [ startAfter="Code" ]
.segment Code
// Global Constants & labels
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
.label i = 2
// [5] phi from main to main::@2 [phi:main->main::@2]
b2_from_main:
// [5] phi (byte) main::i#4 = (byte) 0 [phi:main->main::@2#0] -- vbuz1=vbuc1
lda #0
sta.z i
jmp b2
// [5] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
b2_from_b1:
// [5] phi (byte) main::i#4 = (byte) main::i#1 [phi:main::@1->main::@2#0] -- register_copy
jmp b2
// main::@2
b2:
// [6] *((const byte[$a]) TABLE#0 + (byte) main::i#4) ← (byte) main::i#4 -- pbuc1_derefidx_vbuz1=vbuz1
ldy.z i
tya
sta TABLE,y
// [7] (byte) main::i#1 ← ++ (byte) main::i#4 -- vbuz1=_inc_vbuz1
inc.z i
jmp b1
// main::@1
b1:
// [8] if((byte) main::i#1<(byte) $a) goto main::@2 -- vbuz1_lt_vbuc1_then_la1
lda.z i
cmp #$a
bcc b2_from_b1
jmp breturn
// main::@return
breturn:
// [9] return
rts
}
// File Data
.segment Data
TABLE: .fill $a, 0
REGISTER UPLIFT POTENTIAL REGISTERS
Potential registers zp ZP_BYTE:2 [ main::i#4 main::i#1 ] : zp ZP_BYTE:2 , reg byte a , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 38.5: zp ZP_BYTE:2 [ main::i#4 main::i#1 ]
Uplift Scope []
Uplifting [main] best 293 combination reg byte x [ main::i#4 main::i#1 ]
Uplifting [] best 293 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Tests the target platform ASM6502_SEGMENTS
// Upstart
.file [ name="platform-asm6502_segments.prg",type="prg",segments="Program" ]
.segmentdef Program [ segments="Code,Data" ]
.segmentdef Code [ start=$2000 ]
.segmentdef Data [ startAfter="Code" ]
.segment Code
// Global Constants & labels
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
// [5] phi from main to main::@2 [phi:main->main::@2]
b2_from_main:
// [5] phi (byte) main::i#4 = (byte) 0 [phi:main->main::@2#0] -- vbuxx=vbuc1
ldx #0
jmp b2
// [5] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
b2_from_b1:
// [5] phi (byte) main::i#4 = (byte) main::i#1 [phi:main::@1->main::@2#0] -- register_copy
jmp b2
// main::@2
b2:
// [6] *((const byte[$a]) TABLE#0 + (byte) main::i#4) ← (byte) main::i#4 -- pbuc1_derefidx_vbuxx=vbuxx
txa
sta TABLE,x
// [7] (byte) main::i#1 ← ++ (byte) main::i#4 -- vbuxx=_inc_vbuxx
inx
jmp b1
// main::@1
b1:
// [8] if((byte) main::i#1<(byte) $a) goto main::@2 -- vbuxx_lt_vbuc1_then_la1
cpx #$a
bcc b2_from_b1
jmp breturn
// main::@return
breturn:
// [9] return
rts
}
// File Data
.segment Data
TABLE: .fill $a, 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp b2
Removing instruction jmp b1
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing label b2_from_b1 with b2
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction main_from_b1:
Removing instruction bend_from_b1:
Removing instruction b2_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bbegin:
Removing instruction bend:
Removing instruction b2_from_main:
Removing instruction b1:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction jmp b2
Succesful ASM optimization Pass5NextJumpElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(byte[$a]) TABLE
(const byte[$a]) TABLE#0 TABLE = { fill( $a, 0) }
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte x 16.5
(byte) main::i#4 reg byte x 22.0
reg byte x [ main::i#4 main::i#1 ]
FINAL ASSEMBLER
Score: 161
// File Comments
// Tests the target platform ASM6502_SEGMENTS
// Upstart
.file [ name="platform-asm6502_segments.prg",type="prg",segments="Program" ]
.segmentdef Program [ segments="Code,Data" ]
.segmentdef Code [ start=$2000 ]
.segmentdef Data [ startAfter="Code" ]
.segment Code
// Global Constants & labels
// @begin
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
// [5] phi from main to main::@2 [phi:main->main::@2]
// [5] phi (byte) main::i#4 = (byte) 0 [phi:main->main::@2#0] -- vbuxx=vbuc1
ldx #0
// [5] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
// [5] phi (byte) main::i#4 = (byte) main::i#1 [phi:main::@1->main::@2#0] -- register_copy
// main::@2
b2:
// TABLE[i] = i
// [6] *((const byte[$a]) TABLE#0 + (byte) main::i#4) ← (byte) main::i#4 -- pbuc1_derefidx_vbuxx=vbuxx
txa
sta TABLE,x
// for(char i=0;i<10;i++)
// [7] (byte) main::i#1 ← ++ (byte) main::i#4 -- vbuxx=_inc_vbuxx
inx
// main::@1
// [8] if((byte) main::i#1<(byte) $a) goto main::@2 -- vbuxx_lt_vbuc1_then_la1
cpx #$a
bcc b2
// main::@return
// }
// [9] return
rts
}
// File Data
.segment Data
TABLE: .fill $a, 0

View File

@ -0,0 +1,14 @@
(label) @1
(label) @begin
(label) @end
(byte[$a]) TABLE
(const byte[$a]) TABLE#0 TABLE = { fill( $a, 0) }
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte x 16.5
(byte) main::i#4 reg byte x 22.0
reg byte x [ main::i#4 main::i#1 ]

View File

@ -0,0 +1,21 @@
// Tests the target platform C64BASIC_SEGMENTS
.file [ name="platform-c64basic_segments.prg",type="prg",segments="Program" ]
.segmentdef Program [ segments="Basic,Code,Data" ]
.segmentdef Basic [ start=$0801 ]
.segmentdef Code [ start=$80d ]
.segmentdef Data [ startAfter="Code" ]
.segment Basic
:BasicUpstart(main)
.segment Code
main: {
ldx #0
b2:
txa
sta TABLE,x
inx
cpx #$a
bcc b2
rts
}
.segment Data
TABLE: .fill $a, 0

View File

@ -0,0 +1,23 @@
@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::@2
main::@2: scope:[main] from main main::@1
[5] (byte) main::i#4 ← phi( main::@1/(byte) main::i#1 main/(byte) 0 )
[6] *((const byte[$a]) TABLE#0 + (byte) main::i#4) ← (byte) main::i#4
[7] (byte) main::i#1 ← ++ (byte) main::i#4
to:main::@1
main::@1: scope:[main] from main::@2
[8] if((byte) main::i#1<(byte) $a) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[9] return
to:@return

View File

@ -0,0 +1,376 @@
Culled Empty Block (label) main::@4
Culled Empty Block (label) main::@3
Culled Empty Block (label) main::@5
Culled Empty Block (label) main::@6
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte[$a]) TABLE#0 ← { fill( $a, 0) }
to:@1
main: scope:[main] from @1
(byte) main::i#0 ← (number) 0
to:main::@1
main::@1: scope:[main] from main main::@2
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 )
(bool~) main::$0 ← (byte) main::i#2 < (number) $a
if((bool~) main::$0) goto main::@2
to:main::@return
main::@2: scope:[main] from main::@1
(byte) main::i#3 ← phi( main::@1/(byte) main::i#2 )
*((byte[$a]) TABLE#0 + (byte) main::i#3) ← (byte) main::i#3
(byte) main::i#1 ← ++ (byte) main::i#3
to:main::@1
main::@return: scope:[main] from main::@1
return
to:@return
@1: scope:[] from @begin
call main
to:@2
@2: scope:[] from @1
to:@end
@end: scope:[] from @2
SYMBOL TABLE SSA
(label) @1
(label) @2
(label) @begin
(label) @end
(byte[$a]) TABLE
(byte[$a]) TABLE#0
(void()) main()
(bool~) main::$0
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
(byte) main::i#3
Adding number conversion cast (unumber) 0 in (byte) main::i#0 ← (number) 0
Adding number conversion cast (unumber) $a in (bool~) main::$0 ← (byte) main::i#2 < (number) $a
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (byte) main::i#0 ← (unumber)(number) 0
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast 0
Simplifying constant integer cast $a
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) $a
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias (byte) main::i#2 = (byte) main::i#3
Successful SSA optimization Pass2AliasElimination
Simple Condition (bool~) main::$0 [4] if((byte) main::i#2<(byte) $a) goto main::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant right-side identified [0] (byte[$a]) TABLE#0 ← { fill( $a, 0) }
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte[$a]) TABLE#0 = { fill( $a, 0) }
Constant (const byte) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Successful SSA optimization Pass2LoopHeadConstantIdentification
Alias (byte) main::i#1 = (byte) main::i#2
Successful SSA optimization Pass2AliasElimination
Identical Phi Values (byte) main::i#5 (const byte) main::i#0
Successful SSA optimization Pass2IdenticalPhiElimination
if() condition always true - replacing block destination [9] if((const byte) main::i#0<(byte) $a) goto main::@2
Successful SSA optimization Pass2ConstantIfs
Inlining constant with var siblings (const byte) main::i#0
Constant inlined main::i#0 = (byte) 0
Successful SSA optimization Pass2ConstantInlining
Added new block during phi lifting main::@7(between main::@1 and main::@2)
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
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 main::@1_1
CALL GRAPH
Calls in [] to main:2
Created 1 initial phi equivalence classes
Coalesced [12] main::i#6 ← main::i#1
Coalesced down to 1 phi equivalence classes
Culled Empty Block (label) @2
Culled Empty Block (label) main::@1_1
Culled Empty Block (label) main::@7
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
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::@2
main::@2: scope:[main] from main main::@1
[5] (byte) main::i#4 ← phi( main::@1/(byte) main::i#1 main/(byte) 0 )
[6] *((const byte[$a]) TABLE#0 + (byte) main::i#4) ← (byte) main::i#4
[7] (byte) main::i#1 ← ++ (byte) main::i#4
to:main::@1
main::@1: scope:[main] from main::@2
[8] if((byte) main::i#1<(byte) $a) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[9] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte[$a]) TABLE
(void()) main()
(byte) main::i
(byte) main::i#1 16.5
(byte) main::i#4 22.0
Initial phi equivalence classes
[ main::i#4 main::i#1 ]
Complete equivalence classes
[ main::i#4 main::i#1 ]
Allocated zp ZP_BYTE:2 [ main::i#4 main::i#1 ]
INITIAL ASM
Target platform is c64basic_segments
// File Comments
// Tests the target platform C64BASIC_SEGMENTS
// Upstart
.file [ name="platform-c64basic_segments.prg",type="prg",segments="Program" ]
.segmentdef Program [ segments="Basic,Code,Data" ]
.segmentdef Basic [ start=$0801 ]
.segmentdef Code [ start=$80d ]
.segmentdef Data [ startAfter="Code" ]
.segment Basic
:BasicUpstart(bbegin)
.segment Code
// Global Constants & labels
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
.label i = 2
// [5] phi from main to main::@2 [phi:main->main::@2]
b2_from_main:
// [5] phi (byte) main::i#4 = (byte) 0 [phi:main->main::@2#0] -- vbuz1=vbuc1
lda #0
sta.z i
jmp b2
// [5] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
b2_from_b1:
// [5] phi (byte) main::i#4 = (byte) main::i#1 [phi:main::@1->main::@2#0] -- register_copy
jmp b2
// main::@2
b2:
// [6] *((const byte[$a]) TABLE#0 + (byte) main::i#4) ← (byte) main::i#4 -- pbuc1_derefidx_vbuz1=vbuz1
ldy.z i
tya
sta TABLE,y
// [7] (byte) main::i#1 ← ++ (byte) main::i#4 -- vbuz1=_inc_vbuz1
inc.z i
jmp b1
// main::@1
b1:
// [8] if((byte) main::i#1<(byte) $a) goto main::@2 -- vbuz1_lt_vbuc1_then_la1
lda.z i
cmp #$a
bcc b2_from_b1
jmp breturn
// main::@return
breturn:
// [9] return
rts
}
// File Data
.segment Data
TABLE: .fill $a, 0
REGISTER UPLIFT POTENTIAL REGISTERS
Potential registers zp ZP_BYTE:2 [ main::i#4 main::i#1 ] : zp ZP_BYTE:2 , reg byte a , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 38.5: zp ZP_BYTE:2 [ main::i#4 main::i#1 ]
Uplift Scope []
Uplifting [main] best 293 combination reg byte x [ main::i#4 main::i#1 ]
Uplifting [] best 293 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Tests the target platform C64BASIC_SEGMENTS
// Upstart
.file [ name="platform-c64basic_segments.prg",type="prg",segments="Program" ]
.segmentdef Program [ segments="Basic,Code,Data" ]
.segmentdef Basic [ start=$0801 ]
.segmentdef Code [ start=$80d ]
.segmentdef Data [ startAfter="Code" ]
.segment Basic
:BasicUpstart(bbegin)
.segment Code
// Global Constants & labels
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
// [5] phi from main to main::@2 [phi:main->main::@2]
b2_from_main:
// [5] phi (byte) main::i#4 = (byte) 0 [phi:main->main::@2#0] -- vbuxx=vbuc1
ldx #0
jmp b2
// [5] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
b2_from_b1:
// [5] phi (byte) main::i#4 = (byte) main::i#1 [phi:main::@1->main::@2#0] -- register_copy
jmp b2
// main::@2
b2:
// [6] *((const byte[$a]) TABLE#0 + (byte) main::i#4) ← (byte) main::i#4 -- pbuc1_derefidx_vbuxx=vbuxx
txa
sta TABLE,x
// [7] (byte) main::i#1 ← ++ (byte) main::i#4 -- vbuxx=_inc_vbuxx
inx
jmp b1
// main::@1
b1:
// [8] if((byte) main::i#1<(byte) $a) goto main::@2 -- vbuxx_lt_vbuc1_then_la1
cpx #$a
bcc b2_from_b1
jmp breturn
// main::@return
breturn:
// [9] return
rts
}
// File Data
.segment Data
TABLE: .fill $a, 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp b2
Removing instruction jmp b1
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing label b2_from_b1 with b2
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction main_from_b1:
Removing instruction bend_from_b1:
Removing instruction b2_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction b2_from_main:
Removing instruction b1:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction jmp b2
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(byte[$a]) TABLE
(const byte[$a]) TABLE#0 TABLE = { fill( $a, 0) }
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte x 16.5
(byte) main::i#4 reg byte x 22.0
reg byte x [ main::i#4 main::i#1 ]
FINAL ASSEMBLER
Score: 161
// File Comments
// Tests the target platform C64BASIC_SEGMENTS
// Upstart
.file [ name="platform-c64basic_segments.prg",type="prg",segments="Program" ]
.segmentdef Program [ segments="Basic,Code,Data" ]
.segmentdef Basic [ start=$0801 ]
.segmentdef Code [ start=$80d ]
.segmentdef Data [ startAfter="Code" ]
.segment Basic
:BasicUpstart(main)
.segment Code
// Global Constants & labels
// @begin
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
// [5] phi from main to main::@2 [phi:main->main::@2]
// [5] phi (byte) main::i#4 = (byte) 0 [phi:main->main::@2#0] -- vbuxx=vbuc1
ldx #0
// [5] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
// [5] phi (byte) main::i#4 = (byte) main::i#1 [phi:main::@1->main::@2#0] -- register_copy
// main::@2
b2:
// TABLE[i] = i
// [6] *((const byte[$a]) TABLE#0 + (byte) main::i#4) ← (byte) main::i#4 -- pbuc1_derefidx_vbuxx=vbuxx
txa
sta TABLE,x
// for(char i=0;i<10;i++)
// [7] (byte) main::i#1 ← ++ (byte) main::i#4 -- vbuxx=_inc_vbuxx
inx
// main::@1
// [8] if((byte) main::i#1<(byte) $a) goto main::@2 -- vbuxx_lt_vbuc1_then_la1
cpx #$a
bcc b2
// main::@return
// }
// [9] return
rts
}
// File Data
.segment Data
TABLE: .fill $a, 0

View File

@ -0,0 +1,14 @@
(label) @1
(label) @begin
(label) @end
(byte[$a]) TABLE
(const byte[$a]) TABLE#0 TABLE = { fill( $a, 0) }
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte x 16.5
(byte) main::i#4 reg byte x 22.0
reg byte x [ main::i#4 main::i#1 ]

View File

@ -7,3 +7,4 @@ popd
rm -r ${C64_HOME}/kickc_local/*
unzip -d ${C64_HOME}/kickc_local ${C64_HOME}/kickc/target/kickc-release.zip
mv ${C64_HOME}/kickc_local/kickc/* ${C64_HOME}/kickc_local/
rmdir ${C64_HOME}/kickc_local/kickc