mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-16 18:30:37 +00:00
Work-in-progress: Unwinding struct return values.
This commit is contained in:
parent
f29648ca26
commit
30218564d2
@ -203,18 +203,21 @@ public class Compiler {
|
||||
getLog().append(program.getProcedureModifiedVars().toString(program));
|
||||
}
|
||||
|
||||
getLog().append("CONTROL FLOW GRAPH (CLEANED)");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
|
||||
new Pass1ProcedureCallParameters(program).generate();
|
||||
//getLog().append("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL");
|
||||
//getLog().append(program.getGraph().toString(program));
|
||||
getLog().append("CONTROL FLOW GRAPH (CALL PARAMETERS)");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
|
||||
new Pass1GenerateSingleStaticAssignmentForm(program).execute();
|
||||
|
||||
//getLog().append("CONTROL FLOW GRAPH SSA");
|
||||
//getLog().append(program.getGraph().toString(program));
|
||||
getLog().append("CONTROL FLOW GRAPH (SSA)");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
|
||||
program.setGraph(new Pass1ProcedureCallsReturnValue(program).generate());
|
||||
|
||||
getLog().append("\nCONTROL FLOW GRAPH SSA");
|
||||
getLog().append("\nCONTROL FLOW GRAPH SSA (RETURN VALUES)");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
|
||||
getLog().append("SYMBOL TABLE SSA");
|
||||
|
@ -5,12 +5,10 @@ import dk.camelot64.kickc.model.Program;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A list of sub-values. Used for array variable initializers and word from byte constructors
|
||||
* (in the future also usable for dword from byte, dword from double etc.).
|
||||
* Compilation execution will resolve into a constant array,
|
||||
* constant word or word constructor operator before ASM-generation.
|
||||
* A list of sub-values.
|
||||
* Used for array variable initializers, struct value initilizers, word/dword initializers.
|
||||
*/
|
||||
public class ValueList implements RValue {
|
||||
public class ValueList implements LValue {
|
||||
|
||||
private List<RValue> list;
|
||||
|
||||
|
@ -1,18 +1,16 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
import dk.camelot64.kickc.model.statements.StatementCall;
|
||||
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
|
||||
import dk.camelot64.kickc.model.statements.StatementReturn;
|
||||
import dk.camelot64.kickc.model.symbols.*;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/** Pass that modifies a control flow graph to call procedures by passing parameters through registers */
|
||||
public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
|
||||
@ -34,7 +32,7 @@ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
|
||||
for(StatementPhiBlock.PhiVariable phiVariable : block.getPhiBlock().getPhiVariables()) {
|
||||
for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
|
||||
LabelRef splitBlockNew = splitBlockMap.get(phiRValue.getPredecessor());
|
||||
if(splitBlockNew !=null) {
|
||||
if(splitBlockNew != null) {
|
||||
phiRValue.setPredecessor(splitBlockNew);
|
||||
}
|
||||
}
|
||||
@ -64,10 +62,23 @@ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
|
||||
}
|
||||
String procedureName = origCall.getProcedureName();
|
||||
Variable procReturnVar = procedure.getVariable("return");
|
||||
VariableRef procReturnVarRef = null;
|
||||
LValue procReturnVarRef = null;
|
||||
if(procReturnVar != null) {
|
||||
procReturnVarRef = procReturnVar.getRef();
|
||||
|
||||
// Special handing of struct value returns
|
||||
if(procReturnVar.getType() instanceof SymbolTypeStruct) {
|
||||
Pass1UnwindStructValues.StructUnwinding.VariableUnwinding returnVarUnwinding = program.getStructUnwinding().getVariableUnwinding((VariableRef) procReturnVarRef);
|
||||
if(returnVarUnwinding!=null) {
|
||||
ArrayList<RValue> unwoundReturnVars = new ArrayList<>();
|
||||
for(String memberName : returnVarUnwinding.getMemberNames()) {
|
||||
unwoundReturnVars.add(returnVarUnwinding.getMemberUnwinding(memberName));
|
||||
}
|
||||
procReturnVarRef = new ValueList(unwoundReturnVars);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StatementCall copyCall = new StatementCall(procReturnVarRef, procedureName, null, origCall.getSource(), Comment.NO_COMMENTS);
|
||||
copyCall.setProcedure(procedureRef);
|
||||
addStatementToCurrentBlock(copyCall);
|
||||
|
@ -42,13 +42,15 @@ public class Pass1ProcedureCallsReturnValue extends ControlFlowGraphCopyVisitor
|
||||
// Find return variable final version
|
||||
Label returnBlockLabel = procedure.getLabel(SymbolRef.PROCEXIT_BLOCK_NAME);
|
||||
ControlFlowBlock returnBlock = program.getGraph().getBlock(returnBlockLabel.getRef());
|
||||
VariableRef returnVarFinal = null;
|
||||
RValue returnVarFinal = null;
|
||||
for(Statement statement : returnBlock.getStatements()) {
|
||||
if(statement instanceof StatementReturn) {
|
||||
StatementReturn statementReturn = (StatementReturn) statement;
|
||||
RValue returnValue = statementReturn.getValue();
|
||||
if(returnValue instanceof VariableRef) {
|
||||
returnVarFinal = (VariableRef) returnValue;
|
||||
returnVarFinal = returnValue;
|
||||
} else if(returnValue instanceof ValueList) {
|
||||
returnVarFinal = returnValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
import dk.camelot64.kickc.model.statements.StatementCall;
|
||||
import dk.camelot64.kickc.model.statements.StatementReturn;
|
||||
import dk.camelot64.kickc.model.symbols.*;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
@ -30,13 +31,13 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
||||
}
|
||||
|
||||
// Iterate through all scopes generating member-variables for each struct
|
||||
modified |= unwindAllStructVariables(structUnwinding);
|
||||
modified |= unwindStructVariables(structUnwinding);
|
||||
// Unwind all procedure declaration parameters
|
||||
modified |= unwindProcedureParameters(structUnwinding);
|
||||
modified |= unwindStructParameters(structUnwinding);
|
||||
// Unwind all usages of struct values
|
||||
modified |= unwindStructReferences(structUnwinding);
|
||||
// Change all usages of members of struct values
|
||||
modified |= unwindMemberReferences(structUnwinding);
|
||||
modified |= unwindStructMemberReferences(structUnwinding);
|
||||
return modified;
|
||||
}
|
||||
|
||||
@ -61,6 +62,8 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
||||
}
|
||||
} else if(statement instanceof StatementCall) {
|
||||
modified |= unwindCall((StatementCall) statement, structUnwinding);
|
||||
} else if(statement instanceof StatementReturn) {
|
||||
modified |= unwindReturn((StatementReturn) statement, structUnwinding);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -72,7 +75,7 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
||||
*
|
||||
* @param structUnwinding Information about all unwound struct variables
|
||||
*/
|
||||
private boolean unwindMemberReferences(StructUnwinding structUnwinding) {
|
||||
private boolean unwindStructMemberReferences(StructUnwinding structUnwinding) {
|
||||
AtomicBoolean modified = new AtomicBoolean(false);
|
||||
ProgramValueIterator.execute(
|
||||
getProgram(), (programValue, currentStmt, stmtIt, currentBlock) ->
|
||||
@ -97,14 +100,34 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
||||
/**
|
||||
* Unwind any call parameter that is a struct value into the member values
|
||||
*
|
||||
* @param statementCall The call to unwind
|
||||
* @param call The call to unwind
|
||||
* @param structUnwinding Information about all unwound struct variables
|
||||
*/
|
||||
private boolean unwindCall(StatementCall statementCall, StructUnwinding structUnwinding) {
|
||||
//Procedure procedure = getScope().getProcedure(statementCall.getProcedure());
|
||||
private boolean unwindCall(StatementCall call, StructUnwinding structUnwinding) {
|
||||
|
||||
// Unwind struct value return value
|
||||
boolean lvalUnwound = false;
|
||||
if(call.getlValue() instanceof VariableRef) {
|
||||
Variable lvalueVar = getScope().getVariable((VariableRef) call.getlValue());
|
||||
if(lvalueVar.getType() instanceof SymbolTypeStruct) {
|
||||
StructUnwinding.VariableUnwinding lValueVarUnwinding = structUnwinding.getVariableUnwinding(lvalueVar.getRef());
|
||||
if(lValueVarUnwinding != null) {
|
||||
ArrayList<RValue> unwoundMembers = new ArrayList<>();
|
||||
for(String memberName : lValueVarUnwinding.getMemberNames()) {
|
||||
unwoundMembers.add(lValueVarUnwinding.getMemberUnwinding(memberName));
|
||||
}
|
||||
ValueList unwoundLValue = new ValueList(unwoundMembers);
|
||||
call.setlValue(unwoundLValue);
|
||||
getLog().append("Converted procedure call LValue to member variables " + call.toString(getProgram(), false));
|
||||
lvalUnwound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unwind any struct value parameters
|
||||
ArrayList<RValue> unwoundParameters = new ArrayList<>();
|
||||
boolean anyUnwound = false;
|
||||
for(RValue parameter : statementCall.getParameters()) {
|
||||
boolean anyParameterUnwound = false;
|
||||
for(RValue parameter : call.getParameters()) {
|
||||
boolean unwound = false;
|
||||
if(parameter instanceof VariableRef) {
|
||||
Variable variable = getScope().getVariable((VariableRef) parameter);
|
||||
@ -116,7 +139,7 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
||||
unwoundParameters.add(variableUnwinding.getMemberUnwinding(memberName));
|
||||
}
|
||||
unwound = true;
|
||||
anyUnwound = true;
|
||||
anyParameterUnwound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -125,19 +148,49 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
||||
}
|
||||
}
|
||||
|
||||
if(anyUnwound) {
|
||||
statementCall.setParameters(unwoundParameters);
|
||||
getLog().append("Converted procedure struct value parameter to member variables in call " + statementCall.toString(getProgram(), false));
|
||||
if(anyParameterUnwound) {
|
||||
call.setParameters(unwoundParameters);
|
||||
getLog().append("Converted procedure struct value parameter to member variables in call " + call.toString(getProgram(), false));
|
||||
}
|
||||
return anyUnwound;
|
||||
return (anyParameterUnwound || lvalUnwound);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwind any return value that is a struct value into the member values
|
||||
*
|
||||
* @param statementReturn The return to unwind
|
||||
* @param structUnwinding Information about all unwound struct variables
|
||||
*/
|
||||
|
||||
private boolean unwindReturn(StatementReturn statementReturn, StructUnwinding structUnwinding) {
|
||||
boolean modified = false;
|
||||
// Unwind struct value return value
|
||||
if(statementReturn.getValue() instanceof VariableRef) {
|
||||
Variable returnValueVar = getScope().getVariable((VariableRef) statementReturn.getValue());
|
||||
if(returnValueVar.getType() instanceof SymbolTypeStruct) {
|
||||
StructUnwinding.VariableUnwinding returnVarUnwinding = structUnwinding.getVariableUnwinding(returnValueVar.getRef());
|
||||
if(returnVarUnwinding != null) {
|
||||
ArrayList<RValue> unwoundMembers = new ArrayList<>();
|
||||
for(String memberName : returnVarUnwinding.getMemberNames()) {
|
||||
unwoundMembers.add(returnVarUnwinding.getMemberUnwinding(memberName));
|
||||
}
|
||||
ValueList unwoundReturnValue = new ValueList(unwoundMembers);
|
||||
statementReturn.setValue(unwoundReturnValue);
|
||||
getLog().append("Converted procedure struct return value to member variables " + statementReturn.toString(getProgram(), false));
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Iterate through all procedures changing parameter lists by unwinding each struct value parameter to the unwound member variables
|
||||
*
|
||||
* @param structUnwinding Information about all unwound struct variables (including procedure parameters)
|
||||
*/
|
||||
private boolean unwindProcedureParameters(StructUnwinding structUnwinding) {
|
||||
private boolean unwindStructParameters(StructUnwinding structUnwinding) {
|
||||
boolean modified = false;
|
||||
// Iterate through all procedures changing parameter lists by unwinding each struct value parameter
|
||||
for(Procedure procedure : getScope().getAllProcedures(true)) {
|
||||
@ -168,7 +221,7 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
||||
*
|
||||
* @return Information about all unwound struct variables
|
||||
*/
|
||||
private boolean unwindAllStructVariables(StructUnwinding structUnwinding) {
|
||||
private boolean unwindStructVariables(StructUnwinding structUnwinding) {
|
||||
boolean modified = false;
|
||||
// Iterate through all scopes generating member-variables for each struct
|
||||
for(Variable variable : getScope().getAllVariables(true)) {
|
||||
|
@ -80,10 +80,10 @@ public class TestPrograms {
|
||||
compileAndCompare("struct-6");
|
||||
}
|
||||
|
||||
//@Test
|
||||
//public void testStruct5() throws IOException, URISyntaxException {
|
||||
// compileAndCompare("struct-5", log().verboseParse().verboseCreateSsa());
|
||||
//}
|
||||
@Test
|
||||
public void testStruct5() throws IOException, URISyntaxException {
|
||||
compileAndCompare("struct-5", log().verboseParse().verboseCreateSsa());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStruct4() throws IOException, URISyntaxException {
|
||||
|
@ -7,14 +7,14 @@ struct Point {
|
||||
|
||||
void main() {
|
||||
struct Point q;
|
||||
q = point(2,3);
|
||||
q = point();
|
||||
|
||||
const byte* SCREEN = 0x0400;
|
||||
SCREEN[0] = q.x;
|
||||
SCREEN[1] = q.y;
|
||||
}
|
||||
|
||||
struct Point point(byte x, byte y) {
|
||||
struct Point p = { x, y };
|
||||
struct Point point() {
|
||||
struct Point p = { 2, 3 };
|
||||
return p;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user