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

Added missing fragment. Fixed exception when casting literal string. Closes #309

This commit is contained in:
jespergravgaard 2019-09-09 15:51:39 +02:00
parent a1f4656f79
commit d6ad2c3b9b
9 changed files with 452 additions and 4 deletions

View File

@ -0,0 +1,8 @@
lda #0
sta {z1}+2
sta {z1}+3
lda {z2}+3
sta {z1}+1
lda {z2}+2
sta {z1}

View File

@ -1,11 +1,13 @@
package dk.camelot64.kickc.model.operators; package dk.camelot64.kickc.model.operators;
import dk.camelot64.kickc.model.CompileError; import dk.camelot64.kickc.model.CompileError;
import dk.camelot64.kickc.model.ConstantNotLiteral;
import dk.camelot64.kickc.model.symbols.ProgramScope; import dk.camelot64.kickc.model.symbols.ProgramScope;
import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.values.ConstantInteger; import dk.camelot64.kickc.model.values.ConstantInteger;
import dk.camelot64.kickc.model.values.ConstantLiteral; import dk.camelot64.kickc.model.values.ConstantLiteral;
import dk.camelot64.kickc.model.values.ConstantPointer; import dk.camelot64.kickc.model.values.ConstantPointer;
import dk.camelot64.kickc.model.values.ConstantString;
/** Unary Cast to double word operator ( (dword) x ) */ /** Unary Cast to double word operator ( (dword) x ) */
public class OperatorCastDWord extends OperatorCast { public class OperatorCastDWord extends OperatorCast {
@ -18,9 +20,10 @@ public class OperatorCastDWord extends OperatorCast {
public ConstantLiteral calculateLiteral(ConstantLiteral value, ProgramScope scope) { public ConstantLiteral calculateLiteral(ConstantLiteral value, ProgramScope scope) {
if(value instanceof ConstantInteger) { if(value instanceof ConstantInteger) {
return new ConstantInteger(0xffffffffL & ((ConstantInteger) value).getValue(), SymbolType.DWORD); return new ConstantInteger(0xffffffffL & ((ConstantInteger) value).getValue(), SymbolType.DWORD);
} } else if(value instanceof ConstantPointer) {
if(value instanceof ConstantPointer) {
return new ConstantInteger(0xffff & ((ConstantPointer) value).getLocation(), SymbolType.DWORD); return new ConstantInteger(0xffff & ((ConstantPointer) value).getLocation(), SymbolType.DWORD);
} else if(value instanceof ConstantString) {
throw new ConstantNotLiteral("String cannot be cast to dword");
} }
throw new CompileError("Calculation not implemented " + getOperator() + " " + value ); throw new CompileError("Calculation not implemented " + getOperator() + " " + value );
} }

View File

@ -1,11 +1,13 @@
package dk.camelot64.kickc.model.operators; package dk.camelot64.kickc.model.operators;
import dk.camelot64.kickc.model.CompileError; import dk.camelot64.kickc.model.CompileError;
import dk.camelot64.kickc.model.ConstantNotLiteral;
import dk.camelot64.kickc.model.symbols.ProgramScope; import dk.camelot64.kickc.model.symbols.ProgramScope;
import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.values.ConstantInteger; import dk.camelot64.kickc.model.values.ConstantInteger;
import dk.camelot64.kickc.model.values.ConstantLiteral; import dk.camelot64.kickc.model.values.ConstantLiteral;
import dk.camelot64.kickc.model.values.ConstantPointer; import dk.camelot64.kickc.model.values.ConstantPointer;
import dk.camelot64.kickc.model.values.ConstantString;
/** Unary Cast to word operator ( (word) x ) */ /** Unary Cast to word operator ( (word) x ) */
public class OperatorCastWord extends OperatorCast { public class OperatorCastWord extends OperatorCast {
@ -18,9 +20,10 @@ public class OperatorCastWord extends OperatorCast {
public ConstantLiteral calculateLiteral(ConstantLiteral value, ProgramScope scope) { public ConstantLiteral calculateLiteral(ConstantLiteral value, ProgramScope scope) {
if(value instanceof ConstantInteger) { if(value instanceof ConstantInteger) {
return new ConstantInteger(0xffff & ((ConstantInteger) value).getValue(), SymbolType.WORD); return new ConstantInteger(0xffff & ((ConstantInteger) value).getValue(), SymbolType.WORD);
} } else if(value instanceof ConstantPointer) {
if(value instanceof ConstantPointer) {
return new ConstantInteger(0xffff & ((ConstantPointer) value).getLocation(), SymbolType.WORD); return new ConstantInteger(0xffff & ((ConstantPointer) value).getLocation(), SymbolType.WORD);
} else if(value instanceof ConstantString) {
throw new ConstantNotLiteral("String cannot be cast to word");
} }
throw new CompileError("Calculation not implemented " + getOperator() + " " + value ); throw new CompileError("Calculation not implemented " + getOperator() + " " + value );
} }

View File

@ -35,6 +35,11 @@ public class TestPrograms {
public TestPrograms() { public TestPrograms() {
} }
@Test
public void testOs51() throws IOException, URISyntaxException {
compileAndCompare("complex/unit5/os5.1", log().verboseSSAOptimize());
}
@Test @Test
public void testCpu6502() throws IOException, URISyntaxException { public void testCpu6502() throws IOException, URISyntaxException {
compileAndCompare("cpu-6502"); compileAndCompare("cpu-6502");
@ -2313,6 +2318,11 @@ public class TestPrograms {
compileAndCompare("inline-string-3"); compileAndCompare("inline-string-3");
} }
@Test
public void testInlineString4() throws IOException, URISyntaxException {
compileAndCompare("inline-string-4");
}
@Test @Test
public void testEmptyBlockError() throws IOException, URISyntaxException { public void testEmptyBlockError() throws IOException, URISyntaxException {
compileAndCompare("emptyblock-error"); compileAndCompare("emptyblock-error");

View File

@ -0,0 +1,13 @@
// Test casting the address of an inline string to a dword.
void main() {
const char[] msg = "camelot";
unsigned long dw = (unsigned long)msg;
output(dw);
}
const unsigned long* screen = 0x0400;
void output(unsigned long dw) {
*screen = dw;
}

View File

@ -0,0 +1,23 @@
// Test casting the address of an inline string to a dword.
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label screen = $400
main: {
.label dw = msg
jsr output
rts
msg: .text "camelot"
.byte 0
}
output: {
lda #<main.dw
sta screen
lda #>main.dw
sta screen+1
lda #<main.dw>>$10
sta screen+2
lda #>main.dw>>$10
sta screen+3
rts
}

View File

@ -0,0 +1,22 @@
@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()
[5] call output
to:main::@return
main::@return: scope:[main] from main
[6] return
to:@return
output: scope:[output] from main
[7] *((const dword*) screen#0) ← (const dword) main::dw#0
to:output::@return
output::@return: scope:[output] from output
[8] return
to:@return

View File

@ -0,0 +1,351 @@
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@1
main: scope:[main] from @2
(byte[]) main::msg#0 ← (const string) main::$2
(dword~) main::$0 ← ((dword)) (byte[]) main::msg#0
(dword) main::dw#0 ← (dword~) main::$0
(dword) output::dw#0 ← (dword) main::dw#0
call output
to:main::@1
main::@1: scope:[main] from main
to:main::@return
main::@return: scope:[main] from main::@1
return
to:@return
@1: scope:[] from @begin
(dword*) screen#0 ← ((dword*)) (number) $400
to:@2
output: scope:[output] from main
(dword) output::dw#1 ← phi( main/(dword) output::dw#0 )
*((dword*) screen#0) ← (dword) output::dw#1
to:output::@return
output::@return: scope:[output] from output
return
to:@return
@2: scope:[] from @1
call main
to:@3
@3: scope:[] from @2
to:@end
@end: scope:[] from @3
SYMBOL TABLE SSA
(label) @1
(label) @2
(label) @3
(label) @begin
(label) @end
(void()) main()
(dword~) main::$0
(const string) main::$2 = (string) "camelot"
(label) main::@1
(label) main::@return
(dword) main::dw
(dword) main::dw#0
(byte[]) main::msg
(byte[]) main::msg#0
(void()) output((dword) output::dw)
(label) output::@return
(dword) output::dw
(dword) output::dw#0
(dword) output::dw#1
(dword*) screen
(dword*) screen#0
Inlining cast (dword~) main::$0 ← (dword)(byte[]) main::msg#0
Inlining cast (dword*) screen#0 ← (dword*)(number) $400
Successful SSA optimization Pass2InlineCast
Simplifying constant pointer cast (dword*) 1024
Successful SSA optimization PassNCastSimplification
Alias (dword) main::dw#0 = (dword~) main::$0
Successful SSA optimization Pass2AliasElimination
Identical Phi Values (dword) output::dw#1 (dword) output::dw#0
Successful SSA optimization Pass2IdenticalPhiElimination
Constant (const byte[]) main::msg#0 = main::$2
Constant (const dword*) screen#0 = (dword*) 1024
Successful SSA optimization Pass2ConstantIdentification
Constant value identified (dword)main::msg#0 in [1] (dword) main::dw#0 ← (dword)(const byte[]) main::msg#0
Successful SSA optimization Pass2ConstantValues
Constant (const dword) main::dw#0 = (dword)main::msg#0
Successful SSA optimization Pass2ConstantIdentification
Constant (const dword) output::dw#0 = main::dw#0
Successful SSA optimization Pass2ConstantIdentification
Constant inlined main::$2 = (const byte[]) main::msg#0
Constant inlined output::dw#0 = (const dword) main::dw#0
Successful SSA optimization Pass2ConstantInlining
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 @3
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
Adding NOP phi() at start of main::@1
CALL GRAPH
Calls in [] to main:3
Calls in [main] to output:7
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
Culled Empty Block (label) @1
Culled Empty Block (label) @3
Culled Empty Block (label) main::@1
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
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()
[5] call output
to:main::@return
main::@return: scope:[main] from main
[6] return
to:@return
output: scope:[output] from main
[7] *((const dword*) screen#0) ← (const dword) main::dw#0
to:output::@return
output::@return: scope:[output] from output
[8] return
to:@return
VARIABLE REGISTER WEIGHTS
(void()) main()
(dword) main::dw
(byte[]) main::msg
(void()) output((dword) output::dw)
(dword) output::dw
(dword*) screen
Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Test casting the address of an inline string to a dword.
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label screen = $400
// @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 dw = msg
// [5] call output
jsr output
jmp breturn
// main::@return
breturn:
// [6] return
rts
msg: .text "camelot"
.byte 0
}
// output
output: {
// [7] *((const dword*) screen#0) ← (const dword) main::dw#0 -- _deref_pduc1=vduc2
lda #<main.dw
sta screen
lda #>main.dw
sta screen+1
lda #<main.dw>>$10
sta screen+2
lda #>main.dw>>$10
sta screen+3
jmp breturn
// output::@return
breturn:
// [8] return
rts
}
// File Data
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [7] *((const dword*) screen#0) ← (const dword) main::dw#0 [ ] ( main:2::output:5 [ ] ) always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [main]
Uplift Scope [output]
Uplift Scope []
Uplifting [main] best 60 combination
Uplifting [output] best 60 combination
Uplifting [] best 60 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test casting the address of an inline string to a dword.
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label screen = $400
// @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 dw = msg
// [5] call output
jsr output
jmp breturn
// main::@return
breturn:
// [6] return
rts
msg: .text "camelot"
.byte 0
}
// output
output: {
// [7] *((const dword*) screen#0) ← (const dword) main::dw#0 -- _deref_pduc1=vduc2
lda #<main.dw
sta screen
lda #>main.dw
sta screen+1
lda #<main.dw>>$10
sta screen+2
lda #>main.dw>>$10
sta screen+3
jmp breturn
// output::@return
breturn:
// [8] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp breturn
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction main_from_b1:
Removing instruction bend_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction breturn:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(void()) main()
(label) main::@return
(dword) main::dw
(const dword) main::dw#0 dw = (dword)(const byte[]) main::msg#0
(byte[]) main::msg
(const byte[]) main::msg#0 msg = (string) "camelot"
(void()) output((dword) output::dw)
(label) output::@return
(dword) output::dw
(dword*) screen
(const dword*) screen#0 screen = (dword*) 1024
FINAL ASSEMBLER
Score: 42
// File Comments
// Test casting the address of an inline string to a dword.
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.label screen = $400
// @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: {
.label dw = msg
// output(dw)
// [5] call output
jsr output
// main::@return
// }
// [6] return
rts
msg: .text "camelot"
.byte 0
}
// output
output: {
// *screen = dw
// [7] *((const dword*) screen#0) ← (const dword) main::dw#0 -- _deref_pduc1=vduc2
lda #<main.dw
sta screen
lda #>main.dw
sta screen+1
lda #<main.dw>>$10
sta screen+2
lda #>main.dw>>$10
sta screen+3
// output::@return
// }
// [8] return
rts
}
// File Data

View File

@ -0,0 +1,15 @@
(label) @1
(label) @begin
(label) @end
(void()) main()
(label) main::@return
(dword) main::dw
(const dword) main::dw#0 dw = (dword)(const byte[]) main::msg#0
(byte[]) main::msg
(const byte[]) main::msg#0 msg = (string) "camelot"
(void()) output((dword) output::dw)
(label) output::@return
(dword) output::dw
(dword*) screen
(const dword*) screen#0 screen = (dword*) 1024