mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-01-23 09:33:30 +00:00
Refactoring control flow graph to enable proc calls. Still need to handle return values properly.
This commit is contained in:
parent
12bff79433
commit
3b2cc5cde1
7
.idea/dictionaries/jespergravgaard.xml
generated
Normal file
7
.idea/dictionaries/jespergravgaard.xml
generated
Normal file
@ -0,0 +1,7 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="jespergravgaard">
|
||||
<words>
|
||||
<w>unversioned</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
@ -4,23 +4,23 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** A named/labelled sequence of SSA statements connected to other basic blocks.
|
||||
* The connections defines the control flow of the program. */
|
||||
* The connections defines the control flow of the program.
|
||||
* The block only knows its own successors. To find predecessor blocks access to the entire graph is needed.*/
|
||||
public class ControlFlowBlock {
|
||||
|
||||
private Label label;
|
||||
|
||||
private List<ControlFlowBlock> predecessors;
|
||||
|
||||
private List<Statement> statements;
|
||||
|
||||
private ControlFlowBlock defaultSuccessor;
|
||||
private Label defaultSuccessor;
|
||||
|
||||
private ControlFlowBlock conditionalSuccessor;
|
||||
private Label conditionalSuccessor;
|
||||
|
||||
private Label callSuccessor;
|
||||
|
||||
public ControlFlowBlock(Label label) {
|
||||
this.label = label;
|
||||
this.statements = new ArrayList<>();
|
||||
this.predecessors = new ArrayList<>();
|
||||
this.defaultSuccessor = null;
|
||||
this.conditionalSuccessor = null;
|
||||
}
|
||||
@ -33,32 +33,28 @@ public class ControlFlowBlock {
|
||||
this.statements.add(statement);
|
||||
}
|
||||
|
||||
public void addPredecessor(ControlFlowBlock block) {
|
||||
this.predecessors.add(block);
|
||||
}
|
||||
|
||||
public void setDefaultSuccessor(ControlFlowBlock defaultSuccessor) {
|
||||
public void setDefaultSuccessor(Label defaultSuccessor) {
|
||||
this.defaultSuccessor = defaultSuccessor;
|
||||
}
|
||||
|
||||
public ControlFlowBlock getDefaultSuccessor() {
|
||||
public Label getDefaultSuccessor() {
|
||||
return defaultSuccessor;
|
||||
}
|
||||
|
||||
public ControlFlowBlock getConditionalSuccessor() {
|
||||
public Label getConditionalSuccessor() {
|
||||
return conditionalSuccessor;
|
||||
}
|
||||
|
||||
public List<ControlFlowBlock> getPredecessors() {
|
||||
return predecessors;
|
||||
}
|
||||
|
||||
public void setConditionalSuccessor(ControlFlowBlock conditionalSuccessor) {
|
||||
public void setConditionalSuccessor(Label conditionalSuccessor) {
|
||||
this.conditionalSuccessor = conditionalSuccessor;
|
||||
}
|
||||
|
||||
public void removePredecessor(ControlFlowBlock block) {
|
||||
predecessors.remove(block);
|
||||
public Label getCallSuccessor() {
|
||||
return callSuccessor;
|
||||
}
|
||||
|
||||
public void setCallSuccessor(Label callSuccessor) {
|
||||
this.callSuccessor = callSuccessor;
|
||||
}
|
||||
|
||||
public List<Statement> getStatements() {
|
||||
@ -71,13 +67,22 @@ public class ControlFlowBlock {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(null);
|
||||
}
|
||||
|
||||
public String toString(ControlFlowGraph graph) {
|
||||
StringBuffer out = new StringBuffer();
|
||||
out.append(label.getLocalName() + ":" );
|
||||
if(predecessors.size()>0) {
|
||||
out.append(" from");
|
||||
for (ControlFlowBlock predecessor : predecessors) {
|
||||
out.append(" " + predecessor.getLabel().getLocalName());
|
||||
out.append(" from");
|
||||
if(graph!=null) {
|
||||
List<ControlFlowBlock> predecessors = graph.getPredecessors(this);
|
||||
if(predecessors.size()>0) {
|
||||
for (ControlFlowBlock predecessor : predecessors) {
|
||||
out.append(" " + predecessor.getLabel().getLocalName());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.append(" @UNKNOWN");
|
||||
}
|
||||
out.append("\n");
|
||||
for (Statement statement : statements) {
|
||||
@ -85,7 +90,7 @@ public class ControlFlowBlock {
|
||||
}
|
||||
if(defaultSuccessor!=null) {
|
||||
out.append(" to:");
|
||||
out.append(defaultSuccessor.getLabel().getLocalName());
|
||||
out.append(defaultSuccessor.getLocalName());
|
||||
out.append("\n");
|
||||
}
|
||||
return out.toString();
|
||||
@ -112,4 +117,5 @@ public class ControlFlowBlock {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/** The control flow graph of the program.
|
||||
@ -28,7 +30,7 @@ public class ControlFlowGraph {
|
||||
public String toString() {
|
||||
StringBuffer out = new StringBuffer();
|
||||
for (ControlFlowBlock block : blocks.values()) {
|
||||
out.append(block.toString());
|
||||
out.append(block.toString(this));
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
@ -59,4 +61,27 @@ public class ControlFlowGraph {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ControlFlowBlock getDefaultSuccessor(ControlFlowBlock block) {
|
||||
if(block.getDefaultSuccessor()!=null) {
|
||||
return blocks.get(block.getDefaultSuccessor());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<ControlFlowBlock> getPredecessors(ControlFlowBlock block) {
|
||||
ArrayList<ControlFlowBlock> predecessorBlocks = new ArrayList<>();
|
||||
for (ControlFlowBlock other : getAllBlocks()) {
|
||||
if(block.getLabel().equals(other.getDefaultSuccessor())) {
|
||||
predecessorBlocks.add(other);
|
||||
}
|
||||
if(block.getLabel().equals(other.getConditionalSuccessor())) {
|
||||
predecessorBlocks.add(other);
|
||||
}
|
||||
if(block.getLabel().equals(other.getCallSuccessor())) {
|
||||
predecessorBlocks.add(other);
|
||||
}
|
||||
}
|
||||
return predecessorBlocks;
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ public class ControlFlowGraphBaseVisitor<T> {
|
||||
return null;
|
||||
}
|
||||
|
||||
public T visitStatement(Statement statement) {
|
||||
public Object visitStatement(Statement statement) {
|
||||
if(statement instanceof StatementAssignment) {
|
||||
return visitAssignment((StatementAssignment) statement);
|
||||
} else if(statement instanceof StatementConditionalJump) {
|
||||
@ -31,11 +31,31 @@ public class ControlFlowGraphBaseVisitor<T> {
|
||||
return visitJumpTarget((StatementLabel) statement);
|
||||
} else if(statement instanceof StatementPhi) {
|
||||
return visitPhi((StatementPhi) statement);
|
||||
} else if(statement instanceof StatementCallLValue) {
|
||||
return visitCallLValue((StatementCallLValue) statement);
|
||||
} else if(statement instanceof StatementReturn) {
|
||||
return visitReturn((StatementReturn) statement);
|
||||
} else if(statement instanceof StatementProcedureBegin) {
|
||||
return visitProcedureBegin((StatementProcedureBegin) statement);
|
||||
} else if(statement instanceof StatementProcedureEnd) {
|
||||
return visitProcedureEnd((StatementProcedureEnd) statement);
|
||||
} else {
|
||||
throw new RuntimeException("Unhandled statement type "+statement);
|
||||
}
|
||||
}
|
||||
|
||||
public T visitProcedureBegin(StatementProcedureBegin statement) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public T visitProcedureEnd(StatementProcedureEnd statement) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public T visitReturn(StatementReturn aReturn) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public T visitAssignment(StatementAssignment assignment) {
|
||||
return null;
|
||||
}
|
||||
@ -56,4 +76,8 @@ public class ControlFlowGraphBaseVisitor<T> {
|
||||
return null;
|
||||
}
|
||||
|
||||
public T visitCallLValue(StatementCallLValue callLValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
180
src/dk/camelot64/kickc/icl/ControlFlowGraphCopyVisitor.java
Normal file
180
src/dk/camelot64/kickc/icl/ControlFlowGraphCopyVisitor.java
Normal file
@ -0,0 +1,180 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A visitor that copies a complete control flow graph. contains visitor-methods usable for modifying the copy at any point
|
||||
*/
|
||||
public class ControlFlowGraphCopyVisitor extends ControlFlowGraphBaseVisitor<Object> {
|
||||
|
||||
/**
|
||||
* The origGraph graph.
|
||||
*/
|
||||
private ControlFlowGraph origGraph;
|
||||
|
||||
/**
|
||||
* The copied blocks.
|
||||
*/
|
||||
private HashMap<Symbol, ControlFlowBlock> copyBlockMap;
|
||||
|
||||
/**
|
||||
* The current block being copied.
|
||||
*/
|
||||
private ControlFlowBlock origBlock;
|
||||
|
||||
/**
|
||||
* The current block where statements are generated into.
|
||||
*/
|
||||
private ControlFlowBlock copyBlock;
|
||||
|
||||
@Override
|
||||
public ControlFlowGraph visitGraph(ControlFlowGraph origGraph) {
|
||||
this.origGraph = origGraph;
|
||||
// Copy all blocks
|
||||
this.copyBlockMap = new HashMap<>();
|
||||
for (ControlFlowBlock origBlock : origGraph.getAllBlocks()) {
|
||||
ControlFlowBlock copyBlock = visitBlock(origBlock);
|
||||
if (copyBlock != null) {
|
||||
copyBlockMap.put(copyBlock.getLabel(), copyBlock);
|
||||
}
|
||||
}
|
||||
ControlFlowBlock copyFirstBlock = copyBlockMap.get(origGraph.getFirstBlock().getLabel());
|
||||
ControlFlowGraph copyGraph = new ControlFlowGraph(copyBlockMap, copyFirstBlock);
|
||||
return copyGraph;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ControlFlowBlock visitBlock(ControlFlowBlock origBlock) {
|
||||
Label label = origBlock.getLabel();
|
||||
ControlFlowBlock copyBlock = new ControlFlowBlock(label);
|
||||
this.origBlock = origBlock;
|
||||
this.copyBlock = copyBlock;
|
||||
// Handle statements
|
||||
List<Statement> origBlockStatements = origBlock.getStatements();
|
||||
for (Statement origStatement : origBlockStatements) {
|
||||
Statement copyStatement = visitStatement(origStatement);
|
||||
if (copyStatement != null) {
|
||||
this.copyBlock.addStatement(copyStatement);
|
||||
}
|
||||
}
|
||||
// Handle successors
|
||||
if (origBlock.getDefaultSuccessor() != null) {
|
||||
this.copyBlock.setDefaultSuccessor(origBlock.getDefaultSuccessor());
|
||||
}
|
||||
if (origBlock.getConditionalSuccessor() != null) {
|
||||
this.copyBlock.setConditionalSuccessor(origBlock.getConditionalSuccessor());
|
||||
}
|
||||
if (origBlock.getCallSuccessor() != null) {
|
||||
this.copyBlock.setCallSuccessor(origBlock.getCallSuccessor());
|
||||
}
|
||||
ControlFlowBlock result = this.copyBlock;
|
||||
this.origBlock = null;
|
||||
this.copyBlock = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an extra statement to the current block at the current generated position.
|
||||
* The new statement is added beofre the copy currently being generated.
|
||||
*
|
||||
* @param statement The statement to add
|
||||
*/
|
||||
protected void addStatementToCurrentBlock(Statement statement) {
|
||||
this.copyBlock.addStatement(statement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits the current block into two blocks in the generated graph.
|
||||
* The new block will have the current block as predecessor and current the block will have the new block as default successor.
|
||||
*
|
||||
* @param label The label to use for the new block
|
||||
* @return The new block.
|
||||
*/
|
||||
protected ControlFlowBlock splitCurrentBlock(Label label) {
|
||||
ControlFlowBlock newBlock = new ControlFlowBlock(label);
|
||||
this.copyBlock.setDefaultSuccessor(newBlock.getLabel());
|
||||
this.copyBlockMap.put(this.copyBlock.getLabel(), this.copyBlock);
|
||||
this.copyBlock = newBlock;
|
||||
return newBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the block currently being generated.
|
||||
*
|
||||
* @return The current block being generated into
|
||||
*/
|
||||
public ControlFlowBlock getCurrentBlock() {
|
||||
return copyBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement visitStatement(Statement statement) {
|
||||
return (Statement) super.visitStatement(statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementPhi visitPhi(StatementPhi phi) {
|
||||
VariableVersion lValue = phi.getLValue();
|
||||
StatementPhi copyPhi = new StatementPhi(lValue);
|
||||
for (StatementPhi.PreviousSymbol origPreviousVersion : phi.getPreviousVersions()) {
|
||||
RValue rValue = origPreviousVersion.getRValue();
|
||||
Label block = origPreviousVersion.getBlock();
|
||||
copyPhi.addPreviousVersion(block, rValue);
|
||||
}
|
||||
return copyPhi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementAssignment visitAssignment(StatementAssignment origAssignment) {
|
||||
LValue lValue = origAssignment.getLValue();
|
||||
RValue rValue1 = origAssignment.getRValue1();
|
||||
Operator operator = origAssignment.getOperator();
|
||||
RValue rValue2 = origAssignment.getRValue2();
|
||||
return new StatementAssignment(lValue, rValue1, operator, rValue2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementConditionalJump visitConditionalJump(StatementConditionalJump origConditionalJump) {
|
||||
RValue rValue1 = origConditionalJump.getRValue1();
|
||||
Operator operator = origConditionalJump.getOperator();
|
||||
RValue rValue2 = origConditionalJump.getRValue2();
|
||||
Label destination = origConditionalJump.getDestination();
|
||||
return new StatementConditionalJump(rValue1, operator, rValue2, destination);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementJump visitJump(StatementJump origJump) {
|
||||
Label destination = origJump.getDestination();
|
||||
return new StatementJump(destination);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementLabel visitJumpTarget(StatementLabel origJump) {
|
||||
Label label = origJump.getLabel();
|
||||
return new StatementLabel(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementCallLValue visitCallLValue(StatementCallLValue callLValue) {
|
||||
LValue lValue = callLValue.getLValue();
|
||||
String procedureName = callLValue.getProcedureName();
|
||||
List<RValue> parameters = callLValue.getParameters();
|
||||
return new StatementCallLValue(lValue, procedureName, parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementProcedureBegin visitProcedureBegin(StatementProcedureBegin origProcedureBegin) {
|
||||
return new StatementProcedureBegin(origProcedureBegin.getProcedure());
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementProcedureEnd visitProcedureEnd(StatementProcedureEnd origProcedureEnd) {
|
||||
return new StatementProcedureEnd(origProcedureEnd.getProcedure());
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementReturn visitReturn(StatementReturn origReturn) {
|
||||
return new StatementReturn(origReturn.getValue());
|
||||
}
|
||||
}
|
@ -28,15 +28,13 @@ public class Pass1GenerateControlFlowGraph {
|
||||
if(statement instanceof StatementLabel) {
|
||||
StatementLabel statementLabel = (StatementLabel) statement;
|
||||
ControlFlowBlock nextBlock = getOrCreateBlock(statementLabel.getLabel());
|
||||
currentBlock.setDefaultSuccessor(nextBlock);
|
||||
nextBlock.addPredecessor(currentBlock);
|
||||
currentBlock.setDefaultSuccessor(nextBlock.getLabel());
|
||||
blockStack.pop();
|
||||
blockStack.push(nextBlock);
|
||||
} else if(statement instanceof StatementJump) {
|
||||
StatementJump statementJump = (StatementJump) statement;
|
||||
ControlFlowBlock jmpBlock = getOrCreateBlock(statementJump.getDestination());
|
||||
currentBlock.setDefaultSuccessor(jmpBlock);
|
||||
jmpBlock.addPredecessor(currentBlock);
|
||||
currentBlock.setDefaultSuccessor(jmpBlock.getLabel());
|
||||
ControlFlowBlock nextBlock = getOrCreateBlock(scope.addLabelIntermediate());
|
||||
blockStack.pop();
|
||||
blockStack.push(nextBlock);
|
||||
@ -45,28 +43,30 @@ public class Pass1GenerateControlFlowGraph {
|
||||
StatementConditionalJump statementConditionalJump = (StatementConditionalJump) statement;
|
||||
ControlFlowBlock jmpBlock = getOrCreateBlock(statementConditionalJump.getDestination());
|
||||
ControlFlowBlock nextBlock = getOrCreateBlock(scope.addLabelIntermediate());
|
||||
currentBlock.setDefaultSuccessor(nextBlock);
|
||||
currentBlock.setConditionalSuccessor(jmpBlock);
|
||||
nextBlock.addPredecessor(currentBlock);
|
||||
jmpBlock.addPredecessor(currentBlock);
|
||||
currentBlock.setDefaultSuccessor(nextBlock.getLabel());
|
||||
currentBlock.setConditionalSuccessor(jmpBlock.getLabel());
|
||||
blockStack.pop();
|
||||
blockStack.push(nextBlock);
|
||||
} else if(statement instanceof StatementProcedureBegin) {
|
||||
// Procedure strategy implemented is currently variable-based transfer of parameters/return values
|
||||
StatementProcedureBegin procedure = (StatementProcedureBegin) statement;
|
||||
procedure.setStrategy(StatementProcedureBegin.Strategy.PASS_BY_REGISTER);
|
||||
Label procedureLabel = procedure.getProcedure().getLabel();
|
||||
StatementProcedureBegin procedureBegin = (StatementProcedureBegin) statement;
|
||||
procedureBegin.setStrategy(StatementProcedureBegin.Strategy.PASS_BY_REGISTER);
|
||||
Label procedureLabel = procedureBegin.getProcedure().getLabel();
|
||||
ControlFlowBlock procBlock = getOrCreateBlock(procedureLabel);
|
||||
blockStack.push(procBlock);
|
||||
} else if(statement instanceof StatementProcedureEnd) {
|
||||
// Procedure strategy implemented is currently variable-based transfer of parameters/return values
|
||||
currentBlock.setDefaultSuccessor(new ControlFlowBlock(new Label("@RETURN", scope, false)));
|
||||
currentBlock.setDefaultSuccessor(new Label("@RETURN", scope, false));
|
||||
ControlFlowBlock nextBlock = getOrCreateBlock(scope.addLabelIntermediate());
|
||||
blockStack.pop();
|
||||
ControlFlowBlock prevBlock = blockStack.pop();
|
||||
prevBlock.setDefaultSuccessor(nextBlock);
|
||||
nextBlock.addPredecessor(prevBlock);
|
||||
ControlFlowBlock prevBlock = blockStack.pop();
|
||||
prevBlock.setDefaultSuccessor(nextBlock.getLabel());
|
||||
blockStack.push(nextBlock);
|
||||
} else if(statement instanceof StatementReturn) {
|
||||
// Procedure strategy implemented is currently variable-based transfer of parameters/return values
|
||||
StatementReturn aReturn = (StatementReturn) statement;
|
||||
currentBlock.addStatement(aReturn);
|
||||
// TODO: Make all returns exit through the same exit-block!
|
||||
} else {
|
||||
currentBlock.addStatement(statement);
|
||||
}
|
||||
|
@ -28,7 +28,9 @@ public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
} while (!done);
|
||||
}
|
||||
|
||||
/** Version all non-versioned non-intermediary being assigned a value. */
|
||||
/**
|
||||
* Version all non-versioned non-intermediary being assigned a value.
|
||||
*/
|
||||
private void versionAllAssignments() {
|
||||
for (ControlFlowBlock block : controlFlowGraph.getAllBlocks()) {
|
||||
for (Statement statement : block.getStatements()) {
|
||||
@ -41,12 +43,23 @@ public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
VariableVersion version = symbols.createVersion(assignedSymbol);
|
||||
assignment.setLValue(version);
|
||||
}
|
||||
} else if(statement instanceof StatementCallLValue) {
|
||||
StatementCallLValue call = (StatementCallLValue) statement;
|
||||
LValue lValue = call.getLValue();
|
||||
if (lValue instanceof VariableUnversioned) {
|
||||
// Assignment to a non-versioned non-intermediary variable
|
||||
VariableUnversioned assignedSymbol = (VariableUnversioned) lValue;
|
||||
VariableVersion version = symbols.createVersion(assignedSymbol);
|
||||
call.setLValue(version);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Version all uses of non-versioned non-intermediary variables */
|
||||
/**
|
||||
* Version all uses of non-versioned non-intermediary variables
|
||||
*/
|
||||
private void versionAllUses() {
|
||||
for (ControlFlowBlock block : controlFlowGraph.getAllBlocks()) {
|
||||
// Newest version of variables in the block.
|
||||
@ -105,9 +118,10 @@ public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
/**
|
||||
* Find and return the latest version of an rValue (if it is a non-versioned symbol).
|
||||
* If a version is needed and no version is found a new version is created as a phi-function.
|
||||
* @param rValue The rValue to examine
|
||||
*
|
||||
* @param rValue The rValue to examine
|
||||
* @param blockVersions The current version defined in the block for each symbol.
|
||||
* @param blockNewPhis New versions to be created as phi-functions. Modified if a new phi-function needs to be created.
|
||||
* @param blockNewPhis New versions to be created as phi-functions. Modified if a new phi-function needs to be created.
|
||||
* @return Null if the rValue does not need versioning. The versioned symbol to use if it does.
|
||||
*/
|
||||
private VariableVersion findOrCreateVersion(
|
||||
@ -132,12 +146,14 @@ public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
return version;
|
||||
}
|
||||
|
||||
/** Look through all new phi-functions and fill out their parameters.
|
||||
/**
|
||||
* Look through all new phi-functions and fill out their parameters.
|
||||
*
|
||||
* @return true if all phis were completely filled out.
|
||||
* false if new phis were added, meaning another iteration is needed.
|
||||
* */
|
||||
*/
|
||||
private boolean completePhiFunctions() {
|
||||
Map<ControlFlowBlock, Map<VariableUnversioned, VariableVersion>> newPhis = new HashMap<>();
|
||||
Map<Label, Map<VariableUnversioned, VariableVersion>> newPhis = new HashMap<>();
|
||||
Map<Label, Map<VariableUnversioned, VariableVersion>> symbolMap = buildSymbolMap();
|
||||
for (ControlFlowBlock block : this.controlFlowGraph.getAllBlocks()) {
|
||||
for (Statement statement : block.getStatements()) {
|
||||
@ -146,35 +162,36 @@ public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
if (phi.getPreviousVersions().isEmpty()) {
|
||||
VariableVersion versioned = phi.getLValue();
|
||||
VariableUnversioned unversioned = versioned.getVersionOf();
|
||||
for (ControlFlowBlock predecessor : block.getPredecessors()) {
|
||||
Map<VariableUnversioned, VariableVersion> predecessorMap = symbolMap.get(predecessor.getLabel());
|
||||
for (ControlFlowBlock predecessor : controlFlowGraph.getPredecessors(block)) {
|
||||
Label predecessorLabel = predecessor.getLabel();
|
||||
Map<VariableUnversioned, VariableVersion> predecessorMap = symbolMap.get(predecessorLabel);
|
||||
VariableVersion previousSymbol = null;
|
||||
if (predecessorMap != null) {
|
||||
previousSymbol = predecessorMap.get(unversioned);
|
||||
}
|
||||
if (previousSymbol == null) {
|
||||
// No previous symbol found in predecessor block. Look in new phi functions.
|
||||
Map<VariableUnversioned, VariableVersion> predecessorNewPhis = newPhis.get(predecessor);
|
||||
if (predecessorNewPhis == null) {
|
||||
predecessorNewPhis = new HashMap<>();
|
||||
newPhis.put(predecessor, predecessorNewPhis);
|
||||
}
|
||||
previousSymbol = predecessorNewPhis.get(unversioned);
|
||||
if (previousSymbol == null) {
|
||||
// No previous symbol found in predecessor block. Add a new phi function to the predecessor.
|
||||
previousSymbol = symbols.createVersion(unversioned);
|
||||
predecessorNewPhis.put(unversioned, previousSymbol);
|
||||
}
|
||||
if (previousSymbol == null) {
|
||||
// No previous symbol found in predecessor block. Look in new phi functions.
|
||||
Map<VariableUnversioned, VariableVersion> predecessorNewPhis = newPhis.get(predecessorLabel);
|
||||
if (predecessorNewPhis == null) {
|
||||
predecessorNewPhis = new HashMap<>();
|
||||
newPhis.put(predecessorLabel, predecessorNewPhis);
|
||||
}
|
||||
previousSymbol = predecessorNewPhis.get(unversioned);
|
||||
if (previousSymbol == null) {
|
||||
// No previous symbol found in predecessor block. Add a new phi function to the predecessor.
|
||||
previousSymbol = symbols.createVersion(unversioned);
|
||||
predecessorNewPhis.put(unversioned, previousSymbol);
|
||||
}
|
||||
phi.addPreviousVersion(predecessor, previousSymbol);
|
||||
}
|
||||
phi.addPreviousVersion(predecessorLabel, previousSymbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ads new phi functions to blocks
|
||||
for (ControlFlowBlock block : controlFlowGraph.getAllBlocks()) {
|
||||
Map<VariableUnversioned, VariableVersion> blockNewPhis = newPhis.get(block);
|
||||
Map<VariableUnversioned, VariableVersion> blockNewPhis = newPhis.get(block.getLabel());
|
||||
if (blockNewPhis != null) {
|
||||
for (VariableUnversioned symbol : blockNewPhis.keySet()) {
|
||||
block.addPhiStatement(blockNewPhis.get(symbol));
|
||||
@ -217,6 +234,21 @@ public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
symbolMap.put(label, blockMap);
|
||||
}
|
||||
blockMap.put(unversioned, versioned);
|
||||
} else if (statement instanceof StatementCallLValue) {
|
||||
StatementCallLValue call = (StatementCallLValue) statement;
|
||||
LValue lValue = call.getLValue();
|
||||
if (lValue instanceof VariableVersion) {
|
||||
VariableVersion versioned = (VariableVersion) lValue;
|
||||
Label label = block.getLabel();
|
||||
VariableUnversioned unversioned = versioned.getVersionOf();
|
||||
Map<VariableUnversioned, VariableVersion> blockMap = symbolMap.get(label);
|
||||
if (blockMap == null) {
|
||||
blockMap = new HashMap<>();
|
||||
symbolMap.put(label, blockMap);
|
||||
}
|
||||
blockMap.put(unversioned, versioned);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
46
src/dk/camelot64/kickc/icl/Pass1ProcedureCallParameters.java
Normal file
46
src/dk/camelot64/kickc/icl/Pass1ProcedureCallParameters.java
Normal file
@ -0,0 +1,46 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** Pass that modifies a control flow graph to call procedures by passing parameters through registers */
|
||||
public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
|
||||
|
||||
private Scope scope;
|
||||
private ControlFlowGraph graph;
|
||||
|
||||
public Pass1ProcedureCallParameters(Scope scope, ControlFlowGraph graph ) {
|
||||
this.scope = scope;
|
||||
this.graph= graph;
|
||||
}
|
||||
|
||||
public ControlFlowGraph generate() {
|
||||
ControlFlowGraph generated = visitGraph(graph);
|
||||
return generated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementCallLValue visitCallLValue(StatementCallLValue origCall) {
|
||||
// Procedure strategy implemented is currently variable-based transfer of parameters/return values
|
||||
// Generate parameter passing assignments
|
||||
Procedure procedure = origCall.getProcedure();
|
||||
List<Variable> parameterDecls = procedure.getParameters();
|
||||
List<RValue> parameterValues = origCall.getParameters();
|
||||
for (int i = 0; i < parameterDecls.size(); i++) {
|
||||
Variable parameterDecl = parameterDecls.get(i);
|
||||
RValue parameterValue = parameterValues.get(i);
|
||||
addStatementToCurrentBlock(new StatementAssignment(parameterDecl, parameterValue));
|
||||
}
|
||||
String procedureName = origCall.getProcedureName();
|
||||
Variable procReturnVar = procedure.getVariable("return");
|
||||
StatementCallLValue copyCall = new StatementCallLValue(procReturnVar, procedureName, null);
|
||||
copyCall.setParametersByAssignment(true);
|
||||
copyCall.setProcedure(procedure);
|
||||
addStatementToCurrentBlock(copyCall);
|
||||
getCurrentBlock().setCallSuccessor(procedure.getLabel());
|
||||
splitCurrentBlock(scope.addLabelIntermediate());
|
||||
addStatementToCurrentBlock(new StatementAssignment(origCall.getLValue(), procReturnVar));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
/** Pass that modifies a control flow graph to call procedures by passing return value through registers */
|
||||
public class Pass1ProcedureCallsReturnValue extends ControlFlowGraphCopyVisitor {
|
||||
|
||||
private Scope scope;
|
||||
private ControlFlowGraph graph;
|
||||
|
||||
public Pass1ProcedureCallsReturnValue(Scope scope, ControlFlowGraph graph ) {
|
||||
this.scope = scope;
|
||||
this.graph= graph;
|
||||
}
|
||||
|
||||
public ControlFlowGraph generate() {
|
||||
ControlFlowGraph generated = visitGraph(graph);
|
||||
return generated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementCallLValue visitCallLValue(StatementCallLValue origCall) {
|
||||
// Procedure strategy implemented is currently variable-based transfer of parameters/return values
|
||||
// Generate return value assignment
|
||||
Procedure procedure = origCall.getProcedure();
|
||||
|
||||
String procedureName = origCall.getProcedureName();
|
||||
StatementCallLValue copyCall = new StatementCallLValue(null, procedureName, null);
|
||||
copyCall.setParametersByAssignment(true);
|
||||
copyCall.setProcedure(procedure);
|
||||
addStatementToCurrentBlock(copyCall);
|
||||
getCurrentBlock().setCallSuccessor(procedure.getLabel());
|
||||
|
||||
//StatementAssignment returnAssignment = new StatementAssignment();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -47,6 +47,9 @@ public class Pass1TypeInference {
|
||||
String procedureName = call.getProcedureName();
|
||||
Procedure procedure = scopes.peek().getProcedure(procedureName);
|
||||
call.setProcedure(procedure);
|
||||
if(procedure.getParameters().size()!=call.getParameters().size()) {
|
||||
throw new RuntimeException("Wrong number of parameters in call. Expected " +procedure.getParameters().size()+". "+statement.toString());
|
||||
}
|
||||
((Variable) lValue).setInferredType(procedure.getReturnType());
|
||||
}
|
||||
}
|
||||
|
@ -18,29 +18,23 @@ public class Pass2CullEmptyBlocks extends Pass2SsaOptimization {
|
||||
remove.add(block);
|
||||
}
|
||||
}
|
||||
for (ControlFlowBlock block : remove) {
|
||||
ControlFlowBlock successor = block.getDefaultSuccessor();
|
||||
for (ControlFlowBlock predecessor : block.getPredecessors()) {
|
||||
replace.put(block.getLabel(), predecessor.getLabel());
|
||||
if (block.equals(predecessor.getDefaultSuccessor())) {
|
||||
predecessor.setDefaultSuccessor(successor);
|
||||
if (successor != null) {
|
||||
successor.addPredecessor(predecessor);
|
||||
}
|
||||
for (ControlFlowBlock removeBlock : remove) {
|
||||
ControlFlowBlock successor = getGraph().getDefaultSuccessor(removeBlock);
|
||||
for (ControlFlowBlock predecessor : getGraph().getPredecessors(removeBlock)) {
|
||||
replace.put(removeBlock.getLabel(), predecessor.getLabel());
|
||||
if (removeBlock.getLabel().equals(predecessor.getDefaultSuccessor())) {
|
||||
predecessor.setDefaultSuccessor(successor.getLabel());
|
||||
}
|
||||
if (block.equals(predecessor.getConditionalSuccessor())) {
|
||||
predecessor.setConditionalSuccessor(successor);
|
||||
if (successor != null) {
|
||||
successor.addPredecessor(predecessor);
|
||||
}
|
||||
if (removeBlock.getLabel().equals(predecessor.getConditionalSuccessor())) {
|
||||
predecessor.setConditionalSuccessor(successor.getLabel());
|
||||
}
|
||||
if (removeBlock.getLabel().equals(predecessor.getCallSuccessor())) {
|
||||
predecessor.setCallSuccessor(successor.getLabel());
|
||||
}
|
||||
}
|
||||
if (successor != null && block.getLabel().isIntermediate()) {
|
||||
successor.removePredecessor(block);
|
||||
}
|
||||
getGraph().getAllBlocks().remove(block);
|
||||
getSymbols().remove(block.getLabel());
|
||||
System.out.println("Culled Empty Block " + block.getLabel());
|
||||
getGraph().getAllBlocks().remove(removeBlock);
|
||||
getSymbols().remove(removeBlock.getLabel());
|
||||
System.out.println("Culled Empty Block " + removeBlock.getLabel());
|
||||
}
|
||||
replaceLabels(replace);
|
||||
return remove.size()>0;
|
||||
|
@ -168,9 +168,9 @@ public abstract class Pass2SsaOptimization {
|
||||
@Override
|
||||
public Void visitPhi(StatementPhi phi) {
|
||||
for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) {
|
||||
Label replacement = getReplacement(replacements, previousSymbol.getBlock().getLabel());
|
||||
Label replacement = getReplacement(replacements, previousSymbol.getBlock());
|
||||
if (replacement != null) {
|
||||
previousSymbol.setBlock(graph.getBlock(replacement));
|
||||
previousSymbol.setBlock(replacement);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -27,7 +27,7 @@ public class Pass3CodeGeneration {
|
||||
// Generate statements
|
||||
genStatements(asm, block);
|
||||
// Generate exit
|
||||
ControlFlowBlock defaultSuccessor = block.getDefaultSuccessor();
|
||||
ControlFlowBlock defaultSuccessor = graph.getDefaultSuccessor(block);
|
||||
if (defaultSuccessor != null) {
|
||||
if (defaultSuccessor.hasPhiStatements()) {
|
||||
genBlockPhiTransition(asm, block, defaultSuccessor);
|
||||
@ -81,8 +81,8 @@ public class Pass3CodeGeneration {
|
||||
|
||||
private void genBlockEntryPoints(AsmProgram asm, ControlFlowBlock block) {
|
||||
if (block.hasPhiStatements()) {
|
||||
for (ControlFlowBlock predecessor : block.getPredecessors()) {
|
||||
if (block.equals(predecessor.getConditionalSuccessor())) {
|
||||
for (ControlFlowBlock predecessor : graph.getPredecessors(block)) {
|
||||
if (block.getLabel().equals(predecessor.getConditionalSuccessor())) {
|
||||
genBlockPhiTransition(asm, predecessor, block);
|
||||
asm.addInstruction("JMP", AsmAddressingMode.ABS, block.getLabel().getLocalName().replace('@', 'B'));
|
||||
}
|
||||
|
@ -125,6 +125,7 @@ public class Scope implements Symbol {
|
||||
}
|
||||
Procedure procedure = new Procedure(name, type, this);
|
||||
add(procedure);
|
||||
procedure.addVariable("return", type);
|
||||
return procedure;
|
||||
}
|
||||
|
||||
|
@ -14,11 +14,13 @@ public class StatementCallLValue implements StatementLValue {
|
||||
private String procedureName;
|
||||
private List<RValue> parameters;
|
||||
private Procedure procedure;
|
||||
private boolean parametersByAssignment;
|
||||
|
||||
public StatementCallLValue(LValue lValue, String procedureName, List<RValue> parameters) {
|
||||
this.lValue = lValue;
|
||||
this.procedureName = procedureName;
|
||||
this.parameters = parameters;
|
||||
this.parametersByAssignment = false;
|
||||
}
|
||||
|
||||
public LValue getLValue() {
|
||||
@ -53,6 +55,14 @@ public class StatementCallLValue implements StatementLValue {
|
||||
return parameters.get(idx);
|
||||
}
|
||||
|
||||
public boolean isParametersByAssignment() {
|
||||
return parametersByAssignment;
|
||||
}
|
||||
|
||||
public void setParametersByAssignment(boolean parametersByAssignment) {
|
||||
this.parametersByAssignment = parametersByAssignment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder res = new StringBuilder();
|
||||
@ -64,10 +74,20 @@ public class StatementCallLValue implements StatementLValue {
|
||||
} else {
|
||||
res.append(procedureName + " ");
|
||||
}
|
||||
for (RValue parameter : parameters) {
|
||||
res.append(parameter+" ");
|
||||
if(parameters!=null) {
|
||||
for (RValue parameter : parameters) {
|
||||
res.append(parameter + " ");
|
||||
}
|
||||
}
|
||||
if(parametersByAssignment) {
|
||||
res.append("param-assignment");
|
||||
}
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
public void clearParameters() {
|
||||
this.parameters = null;
|
||||
this.parametersByAssignment = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,15 +27,15 @@ public class StatementPhi implements StatementLValue {
|
||||
* Which value is chosen depends on which block transition was made.
|
||||
*/
|
||||
public static class PreviousSymbol {
|
||||
private ControlFlowBlock block;
|
||||
private Label block;
|
||||
private RValue rValue;
|
||||
|
||||
public PreviousSymbol(ControlFlowBlock block, RValue rValue) {
|
||||
public PreviousSymbol(Label block, RValue rValue) {
|
||||
this.block = block;
|
||||
this.rValue = rValue;
|
||||
}
|
||||
|
||||
public ControlFlowBlock getBlock() {
|
||||
public Label getBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
@ -43,12 +43,11 @@ public class StatementPhi implements StatementLValue {
|
||||
return rValue;
|
||||
}
|
||||
|
||||
|
||||
public void setRValue(RValue RValue) {
|
||||
this.rValue = RValue;
|
||||
}
|
||||
|
||||
public void setBlock(ControlFlowBlock block) {
|
||||
public void setBlock(Label block) {
|
||||
this.block = block;
|
||||
}
|
||||
}
|
||||
@ -65,8 +64,8 @@ public class StatementPhi implements StatementLValue {
|
||||
this.lValue = (VariableVersion) lValue;
|
||||
}
|
||||
|
||||
public void addPreviousVersion(ControlFlowBlock block, VariableVersion symbol) {
|
||||
previousVersions.add(new PreviousSymbol(block, symbol));
|
||||
public void addPreviousVersion(Label block, RValue rValue) {
|
||||
previousVersions.add(new PreviousSymbol(block, rValue));
|
||||
}
|
||||
|
||||
public List<PreviousSymbol> getPreviousVersions() {
|
||||
@ -78,7 +77,7 @@ public class StatementPhi implements StatementLValue {
|
||||
StringBuilder out = new StringBuilder();
|
||||
out.append(lValue + " ← " + "phi(");
|
||||
for (PreviousSymbol previousSymbol : previousVersions) {
|
||||
out.append(" "+previousSymbol.getBlock().getLabel().getLocalName()+"/"+previousSymbol.getRValue());
|
||||
out.append(" "+previousSymbol.getBlock().getLocalName()+"/"+previousSymbol.getRValue());
|
||||
}
|
||||
out.append(" )");
|
||||
return out.toString();
|
||||
|
@ -42,15 +42,25 @@ public class Main {
|
||||
System.out.println("INITIAL CONTROL FLOW GRAPH");
|
||||
System.out.println(controlFlowGraph.toString());
|
||||
|
||||
|
||||
|
||||
|
||||
if(1==1) return;
|
||||
Pass1ProcedureCallParameters pass1ProcedureCallParameters = new Pass1ProcedureCallParameters(programScope, controlFlowGraph);
|
||||
controlFlowGraph = pass1ProcedureCallParameters.generate();
|
||||
System.out.println("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL");
|
||||
System.out.println(controlFlowGraph.toString());
|
||||
|
||||
Pass1GenerateSingleStaticAssignmentForm pass1GenerateSingleStaticAssignmentForm =
|
||||
new Pass1GenerateSingleStaticAssignmentForm(programScope, controlFlowGraph);
|
||||
pass1GenerateSingleStaticAssignmentForm.generate();
|
||||
|
||||
System.out.println("CONTROL FLOW GRAPH SSA");
|
||||
System.out.println(controlFlowGraph.toString());
|
||||
|
||||
//Pass1ProcedureCallsReturnValue pass1ProcedureCallsReturnValue = new Pass1ProcedureCallsReturnValue(programScope, controlFlowGraph);
|
||||
//controlFlowGraph = pass1ProcedureCallsReturnValue.generate();
|
||||
//System.out.println("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN");
|
||||
//System.out.println(controlFlowGraph.toString());
|
||||
|
||||
if(1==1) return;
|
||||
|
||||
List<Pass2SsaOptimization> optimizations = new ArrayList<>();
|
||||
optimizations.add(new Pass2CullEmptyBlocks(controlFlowGraph, programScope));
|
||||
optimizations.add(new Pass2ConstantPropagation(controlFlowGraph, programScope));
|
||||
|
Loading…
x
Reference in New Issue
Block a user