1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-08-02 09:29:35 +00:00

Changed control flow graph block collection to a modifiable list.

This commit is contained in:
jespergravgaard 2018-04-29 22:34:26 +02:00
parent 3879ac83b0
commit b15a88f27e
6 changed files with 175 additions and 41 deletions

View File

@ -140,6 +140,8 @@ public class Compiler {
new Pass1ModifiedVarsAnalysis(program).execute();
getLog().append(program.getProcedureModifiedVars().toString(program));
new Pass1ProcedureInline(program).execute();
new Pass1ProcedureCallParameters(program).generate();
//getLog().append("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL");
//getLog().append(program.getGraph().toString(program));

View File

@ -15,7 +15,7 @@ import java.util.*;
*/
public class ControlFlowGraph {
private Map<LabelRef, ControlFlowBlock> blocks;
private List<ControlFlowBlock> blocks;
private LabelRef firstBlockRef;
/**
@ -23,37 +23,41 @@ public class ControlFlowGraph {
*/
private List<LabelRef> sequence;
public ControlFlowGraph(Map<LabelRef, ControlFlowBlock> blocks, LabelRef firstBlockRef) {
public ControlFlowGraph(List<ControlFlowBlock> blocks, LabelRef firstBlockRef) {
this.blocks = blocks;
this.firstBlockRef = firstBlockRef;
}
public ControlFlowBlock getBlock(LabelRef symbol) {
return blocks.get(symbol);
for(ControlFlowBlock block : blocks) {
if(block.getLabel().equals(symbol)) {
return block;
}
}
return null;
}
public void addBlock(ControlFlowBlock block) {
blocks.put(block.getLabel(), block);
blocks.add(block);
}
public ControlFlowBlock getFirstBlock() {
return getBlock(firstBlockRef);
}
public Collection<ControlFlowBlock> getAllBlocks() {
if(sequence != null) {
ArrayList<ControlFlowBlock> blocks = new ArrayList<>();
for(LabelRef labelRef : sequence) {
blocks.add(getBlock(labelRef));
}
public List<ControlFlowBlock> getAllBlocks() {
return blocks;
} else {
return blocks.values();
}
}
public void remove(LabelRef label) {
blocks.remove(label);
ListIterator<ControlFlowBlock> blocksIt = blocks.listIterator();
while(blocksIt.hasNext()) {
ControlFlowBlock block = blocksIt.next();
if(block.getLabel().equals(label)) {
blocksIt.remove();
return;
}
}
}
/**
@ -105,7 +109,7 @@ public class ControlFlowGraph {
public ControlFlowBlock getDefaultSuccessor(ControlFlowBlock block) {
if(block.getDefaultSuccessor() != null) {
return blocks.get(block.getDefaultSuccessor());
return getBlock(block.getDefaultSuccessor());
} else {
return null;
}
@ -113,7 +117,7 @@ public class ControlFlowGraph {
public ControlFlowBlock getCallSuccessor(ControlFlowBlock block) {
if(block.getCallSuccessor() != null) {
return blocks.get(block.getCallSuccessor());
return getBlock(block.getCallSuccessor());
} else {
return null;
}
@ -121,7 +125,7 @@ public class ControlFlowGraph {
public ControlFlowBlock getConditionalSuccessor(ControlFlowBlock block) {
if(block.getConditionalSuccessor() != null) {
return blocks.get(block.getConditionalSuccessor());
return getBlock(block.getConditionalSuccessor());
} else {
return null;
}
@ -150,7 +154,15 @@ public class ControlFlowGraph {
}
public void setSequence(List<LabelRef> sequence) {
if(sequence.size()!=blocks.size()) {
throw new CompileError("ERROR! Sequence does not contain all blocks from the program. Sequence: "+sequence.size()+" Blocks: "+blocks.size());
}
this.sequence = sequence;
ArrayList<ControlFlowBlock> seqBlocks = new ArrayList<>();
for(LabelRef labelRef : sequence) {
seqBlocks.add(getBlock(labelRef));
}
this.blocks = seqBlocks;
}
public ControlFlowBlock getMainBlock() {

View File

@ -1,13 +1,13 @@
package dk.camelot64.kickc.model;
import dk.camelot64.kickc.model.operators.Operator;
import dk.camelot64.kickc.model.statements.*;
import dk.camelot64.kickc.model.values.LValue;
import dk.camelot64.kickc.model.values.LabelRef;
import dk.camelot64.kickc.model.values.RValue;
import dk.camelot64.kickc.model.values.VariableRef;
import dk.camelot64.kickc.model.statements.*;
import java.util.LinkedHashMap;
import java.util.ArrayList;
import java.util.List;
/**
@ -23,7 +23,7 @@ public class ControlFlowGraphCopyVisitor extends ControlFlowGraphBaseVisitor<Obj
/**
* The copied blocks.
*/
private LinkedHashMap<LabelRef, ControlFlowBlock> copyBlockMap;
private List<ControlFlowBlock> copyBlockList;
/**
* The current block being copied.
@ -39,15 +39,14 @@ public class ControlFlowGraphCopyVisitor extends ControlFlowGraphBaseVisitor<Obj
public ControlFlowGraph visitGraph(ControlFlowGraph origGraph) {
this.origGraph = origGraph;
// Copy all blocks
this.copyBlockMap = new LinkedHashMap<>();
this.copyBlockList = new ArrayList<>();
for(ControlFlowBlock origBlock : origGraph.getAllBlocks()) {
ControlFlowBlock copyBlock = visitBlock(origBlock);
if(copyBlock != null) {
copyBlockMap.put(copyBlock.getLabel(), copyBlock);
copyBlockList.add(copyBlock);
}
}
ControlFlowBlock copyFirstBlock = copyBlockMap.get(origGraph.getFirstBlock().getLabel());
ControlFlowGraph copyGraph = new ControlFlowGraph(copyBlockMap, copyFirstBlock.getLabel());
ControlFlowGraph copyGraph = new ControlFlowGraph(copyBlockList, origGraph.getFirstBlock().getLabel());
return copyGraph;
}
@ -101,7 +100,7 @@ public class ControlFlowGraphCopyVisitor extends ControlFlowGraphBaseVisitor<Obj
protected ControlFlowBlock splitCurrentBlock(LabelRef label) {
ControlFlowBlock newBlock = new ControlFlowBlock(label, origBlock.getScope());
this.copyBlock.setDefaultSuccessor(newBlock.getLabel());
this.copyBlockMap.put(this.copyBlock.getLabel(), this.copyBlock);
this.copyBlockList.add(this.copyBlock);
this.copyBlock = newBlock;
return newBlock;
}

View File

@ -1,6 +1,9 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.ControlFlowGraph;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.StatementSequence;
import dk.camelot64.kickc.model.statements.*;
import dk.camelot64.kickc.model.symbols.*;
import dk.camelot64.kickc.model.values.LabelRef;
@ -8,14 +11,14 @@ import dk.camelot64.kickc.model.values.ProcedureRef;
import dk.camelot64.kickc.model.values.ScopeRef;
import dk.camelot64.kickc.model.values.SymbolRef;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/** Pass that generates a control flow graph for the program */
public class Pass1GenerateControlFlowGraph extends Pass1Base {
private Map<LabelRef, ControlFlowBlock> blocks;
private List<ControlFlowBlock> blocks;
public Pass1GenerateControlFlowGraph(Program program) {
super(program);
@ -23,7 +26,7 @@ public class Pass1GenerateControlFlowGraph extends Pass1Base {
@Override
public boolean step() {
this.blocks = new LinkedHashMap<>();
this.blocks = new ArrayList<>();
ProgramScope scope = getScope();
StatementSequence sequence = getProgram().getStatementSequence();
ControlFlowBlock firstBlock = getOrCreateBlock(scope.addLabel(SymbolRef.BEGIN_BLOCK_NAME).getRef(), ScopeRef.ROOT);
@ -92,11 +95,13 @@ public class Pass1GenerateControlFlowGraph extends Pass1Base {
}
private ControlFlowBlock getOrCreateBlock(LabelRef label, ScopeRef scope) {
ControlFlowBlock block = blocks.get(label);
if(block == null) {
block = new ControlFlowBlock(label, scope);
blocks.put(block.getLabel(), block);
for(ControlFlowBlock block : blocks) {
if(block.getLabel().equals(label)) {
return block;
}
}
ControlFlowBlock block = new ControlFlowBlock(label, scope);
blocks.add(block);
return block;
}

View File

@ -0,0 +1,117 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.*;
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.SymbolType;
import dk.camelot64.kickc.model.values.LValue;
import dk.camelot64.kickc.model.values.ProcedureRef;
import dk.camelot64.kickc.model.values.RValue;
import dk.camelot64.kickc.model.values.VariableRef;
import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
/** Pass that modifies a control flow graph to inline any procedures declared as inline */
public class Pass1ProcedureInline extends Pass1Base {
public Pass1ProcedureInline(Program program) {
super(program);
}
@Override
public boolean step() {
List<ControlFlowBlock> allBlocks = getGraph().getAllBlocks();
for(ControlFlowBlock block : allBlocks) {
List<Statement> blockStatements = block.getStatements();
ListIterator<Statement> statementsIt = blockStatements.listIterator();
while(statementsIt.hasNext()) {
Statement statement = statementsIt.next();
if(statement instanceof StatementCall) {
StatementCall call = (StatementCall) statement;
ProcedureRef procedureRef = call.getProcedure();
Procedure procedure = getScope().getProcedure(procedureRef);
if(procedure.isDeclaredInline()) {
// Generate parameter assignments
// Copy all procedure blocks
// Generate return assignment
throw new CompileError("Inline functions not implemented!");
}
}
}
}
return false;
}
/*
public StatementCall visitCall(StatementCall origCall) {
// Procedure strategy implemented is currently variable-based transfer of parameters/return values
// Generate parameter passing assignments
ProcedureRef procedureRef = origCall.getProcedure();
Procedure procedure = getScope().getProcedure(procedureRef);
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.getRef(), parameterValue));
}
String procedureName = origCall.getProcedureName();
Variable procReturnVar = procedure.getVariable("return");
VariableRef procReturnVarRef = null;
if(procReturnVar != null) {
procReturnVarRef = procReturnVar.getRef();
}
StatementCall copyCall = new StatementCall(procReturnVarRef, procedureName, null);
copyCall.setParametersByAssignment(true);
copyCall.setProcedure(procedureRef);
addStatementToCurrentBlock(copyCall);
getCurrentBlock().setCallSuccessor(procedure.getLabel().getRef());
Symbol currentBlockSymbol = getScope().getSymbol(getCurrentBlock().getLabel());
Scope currentBlockScope;
if(currentBlockSymbol instanceof Procedure) {
currentBlockScope = (Scope) currentBlockSymbol;
} else {
currentBlockScope = currentBlockSymbol.getScope();
}
splitCurrentBlock(currentBlockScope.addLabelIntermediate().getRef());
if(!SymbolType.VOID.equals(procedure.getReturnType()) && origCall.getlValue() != null) {
addStatementToCurrentBlock(new StatementAssignment(origCall.getlValue(), procReturnVarRef));
} else {
// No return type. Remove variable receiving the result.
LValue lValue = origCall.getlValue();
if(lValue instanceof VariableRef) {
VariableRef lValueRef = (VariableRef) lValue;
Variable lValueVar = getScope().getVariable(lValueRef);
lValueVar.getScope().remove(lValueVar);
}
}
// Add self-assignments for all variables modified in the procedure
Set<VariableRef> modifiedVars = program.getProcedureModifiedVars().getModifiedVars(procedure.getRef());
for(VariableRef modifiedVar : modifiedVars) {
addStatementToCurrentBlock(new StatementAssignment(modifiedVar, modifiedVar));
}
return null;
}
@Override
public StatementReturn visitReturn(StatementReturn origReturn) {
ControlFlowBlock currentBlock = getCurrentBlock();
String currentProcName = currentBlock.getLabel().getScopeNames();
Procedure procedure = program.getScope().getProcedure(currentProcName);
// Add self-assignments for all variables modified in the procedure
Set<VariableRef> modifiedVars = program.getProcedureModifiedVars().getModifiedVars(procedure.getRef());
for(VariableRef modifiedVar : modifiedVars) {
addStatementToCurrentBlock(new StatementAssignment(modifiedVar, modifiedVar));
}
return super.visitReturn(origReturn);
}
*/
}

View File

@ -9,10 +9,7 @@ import dk.camelot64.kickc.model.statements.StatementPhiBlock;
import dk.camelot64.kickc.model.symbols.*;
import dk.camelot64.kickc.model.values.LabelRef;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* Perform PhiLifting to greatly reduce overlapping of alive intervals for variables.
@ -35,8 +32,10 @@ public class Pass3PhiLifting {
public void perform() {
ControlFlowGraph graph = program.getGraph();
ProgramScope programScope = program.getScope();
Collection<ControlFlowBlock> blocks = graph.getAllBlocks();
for(ControlFlowBlock block : blocks) {
List<ControlFlowBlock> blocks = graph.getAllBlocks();
ListIterator<ControlFlowBlock> blocksIt = blocks.listIterator();
while(blocksIt.hasNext()) {
ControlFlowBlock block = blocksIt.next();
// Maps old predecessors to new blocks created
Map<LabelRef, LabelRef> newBlocks = new HashMap<>();
if(block.hasPhiBlock()) {
@ -73,7 +72,7 @@ public class Pass3PhiLifting {
Scope currentScope = programScope.getSymbol(currentBlockLabel).getScope();
Label newBlockLabel = currentScope.addLabelIntermediate();
newBlock = new ControlFlowBlock(newBlockLabel.getRef(), currentScope.getRef());
graph.addBlock(newBlock);
blocksIt.add(newBlock);
newBlock.setDefaultSuccessor(block.getLabel());
newBlocks.put(predecessorRef, newBlock.getLabel());
StatementConditionalJump previousConditionalJump = (StatementConditionalJump) lastPredecessorStatement;