1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-11-27 19:50:10 +00:00

Added versions to struct-unwinding.

This commit is contained in:
jespergravgaard 2019-06-16 22:26:17 +02:00
parent ad6eadad0b
commit 3725bf6821
12 changed files with 197 additions and 129 deletions

View File

@ -223,6 +223,7 @@ public class Compiler {
program.setGraph(new Pass1ProcedureCallsReturnValue(program).generate());
new PassNUnwindLValueLists(program).execute();
new Pass1UnwindStructVersions(program).execute();
getLog().append("\nCONTROL FLOW GRAPH SSA");
getLog().append(program.getGraph().toString(program));

View File

@ -6,7 +6,6 @@ import dk.camelot64.kickc.model.statements.StatementInfos;
import dk.camelot64.kickc.model.symbols.ProgramScope;
import dk.camelot64.kickc.model.values.LabelRef;
import dk.camelot64.kickc.model.values.VariableRef;
import dk.camelot64.kickc.passes.Pass1UnwindStructValues;
import java.nio.file.Path;
import java.util.ArrayList;
@ -75,7 +74,7 @@ public class Program {
/** Cached phi transitions into each block. */
private Map<LabelRef, PhiTransitions> phiTransitions;
/** Struct values unwound to individual variables. */
private Pass1UnwindStructValues.StructUnwinding structUnwinding;
private StructUnwinding structUnwinding;
public Program() {
this.scope = new ProgramScope();
@ -86,11 +85,11 @@ public class Program {
this.reservedZps = new ArrayList<>();
}
public Pass1UnwindStructValues.StructUnwinding getStructUnwinding() {
public StructUnwinding getStructUnwinding() {
return structUnwinding;
}
public void setStructUnwinding(Pass1UnwindStructValues.StructUnwinding structUnwinding) {
public void setStructUnwinding(StructUnwinding structUnwinding) {
this.structUnwinding = structUnwinding;
}

View File

@ -0,0 +1,113 @@
package dk.camelot64.kickc.model;
import dk.camelot64.kickc.model.values.LValue;
import dk.camelot64.kickc.model.values.SymbolRef;
import dk.camelot64.kickc.model.values.VariableRef;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Keeps track of all structs that have been unwound into member variables.
*/
public class StructUnwinding {
/** Maps struct variables to unwinding of each member. */
Map<VariableRef, VariableUnwinding> structVariables = new LinkedHashMap<>();
/**
* Get information about how a struct variable was unwound into member variables
*
* @param ref The variable to look for
* @return Information about the unwinding. Null if not unwound
*/
public VariableUnwinding getVariableUnwinding(VariableRef ref) {
return structVariables.get(ref);
}
/**
* Add information about how a struct variable was unwound into member variables
*
* @param ref The variable to add information for
* @return The new information about the unwinding.
*/
public VariableUnwinding createVariableUnwinding(VariableRef ref) {
VariableUnwinding existing = structVariables.put(ref, new VariableUnwinding());
if(existing != null) {
throw new InternalError("ERROR! Struct unwinding was already created once! " + ref.toString());
}
return structVariables.get(ref);
}
/**
* Find the struct variable that the passed symbol was unwound from.
*
* @param symbolRef The symbol to look for
* @return The struct variable containing it. null if the passed symbol is not an unwound variable.
*/
public VariableRef getContainingStructVariable(SymbolRef symbolRef) {
for(VariableRef structVarRef : structVariables.keySet()) {
VariableUnwinding variableUnwinding = getVariableUnwinding(structVarRef);
for(String memberName : variableUnwinding.getMemberNames()) {
LValue memberUnwinding = variableUnwinding.getMemberUnwinding(memberName);
if(memberUnwinding instanceof VariableRef && memberUnwinding.equals(symbolRef)) {
return structVarRef;
}
}
}
return null;
}
/** Information about how a single struct variable was unwound. */
public static class VariableUnwinding implements StructMemberUnwinding {
/** Maps member names to the unwound variables. */
Map<String, VariableRef> memberUnwinding = new LinkedHashMap<>();
/** Set how a member variable was unwound to a specific (new) variable. */
public void setMemberUnwinding(String memberName, VariableRef memberVariableUnwound) {
this.memberUnwinding.put(memberName, memberVariableUnwound);
}
/**
* Get the names of the members of the struct
*
* @return the names
*/
public List<String> getMemberNames() {
return new ArrayList<>(memberUnwinding.keySet());
}
/**
* Get the (new) variable that a specific member was unwound to
*
* @param memberName The member name
* @return The new variable
*/
public LValue getMemberUnwinding(String memberName) {
return this.memberUnwinding.get(memberName);
}
}
/** Information about how members of an struct Lvalue is unwound. */
public interface StructMemberUnwinding {
/**
* Get the names of the members of the struct
*
* @return the names
*/
List<String> getMemberNames();
/**
* Get the LValue that a specific member was unwound to
*
* @param memberName The member name
* @return The unwinding of the member
*/
LValue getMemberUnwinding(String memberName);
}
}

View File

@ -68,7 +68,7 @@ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
// Special handing of struct value returns
if(procReturnVar.getType() instanceof SymbolTypeStruct) {
Pass1UnwindStructValues.StructUnwinding.VariableUnwinding returnVarUnwinding = program.getStructUnwinding().getVariableUnwinding((VariableRef) procReturnVarRef);
StructUnwinding.VariableUnwinding returnVarUnwinding = program.getStructUnwinding().getVariableUnwinding((VariableRef) procReturnVarRef);
if(returnVarUnwinding!=null) {
ArrayList<RValue> unwoundReturnVars = new ArrayList<>();
for(String memberName : returnVarUnwinding.getMemberNames()) {

View File

@ -269,7 +269,7 @@ public class Pass1UnwindStructValues extends Pass1Base {
private boolean unwindAssignment(StatementAssignment assignment, SymbolTypeStruct structType, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock, StructUnwinding structUnwinding) {
boolean modified = false;
StructMemberUnwinding memberUnwinding = getStructMemberUnwinding(assignment.getlValue(), structType, structUnwinding, assignment, stmtIt, currentBlock);
StructUnwinding.StructMemberUnwinding memberUnwinding = getStructMemberUnwinding(assignment.getlValue(), structType, structUnwinding, assignment, stmtIt, currentBlock);
if(memberUnwinding == null) {
throw new CompileError("Cannot unwind struct assignment " + assignment.toString(getProgram(), false), assignment);
}
@ -322,7 +322,7 @@ public class Pass1UnwindStructValues extends Pass1Base {
SymbolType sourceType = SymbolTypeInference.inferType(getScope(), assignment.getrValue2());
if(sourceType.equals(structType)) {
// Copying a struct - unwind to assigning each member!
StructMemberUnwinding sourceMemberUnwinding = getStructMemberUnwinding((LValue) assignment.getrValue2(), structType, structUnwinding, assignment, stmtIt, currentBlock);
StructUnwinding.StructMemberUnwinding sourceMemberUnwinding = getStructMemberUnwinding((LValue) assignment.getrValue2(), structType, structUnwinding, assignment, stmtIt, currentBlock);
if(sourceMemberUnwinding != null) {
List<RValue> membersUnwound = new ArrayList<>();
stmtIt.previous();
@ -351,7 +351,7 @@ public class Pass1UnwindStructValues extends Pass1Base {
return modified;
}
private StructMemberUnwinding getStructMemberUnwinding(LValue lValue, SymbolTypeStruct lValueType, StructUnwinding structUnwinding, Statement currentStmt, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) {
private StructUnwinding.StructMemberUnwinding getStructMemberUnwinding(LValue lValue, SymbolTypeStruct lValueType, StructUnwinding structUnwinding, Statement currentStmt, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) {
if(lValue instanceof VariableRef) {
return structUnwinding.getVariableUnwinding((VariableRef) lValue);
} else if(lValue instanceof PointerDereferenceSimple) {
@ -364,120 +364,15 @@ public class Pass1UnwindStructValues extends Pass1Base {
}
/** Information about how members of an struct Lvalue is unwound. */
interface StructMemberUnwinding {
/**
* Get the names of the members of the struct
*
* @return the names
*/
List<String> getMemberNames();
/**
* Get the LValue that a specific member was unwound to
*
* @param memberName The member name
* @return The unwinding of the member
*/
LValue getMemberUnwinding(String memberName);
}
/**
* Keeps track of all structs that have been unwound into member variables.
*/
public static class StructUnwinding {
/** Maps struct variables to unwinding of each member. */
Map<VariableRef, VariableUnwinding> structVariables = new LinkedHashMap<>();
/**
* Get information about how a struct variable was unwound into member variables
*
* @param ref The variable to look for
* @return Information about the unwinding. Null if not unwound
*/
VariableUnwinding getVariableUnwinding(VariableRef ref) {
return structVariables.get(ref);
}
/**
* Add information about how a struct variable was unwound into member variables
*
* @param ref The variable to add information for
* @return The new information about the unwinding.
*/
VariableUnwinding createVariableUnwinding(VariableRef ref) {
VariableUnwinding existing = structVariables.put(ref, new VariableUnwinding());
if(existing != null) {
throw new InternalError("ERROR! Struct unwinding was already created once! " + ref.toString());
}
return structVariables.get(ref);
}
/**
* Find the struct variable that the passed symbol was unwound from.
*
* @param symbolRef The symbol to look for
* @return The struct variable containing it. null if the passed symbol is not an unwound variable.
*/
public VariableRef getContainingStructVariable(SymbolRef symbolRef) {
for(VariableRef structVarRef : structVariables.keySet()) {
VariableUnwinding variableUnwinding = getVariableUnwinding(structVarRef);
for(String memberName : variableUnwinding.getMemberNames()) {
LValue memberUnwinding = variableUnwinding.getMemberUnwinding(memberName);
if(memberUnwinding instanceof VariableRef && memberUnwinding.equals(symbolRef)) {
return structVarRef;
}
}
}
return null;
}
/** Information about how a single struct variable was unwound. */
static class VariableUnwinding implements StructMemberUnwinding {
/** Maps member names to the unwound variables. */
Map<String, VariableRef> memberUnwinding = new LinkedHashMap<>();
/** Set how a member variable was unwound to a specific (new) variable. */
void setMemberUnwinding(String memberName, VariableRef memberVariableUnwound) {
this.memberUnwinding.put(memberName, memberVariableUnwound);
}
/**
* Get the names of the members of the struct
*
* @return the names
*/
public List<String> getMemberNames() {
return new ArrayList<>(memberUnwinding.keySet());
}
/**
* Get the (new) variable that a specific member was unwound to
*
* @param memberName The member name
* @return The new variable
*/
public LValue getMemberUnwinding(String memberName) {
return this.memberUnwinding.get(memberName);
}
}
}
/** Unwinding for a simple pointer deref to a struct. */
private class StructMemberUnwindingPointerDerefSimple implements StructMemberUnwinding {
private class StructMemberUnwindingPointerDerefSimple implements StructUnwinding.StructMemberUnwinding {
private final StructDefinition structDefinition;
private final ControlFlowBlock currentBlock;
private final ListIterator<Statement> stmtIt;
private final PointerDereferenceSimple pointerDeref;
private final Statement currentStmt;
public StructMemberUnwindingPointerDerefSimple(PointerDereferenceSimple pointerDeref, StructDefinition structDefinition, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock, Statement currentStmt) {
StructMemberUnwindingPointerDerefSimple(PointerDereferenceSimple pointerDeref, StructDefinition structDefinition, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock, Statement currentStmt) {
this.structDefinition = structDefinition;
this.currentBlock = currentBlock;
this.stmtIt = stmtIt;
@ -511,14 +406,14 @@ public class Pass1UnwindStructValues extends Pass1Base {
}
/** Unwinding for a indexed pointer deref to a struct. */
private class StructMemberUnwindingPointerDerefIndexed implements StructMemberUnwinding {
private class StructMemberUnwindingPointerDerefIndexed implements StructUnwinding.StructMemberUnwinding {
private final StructDefinition structDefinition;
private final ControlFlowBlock currentBlock;
private final ListIterator<Statement> stmtIt;
private final PointerDereferenceIndexed pointerDeref;
private final Statement currentStmt;
public StructMemberUnwindingPointerDerefIndexed(PointerDereferenceIndexed pointerDeref, StructDefinition structDefinition, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock, Statement currentStmt) {
StructMemberUnwindingPointerDerefIndexed(PointerDereferenceIndexed pointerDeref, StructDefinition structDefinition, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock, Statement currentStmt) {
this.structDefinition = structDefinition;
this.currentBlock = currentBlock;
this.stmtIt = stmtIt;

View File

@ -0,0 +1,60 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.StructUnwinding;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.symbols.StructDefinition;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
import dk.camelot64.kickc.model.values.RValue;
import dk.camelot64.kickc.model.values.StructUnwoundPlaceholder;
import dk.camelot64.kickc.model.values.VariableRef;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
/** Find the versioned unwound structs - and update the StructUnwinding data structure */
public class Pass1UnwindStructVersions extends Pass1Base {
public Pass1UnwindStructVersions(Program program) {
super(program);
}
@Override
public boolean step() {
boolean modified = false;
StructUnwinding structUnwinding = getProgram().getStructUnwinding();
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
for(Statement statement : block.getStatements()) {
if(statement instanceof StatementAssignment) {
StatementAssignment assignment = (StatementAssignment) statement;
if(assignment.getOperator() == null && assignment.getlValue() instanceof VariableRef && assignment.getrValue2() instanceof StructUnwoundPlaceholder) {
VariableRef structVarRef = (VariableRef) assignment.getlValue();
if(structUnwinding.getVariableUnwinding(structVarRef) == null) {
StructUnwinding.VariableUnwinding versionedUnwinding = structUnwinding.createVariableUnwinding(structVarRef);
StructUnwoundPlaceholder placeholder = (StructUnwoundPlaceholder) assignment.getrValue2();
SymbolTypeStruct typeStruct = placeholder.getTypeStruct();
StructDefinition structDefinition = typeStruct.getStructDefinition(getProgram().getScope());
Collection<Variable> members = structDefinition.getAllVariables(false);
Iterator<Variable> memberDefIt = members.iterator();
List<RValue> unwoundMembers = placeholder.getUnwoundMembers();
Iterator<RValue> memberUnwoundIt = unwoundMembers.iterator();
while(memberDefIt.hasNext()) {
Variable memberVar = memberDefIt.next();
RValue memberVal = memberUnwoundIt.next();
versionedUnwinding.setMemberUnwinding(memberVar.getLocalName(), (VariableRef) memberVal);
}
getLog().append("Adding versioned struct unwinding for "+assignment.getlValue().toString(getProgram()));
modified = true;
}
}
}
}
}
return modified;
}
}

View File

@ -1,9 +1,6 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.CompileError;
import dk.camelot64.kickc.model.ConstantNotLiteral;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
import dk.camelot64.kickc.model.operators.OperatorBinary;
import dk.camelot64.kickc.model.operators.OperatorUnary;
@ -330,7 +327,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
}
// If the symbol is part of an unwound struct - look at the struct itself
Pass1UnwindStructValues.StructUnwinding structUnwinding = program.getStructUnwinding();
StructUnwinding structUnwinding = program.getStructUnwinding();
VariableRef structVarRef = structUnwinding.getContainingStructVariable(symbolRef);
if(structVarRef != null) {
return isAddressOfUsed(structVarRef, program);

View File

@ -2,6 +2,7 @@ package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.StructUnwinding;
import dk.camelot64.kickc.model.VariableReferenceInfos;
import dk.camelot64.kickc.model.statements.*;
import dk.camelot64.kickc.model.symbols.ConstantVar;
@ -50,15 +51,11 @@ public class PassNEliminateUnusedVars extends Pass2SsaOptimization {
eliminate = true;
} else if(variable.isDeclaredVolatile() && variable.getType() instanceof SymbolTypeStruct) {
// If an unwound volatile struct - eliminate it
if(variable.getRef().isVersion()) {
String fullNameUnversioned = variable.getRef().getFullNameUnversioned();
VariableRef unversionedRef = new VariableRef(fullNameUnversioned);
Pass1UnwindStructValues.StructUnwinding.VariableUnwinding variableUnwinding = getProgram().getStructUnwinding().getVariableUnwinding(unversionedRef);
StructUnwinding.VariableUnwinding variableUnwinding = getProgram().getStructUnwinding().getVariableUnwinding(variable.getRef());
if(variableUnwinding != null) {
eliminate = true;
}
}
}
if(eliminate) {
if(!pass2 && isReturnValue(variable)) {
// Do not eliminate return variables in pass 1

View File

@ -189,6 +189,8 @@ Culled Empty Block (label) @15
Culled Empty Block (label) setupRasterIrq::@4
Unwinding list assignment { (byte) main::$9_x, (byte) main::$9_y, (word) main::$9_dist } ← { (byte) getCharToProcess::return_x, (byte) getCharToProcess::return_y, (word) getCharToProcess::return_dist }
Unwinding list assignment { (byte) getCharToProcess::return_x#0, (byte) getCharToProcess::return_y#0, (word) getCharToProcess::return_dist#0 } ← { (byte) getCharToProcess::return_x#2, (byte) getCharToProcess::return_y#2, (word) getCharToProcess::return_dist#2 }
Adding versioned struct unwinding for (struct ProcessingChar) getCharToProcess::return#0
Adding versioned struct unwinding for (struct ProcessingChar) getCharToProcess::return#1
CONTROL FLOW GRAPH SSA
@begin: scope:[] from

View File

@ -31,6 +31,8 @@ Culled Empty Block (label) @1
Culled Empty Block (label) point::@1
Unwinding list assignment { (byte) main::$0_x, (byte) main::$0_y } ← { (byte) point::return_x, (byte) point::return_y }
Unwinding list assignment { (byte) point::return_x#0, (byte) point::return_y#0 } ← { (byte) point::return_x#2, (byte) point::return_y#2 }
Adding versioned struct unwinding for (struct Point) point::return#0
Adding versioned struct unwinding for (struct Point) point::return#1
CONTROL FLOW GRAPH SSA
@begin: scope:[] from

View File

@ -6,6 +6,7 @@ Adding struct value list initializer (byte) main::p_y ← (number) 3
Rewriting struct pointer member access *((struct Point*) main::q).x
Rewriting struct pointer member access *((struct Point*) main::q).y
Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400
Adding versioned struct unwinding for (struct Point) main::p#0
CONTROL FLOW GRAPH SSA
@begin: scope:[] from

View File

@ -9,6 +9,7 @@ Rewriting struct pointer member access *((struct Point*) set::ptr).x
Rewriting struct pointer member access *((struct Point*) set::ptr).y
Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400
Culled Empty Block (label) @1
Adding versioned struct unwinding for (struct Point) main::p#0
CONTROL FLOW GRAPH SSA
@begin: scope:[] from