1
0
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:
jespergravgaard 2019-06-09 13:56:35 +02:00
parent f29648ca26
commit 30218564d2
7 changed files with 110 additions and 43 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -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)) {

View File

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

View File

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