1
0
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:
jespergravgaard 2017-11-29 21:31:20 +01:00
parent 14987484ee
commit 1c59ae231e
11 changed files with 1991 additions and 10 deletions

View File

@ -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");

View File

@ -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());
} }

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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");
} }

View File

@ -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");
} }

View File

@ -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++);
} }
} }

View 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
}

View 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

File diff suppressed because it is too large Load Diff

View 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 ]