mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-24 20:32:39 +00:00
Fixed problem with inline string by extracting them as local constants. Closes #98
This commit is contained in:
parent
14987484ee
commit
1c59ae231e
@ -86,6 +86,7 @@ public class Compiler {
|
|||||||
log.append("INITIAL CONTROL FLOW GRAPH");
|
log.append("INITIAL CONTROL FLOW GRAPH");
|
||||||
log.append(program.getGraph().toString(program));
|
log.append(program.getGraph().toString(program));
|
||||||
|
|
||||||
|
new Pass1ExtractInlineStrings(program).extract();
|
||||||
new Pass1EliminateUncalledProcedures(program).eliminate();
|
new Pass1EliminateUncalledProcedures(program).eliminate();
|
||||||
new Pass1EliminateEmptyBlocks(program).eliminate();
|
new Pass1EliminateEmptyBlocks(program).eliminate();
|
||||||
log.append("CONTROL FLOW GRAPH");
|
log.append("CONTROL FLOW GRAPH");
|
||||||
|
@ -112,12 +112,16 @@ public abstract class Scope implements Symbol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public VariableIntermediate addVariableIntermediate() {
|
public VariableIntermediate addVariableIntermediate() {
|
||||||
String name = "$" + intermediateVarCount++;
|
String name = allocateIntermediateVariableName();
|
||||||
VariableIntermediate symbol = new VariableIntermediate(name, this, SymbolType.VAR);
|
VariableIntermediate symbol = new VariableIntermediate(name, this, SymbolType.VAR);
|
||||||
add(symbol);
|
add(symbol);
|
||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String allocateIntermediateVariableName() {
|
||||||
|
return "$" + intermediateVarCount++;
|
||||||
|
}
|
||||||
|
|
||||||
public Symbol getSymbol(SymbolRef symbolRef) {
|
public Symbol getSymbol(SymbolRef symbolRef) {
|
||||||
return getSymbol(symbolRef.getFullName());
|
return getSymbol(symbolRef.getFullName());
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
package dk.camelot64.kickc.passes;
|
||||||
|
|
||||||
|
import dk.camelot64.kickc.model.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Eliminate uncalled methods
|
||||||
|
*/
|
||||||
|
public class Pass1ExtractInlineStrings {
|
||||||
|
|
||||||
|
private Program program;
|
||||||
|
|
||||||
|
public Pass1ExtractInlineStrings(Program program) {
|
||||||
|
this.program = program;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void extract() {
|
||||||
|
for (ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||||
|
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||||
|
Scope blockScope = program.getScope().getScope(block.getScope());
|
||||||
|
while (stmtIt.hasNext()) {
|
||||||
|
Statement statement = stmtIt.next();
|
||||||
|
if (statement instanceof StatementCall) {
|
||||||
|
StatementCall call = (StatementCall) statement;
|
||||||
|
ListIterator<RValue> parIt = call.getParameters().listIterator();
|
||||||
|
int parNum = 0;
|
||||||
|
while (parIt.hasNext()) {
|
||||||
|
RValue parameter = parIt.next();
|
||||||
|
if (parameter instanceof ConstantString) {
|
||||||
|
Procedure procedure = program.getScope().getProcedure(call.getProcedure());
|
||||||
|
String parameterName = procedure.getParameterNames().get(parNum);
|
||||||
|
ConstantVar strConst = createStringConstantVar(blockScope, (ConstantString) parameter, parameterName);
|
||||||
|
parIt.set(strConst.getRef());
|
||||||
|
}
|
||||||
|
parNum++;
|
||||||
|
}
|
||||||
|
} else if (statement instanceof StatementAssignment) {
|
||||||
|
StatementAssignment assignment = (StatementAssignment) statement;
|
||||||
|
if(assignment.getrValue1() instanceof ConstantString && assignment.getrValue2() instanceof ConstantString) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (assignment.getrValue1() instanceof ConstantString) {
|
||||||
|
ConstantVar strConst = createStringConstantVar(blockScope, (ConstantString) assignment.getrValue1(), null);
|
||||||
|
assignment.setrValue1(strConst.getRef());
|
||||||
|
}
|
||||||
|
if (assignment.getrValue2() instanceof ConstantString && assignment.getOperator() != null) {
|
||||||
|
ConstantVar strConst = createStringConstantVar(blockScope, (ConstantString) assignment.getrValue2(), null);
|
||||||
|
assignment.setrValue2(strConst.getRef());
|
||||||
|
}
|
||||||
|
} else if (statement instanceof StatementReturn) {
|
||||||
|
StatementReturn statementReturn = (StatementReturn) statement;
|
||||||
|
if (statementReturn.getValue() instanceof ConstantString) {
|
||||||
|
ConstantVar strConst = createStringConstantVar(blockScope, (ConstantString) statementReturn.getValue(), null);
|
||||||
|
statementReturn.setValue(strConst.getRef());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConstantVar createStringConstantVar(Scope blockScope, ConstantString constantString, String nameHint) {
|
||||||
|
String name;
|
||||||
|
if (nameHint == null) {
|
||||||
|
name = blockScope.allocateIntermediateVariableName();
|
||||||
|
} else {
|
||||||
|
int nameHintIdx = 1;
|
||||||
|
name = nameHint;
|
||||||
|
while (blockScope.getSymbol(name) != null) {
|
||||||
|
name = nameHint + nameHintIdx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConstantVar strConst = new ConstantVar(name, blockScope, new SymbolTypeArray(SymbolType.BYTE), constantString);
|
||||||
|
blockScope.add(strConst);
|
||||||
|
program.getLog().append("Creating constant string variable for inline " + strConst.toString(program) + " \"" + constantString.getValue() + "\"");
|
||||||
|
return strConst;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -92,7 +92,9 @@ public class Pass2ConstantInlining extends Pass2SsaOptimization {
|
|||||||
Collection<ConstantVar> allConstants = getProgram().getScope().getAllConstants(true);
|
Collection<ConstantVar> allConstants = getProgram().getScope().getAllConstants(true);
|
||||||
for (ConstantVar constant : allConstants) {
|
for (ConstantVar constant : allConstants) {
|
||||||
if(constant.getRef().isIntermediate()) {
|
if(constant.getRef().isIntermediate()) {
|
||||||
unnamed.put(constant.getRef(), constant.getValue());
|
if(!(constant.getValue() instanceof ConstantString) && !(constant.getValue() instanceof ConstantArray)) {
|
||||||
|
unnamed.put(constant.getRef(), constant.getValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return unnamed;
|
return unnamed;
|
||||||
|
@ -24,10 +24,6 @@ public class TestErrors extends TestCase {
|
|||||||
helper = new ReferenceHelper("dk/camelot64/kickc/test/ref/");
|
helper = new ReferenceHelper("dk/camelot64/kickc/test/ref/");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testInlineString() throws IOException, URISyntaxException {
|
|
||||||
compileAndCompare("inline-string");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testConstants() throws IOException, URISyntaxException {
|
public void testConstants() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("constants");
|
compileAndCompare("constants");
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,10 @@ public class TestPrograms extends TestCase {
|
|||||||
compileAndCompare("unused-method");
|
compileAndCompare("unused-method");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testInlineString() throws IOException, URISyntaxException {
|
||||||
|
compileAndCompare("inline-string");
|
||||||
|
}
|
||||||
|
|
||||||
public void testLocalString() throws IOException, URISyntaxException {
|
public void testLocalString() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("local-string");
|
compileAndCompare("local-string");
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
// Inline Strings in method calls are attempted inlined all the way to ASM. This creates error during binding. Instead a local constant byte[] st = "..."; variable should be created (generating an ASM .text).
|
// Inline Strings in method calls are automatically converted to local constant variables byte[] st = "..."; - generating an ASM .text).
|
||||||
|
|
||||||
byte* screen = $0400;
|
|
||||||
byte[] msg1 = "message 1 @";
|
byte[] msg1 = "message 1 @";
|
||||||
void main() {
|
void main() {
|
||||||
|
byte[] msg2 = "message 2 @";
|
||||||
print(msg1);
|
print(msg1);
|
||||||
print("message 2 @");
|
print(msg2);
|
||||||
|
print("message 3 @");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
byte* screen = $0400;
|
||||||
void print(byte* msg) {
|
void print(byte* msg) {
|
||||||
while(*msg!='@') {
|
while(*msg!='@') {
|
||||||
*(screen++) = *msg;
|
*(screen++) = *(msg++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
52
src/main/java/dk/camelot64/kickc/test/ref/inline-string.asm
Normal file
52
src/main/java/dk/camelot64/kickc/test/ref/inline-string.asm
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
.pc = $801 "Basic"
|
||||||
|
:BasicUpstart(main)
|
||||||
|
.pc = $80d "Program"
|
||||||
|
.label screen = 2
|
||||||
|
msg1: .text "message 1 @"
|
||||||
|
jsr main
|
||||||
|
main: {
|
||||||
|
lda #<$400
|
||||||
|
sta screen
|
||||||
|
lda #>$400
|
||||||
|
sta screen+1
|
||||||
|
lda #<msg1
|
||||||
|
sta print.msg
|
||||||
|
lda #>msg1
|
||||||
|
sta print.msg+1
|
||||||
|
jsr print
|
||||||
|
lda #<msg2
|
||||||
|
sta print.msg
|
||||||
|
lda #>msg2
|
||||||
|
sta print.msg+1
|
||||||
|
jsr print
|
||||||
|
lda #<msg
|
||||||
|
sta print.msg
|
||||||
|
lda #>msg
|
||||||
|
sta print.msg+1
|
||||||
|
jsr print
|
||||||
|
rts
|
||||||
|
msg: .text "message 3 @"
|
||||||
|
msg2: .text "message 2 @"
|
||||||
|
}
|
||||||
|
print: {
|
||||||
|
.label msg = 4
|
||||||
|
b1:
|
||||||
|
ldy #0
|
||||||
|
lda (msg),y
|
||||||
|
cmp #'@'
|
||||||
|
bne b2
|
||||||
|
rts
|
||||||
|
b2:
|
||||||
|
ldy #0
|
||||||
|
lda (msg),y
|
||||||
|
sta (screen),y
|
||||||
|
inc screen
|
||||||
|
bne !+
|
||||||
|
inc screen+1
|
||||||
|
!:
|
||||||
|
inc msg
|
||||||
|
bne !+
|
||||||
|
inc msg+1
|
||||||
|
!:
|
||||||
|
jmp b1
|
||||||
|
}
|
41
src/main/java/dk/camelot64/kickc/test/ref/inline-string.cfg
Normal file
41
src/main/java/dk/camelot64/kickc/test/ref/inline-string.cfg
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
@begin: scope:[] from
|
||||||
|
[0] phi() [ ] ( )
|
||||||
|
to:@2
|
||||||
|
@2: scope:[] from @begin
|
||||||
|
[1] phi() [ ] ( )
|
||||||
|
[2] call main param-assignment [ ] ( )
|
||||||
|
to:@end
|
||||||
|
@end: scope:[] from @2
|
||||||
|
[3] phi() [ ] ( )
|
||||||
|
main: scope:[main] from @2
|
||||||
|
[4] phi() [ ] ( main:2 [ ] )
|
||||||
|
[5] call print param-assignment [ screen#12 ] ( main:2 [ screen#12 ] )
|
||||||
|
to:main::@1
|
||||||
|
main::@1: scope:[main] from main
|
||||||
|
[6] phi() [ screen#12 ] ( main:2 [ screen#12 ] )
|
||||||
|
[7] call print param-assignment [ screen#12 ] ( main:2 [ screen#12 ] )
|
||||||
|
to:main::@2
|
||||||
|
main::@2: scope:[main] from main::@1
|
||||||
|
[8] phi() [ screen#12 ] ( main:2 [ screen#12 ] )
|
||||||
|
[9] call print param-assignment [ ] ( main:2 [ ] )
|
||||||
|
to:main::@return
|
||||||
|
main::@return: scope:[main] from main::@2
|
||||||
|
[10] return [ ] ( main:2 [ ] )
|
||||||
|
to:@return
|
||||||
|
print: scope:[print] from main main::@1 main::@2
|
||||||
|
[11] (byte*) screen#18 ← phi( main/((byte*))(word/signed word) 1024 main::@1/(byte*) screen#12 main::@2/(byte*) screen#12 ) [ print::msg#6 screen#18 ] ( main:2::print:5 [ print::msg#6 screen#18 ] main:2::print:7 [ print::msg#6 screen#18 ] main:2::print:9 [ print::msg#6 screen#18 ] )
|
||||||
|
[11] (byte*) print::msg#6 ← phi( main/(const byte[]) msg1#0 main::@1/(const byte[]) main::msg2#0 main::@2/(const byte[]) main::msg ) [ print::msg#6 screen#18 ] ( main:2::print:5 [ print::msg#6 screen#18 ] main:2::print:7 [ print::msg#6 screen#18 ] main:2::print:9 [ print::msg#6 screen#18 ] )
|
||||||
|
to:print::@1
|
||||||
|
print::@1: scope:[print] from print print::@2
|
||||||
|
[12] (byte*) screen#12 ← phi( print/(byte*) screen#18 print::@2/(byte*) screen#5 ) [ screen#12 print::msg#4 ] ( main:2::print:5 [ screen#12 print::msg#4 ] main:2::print:7 [ screen#12 print::msg#4 ] main:2::print:9 [ screen#12 print::msg#4 ] )
|
||||||
|
[12] (byte*) print::msg#4 ← phi( print/(byte*) print::msg#6 print::@2/(byte*) print::msg#3 ) [ screen#12 print::msg#4 ] ( main:2::print:5 [ screen#12 print::msg#4 ] main:2::print:7 [ screen#12 print::msg#4 ] main:2::print:9 [ screen#12 print::msg#4 ] )
|
||||||
|
[13] if(*((byte*) print::msg#4)!=(byte) '@') goto print::@2 [ screen#12 print::msg#4 ] ( main:2::print:5 [ screen#12 print::msg#4 ] main:2::print:7 [ screen#12 print::msg#4 ] main:2::print:9 [ screen#12 print::msg#4 ] )
|
||||||
|
to:print::@return
|
||||||
|
print::@return: scope:[print] from print::@1
|
||||||
|
[14] return [ screen#12 ] ( main:2::print:5 [ screen#12 ] main:2::print:7 [ screen#12 ] main:2::print:9 [ screen#12 ] )
|
||||||
|
to:@return
|
||||||
|
print::@2: scope:[print] from print::@1
|
||||||
|
[15] *((byte*) screen#12) ← *((byte*) print::msg#4) [ screen#12 print::msg#4 ] ( main:2::print:5 [ screen#12 print::msg#4 ] main:2::print:7 [ screen#12 print::msg#4 ] main:2::print:9 [ screen#12 print::msg#4 ] )
|
||||||
|
[16] (byte*) screen#5 ← ++ (byte*) screen#12 [ print::msg#4 screen#5 ] ( main:2::print:5 [ print::msg#4 screen#5 ] main:2::print:7 [ print::msg#4 screen#5 ] main:2::print:9 [ print::msg#4 screen#5 ] )
|
||||||
|
[17] (byte*) print::msg#3 ← ++ (byte*) print::msg#4 [ print::msg#3 screen#5 ] ( main:2::print:5 [ print::msg#3 screen#5 ] main:2::print:7 [ print::msg#3 screen#5 ] main:2::print:9 [ print::msg#3 screen#5 ] )
|
||||||
|
to:print::@1
|
1772
src/main/java/dk/camelot64/kickc/test/ref/inline-string.log
Normal file
1772
src/main/java/dk/camelot64/kickc/test/ref/inline-string.log
Normal file
File diff suppressed because it is too large
Load Diff
27
src/main/java/dk/camelot64/kickc/test/ref/inline-string.sym
Normal file
27
src/main/java/dk/camelot64/kickc/test/ref/inline-string.sym
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
(label) @2
|
||||||
|
(label) @begin
|
||||||
|
(label) @end
|
||||||
|
(void()) main()
|
||||||
|
(label) main::@1
|
||||||
|
(label) main::@2
|
||||||
|
(label) main::@return
|
||||||
|
(const byte[]) main::msg msg = (string) "message 3 @"
|
||||||
|
(byte[]) main::msg2
|
||||||
|
(const byte[]) main::msg2#0 msg2 = (string) "message 2 @"
|
||||||
|
(byte[]) msg1
|
||||||
|
(const byte[]) msg1#0 msg1 = (string) "message 1 @"
|
||||||
|
(void()) print((byte*) print::msg)
|
||||||
|
(label) print::@1
|
||||||
|
(label) print::@2
|
||||||
|
(label) print::@return
|
||||||
|
(byte*) print::msg
|
||||||
|
(byte*) print::msg#3 msg zp ZP_PTR_BYTE:4 22.0
|
||||||
|
(byte*) print::msg#4 msg zp ZP_PTR_BYTE:4 11.5
|
||||||
|
(byte*) print::msg#6 msg zp ZP_PTR_BYTE:4 2.0
|
||||||
|
(byte*) screen
|
||||||
|
(byte*) screen#12 screen zp ZP_PTR_BYTE:2 4.875
|
||||||
|
(byte*) screen#18 screen zp ZP_PTR_BYTE:2 6.0
|
||||||
|
(byte*) screen#5 screen zp ZP_PTR_BYTE:2 11.0
|
||||||
|
|
||||||
|
zp ZP_PTR_BYTE:2 [ screen#18 screen#12 screen#5 ]
|
||||||
|
zp ZP_PTR_BYTE:4 [ print::msg#4 print::msg#6 print::msg#3 ]
|
Loading…
Reference in New Issue
Block a user