mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-19 15:29:48 +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(program.getGraph().toString(program));
|
||||
|
||||
new Pass1ExtractInlineStrings(program).extract();
|
||||
new Pass1EliminateUncalledProcedures(program).eliminate();
|
||||
new Pass1EliminateEmptyBlocks(program).eliminate();
|
||||
log.append("CONTROL FLOW GRAPH");
|
||||
|
@ -112,12 +112,16 @@ public abstract class Scope implements Symbol {
|
||||
}
|
||||
|
||||
public VariableIntermediate addVariableIntermediate() {
|
||||
String name = "$" + intermediateVarCount++;
|
||||
String name = allocateIntermediateVariableName();
|
||||
VariableIntermediate symbol = new VariableIntermediate(name, this, SymbolType.VAR);
|
||||
add(symbol);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public String allocateIntermediateVariableName() {
|
||||
return "$" + intermediateVarCount++;
|
||||
}
|
||||
|
||||
public Symbol getSymbol(SymbolRef symbolRef) {
|
||||
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);
|
||||
for (ConstantVar constant : allConstants) {
|
||||
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;
|
||||
|
@ -24,10 +24,6 @@ public class TestErrors extends TestCase {
|
||||
helper = new ReferenceHelper("dk/camelot64/kickc/test/ref/");
|
||||
}
|
||||
|
||||
public void testInlineString() throws IOException, URISyntaxException {
|
||||
compileAndCompare("inline-string");
|
||||
}
|
||||
|
||||
public void testConstants() throws IOException, URISyntaxException {
|
||||
compileAndCompare("constants");
|
||||
}
|
||||
|
@ -40,6 +40,10 @@ public class TestPrograms extends TestCase {
|
||||
compileAndCompare("unused-method");
|
||||
}
|
||||
|
||||
public void testInlineString() throws IOException, URISyntaxException {
|
||||
compileAndCompare("inline-string");
|
||||
}
|
||||
|
||||
public void testLocalString() throws IOException, URISyntaxException {
|
||||
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 @";
|
||||
void main() {
|
||||
byte[] msg2 = "message 2 @";
|
||||
print(msg1);
|
||||
print("message 2 @");
|
||||
print(msg2);
|
||||
print("message 3 @");
|
||||
}
|
||||
|
||||
byte* screen = $0400;
|
||||
void print(byte* 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