mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-01 00:51:12 +00:00
#815 working on moving control flow graphs into procedure compilation.
This commit is contained in:
parent
5905c1d5b6
commit
1fad48f8bc
@ -11,19 +11,19 @@ import java.util.*;
|
||||
*/
|
||||
public class ControlFlowGraph implements Graph {
|
||||
|
||||
private List<ControlFlowBlock> blocks;
|
||||
private List<Graph.Block> blocks;
|
||||
|
||||
/**
|
||||
* Sequence of blocks used when generating ASM
|
||||
*/
|
||||
private List<LabelRef> sequence;
|
||||
|
||||
public ControlFlowGraph(List<ControlFlowBlock> blocks) {
|
||||
public ControlFlowGraph(List<Graph.Block> blocks) {
|
||||
this.blocks = blocks;
|
||||
}
|
||||
|
||||
public ControlFlowBlock getBlock(LabelRef symbol) {
|
||||
for(ControlFlowBlock block : blocks) {
|
||||
public Graph.Block getBlock(LabelRef symbol) {
|
||||
for(var block : blocks) {
|
||||
if(block.getLabel().equals(symbol)) {
|
||||
return block;
|
||||
}
|
||||
@ -31,7 +31,7 @@ public class ControlFlowGraph implements Graph {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addBlock(ControlFlowBlock block) {
|
||||
public void addBlock(Graph.Block block) {
|
||||
blocks.add(block);
|
||||
}
|
||||
|
||||
@ -39,14 +39,10 @@ public class ControlFlowGraph implements Graph {
|
||||
return Collections.unmodifiableList(blocks);
|
||||
}
|
||||
|
||||
public void setAllBlocks(List<ControlFlowBlock> blocks) {
|
||||
this.blocks = blocks;
|
||||
}
|
||||
|
||||
public void remove(LabelRef label) {
|
||||
ListIterator<ControlFlowBlock> blocksIt = blocks.listIterator();
|
||||
ListIterator<Graph.Block> blocksIt = blocks.listIterator();
|
||||
while(blocksIt.hasNext()) {
|
||||
ControlFlowBlock block = blocksIt.next();
|
||||
var block = blocksIt.next();
|
||||
if(block.getLabel().equals(label)) {
|
||||
blocksIt.remove();
|
||||
return;
|
||||
@ -54,23 +50,6 @@ public class ControlFlowGraph implements Graph {
|
||||
}
|
||||
}
|
||||
|
||||
public List<LabelRef> getSequence() {
|
||||
return sequence;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(null);
|
||||
@ -95,7 +74,7 @@ public class ControlFlowGraph implements Graph {
|
||||
* Clear all statement indices,
|
||||
*/
|
||||
public void clearStatementIndices() {
|
||||
for(Graph.Block block : getAllBlocks()) {
|
||||
for(var block : getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
statement.setIndex(null);
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ public interface Graph {
|
||||
|
||||
List<Block> getAllBlocks();
|
||||
|
||||
void addBlock(Graph.Block block);
|
||||
|
||||
default List<Graph.Block> getPredecessors(Graph.Block block) {
|
||||
ArrayList<Block> predecessorBlocks = new ArrayList<>();
|
||||
for(Graph.Block other : getAllBlocks()) {
|
||||
|
@ -4,7 +4,6 @@ import dk.camelot64.kickc.CompileLog;
|
||||
import dk.camelot64.kickc.OutputFileManager;
|
||||
import dk.camelot64.kickc.asm.AsmProgram;
|
||||
import dk.camelot64.kickc.fragment.synthesis.AsmFragmentTemplateMasterSynthesizer;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
|
||||
import dk.camelot64.kickc.model.symbols.*;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
@ -158,12 +157,17 @@ public class Program {
|
||||
|
||||
@Override
|
||||
public List<Block> getAllBlocks() {
|
||||
return getProcedureCompilations().stream().map(ProcedureCompilation::getGraph).map(ControlFlowGraph::getAllBlocks).flatMap(Collection::stream).collect(Collectors.toList());
|
||||
return getProcedureCompilations().stream().map(ProcedureCompilation::getGraph).map(ControlFlowGraph::getAllBlocks).flatMap(Collection::stream).collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBlock(Block block) {
|
||||
throw new CompileError("Internal Error! Cannot add blocks to the read-only total control flow graph!");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Collection<ProcedureCompilation> getProcedureCompilations() {
|
||||
public Collection<ProcedureCompilation> getProcedureCompilations() {
|
||||
return procedureCompilations.values();
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,19 @@ public abstract class Scope implements Symbol {
|
||||
setFullName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the containing procedure.
|
||||
* @return The procedure containing the scope. Null if the scope is not contained in a procedure.
|
||||
*/
|
||||
public Procedure getProcedure() {
|
||||
if(this instanceof Procedure)
|
||||
return (Procedure) this;
|
||||
else if(this instanceof ProgramScope)
|
||||
return null;
|
||||
else
|
||||
return this.getScope().getProcedure();
|
||||
}
|
||||
|
||||
private void setFullName() {
|
||||
String scopeName = (parentScope == null) ? "" : parentScope.getFullName();
|
||||
fullName = (scopeName.length() > 0) ? scopeName + "::" + name : name;
|
||||
|
@ -1,9 +1,6 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.ProcedureCompilation;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.symbols.Label;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
|
||||
@ -29,7 +26,7 @@ public class Pass1AssertProcedureDefined extends Pass1Base {
|
||||
final ProcedureCompilation procedureCompilation = getProgram().getProcedureCompilation(procedure.getRef());
|
||||
if(procedureCompilation == null)
|
||||
throw new CompileError("Error! Function body is never defined: " + procedure.getFullName());
|
||||
final ControlFlowBlock procedureBlock = procedureCompilation.getGraph().getBlock(procedureLabel.getRef());
|
||||
final Graph.Block procedureBlock = procedureCompilation.getGraph().getBlock(procedureLabel.getRef());
|
||||
if(procedureBlock == null)
|
||||
throw new CompileError("Error! Function body is never defined: " + procedure.getFullName());
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ public class Pass1AssertReturn extends Pass1Base {
|
||||
final ProcedureCompilation procedureCompilation = getProgram().getProcedureCompilation(procedure.getRef());
|
||||
final ControlFlowGraph graph = procedureCompilation.getGraph();
|
||||
LabelRef entryLabel = procedure.getRef().getLabelRef();
|
||||
ControlFlowBlock entryBlock = graph.getBlock(entryLabel);
|
||||
Graph.Block entryBlock = graph.getBlock(entryLabel);
|
||||
assertReturn(graph, entryBlock, new LinkedHashSet<>());
|
||||
}
|
||||
}
|
||||
@ -45,25 +45,23 @@ public class Pass1AssertReturn extends Pass1Base {
|
||||
* @param block The block to examine
|
||||
* @param visited Blocks already visited
|
||||
*/
|
||||
public void assertReturn(ControlFlowGraph graph, ControlFlowBlock block, Collection<LabelRef> visited) {
|
||||
public void assertReturn(ControlFlowGraph graph, Graph.Block block, Collection<LabelRef> visited) {
|
||||
if(visited.contains(block.getLabel())) {
|
||||
return;
|
||||
}
|
||||
visited.add(block.getLabel());
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
if(statement instanceof StatementAssignment assignment) {
|
||||
if(assignment.getlValue() instanceof VariableRef && ((VariableRef) assignment.getlValue()).getLocalName().equals("return")) {
|
||||
// Happy days - return found!
|
||||
return;
|
||||
}
|
||||
} else if(statement instanceof StatementConditionalJump) {
|
||||
StatementConditionalJump cond = (StatementConditionalJump) statement;
|
||||
ControlFlowBlock jumpTo = graph.getBlock(cond.getDestination());
|
||||
} else if(statement instanceof StatementConditionalJump cond) {
|
||||
Graph.Block jumpTo = graph.getBlock(cond.getDestination());
|
||||
assertReturn(graph, jumpTo, visited);
|
||||
}
|
||||
}
|
||||
ControlFlowBlock successor = graph.getBlock(block.getDefaultSuccessor());
|
||||
Graph.Block successor = graph.getBlock(block.getDefaultSuccessor());
|
||||
if(successor == null || successor.getLabel().getLocalName().equals(SymbolRef.PROCEXIT_BLOCK_NAME)) {
|
||||
throw new CompileError("Error! Method must end with a return statement. " + block.getScope().toString(getProgram()));
|
||||
} else {
|
||||
|
@ -15,18 +15,28 @@ import java.util.*;
|
||||
/** Handle calling convention {@link Procedure.CallingConvention#PHI_CALL} by passing parameters through variables */
|
||||
public class Pass1CallPhiParameters {
|
||||
|
||||
private Program program;
|
||||
private final Program program;
|
||||
|
||||
public Pass1CallPhiParameters(Program program) {
|
||||
this.program = program;
|
||||
}
|
||||
|
||||
private Map<LabelRef, LabelRef> splitBlockMap = new LinkedHashMap<>();
|
||||
|
||||
public void execute() {
|
||||
final List<Graph.Block> todoBlocks = getGraph().getAllBlocks();
|
||||
for(ProcedureCompilation procedureCompilation : this.program.getProcedureCompilations()) {
|
||||
handleProcedure(procedureCompilation);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleProcedure(ProcedureCompilation procedureCompilation) {
|
||||
|
||||
final Graph graph = procedureCompilation.getGraph();
|
||||
|
||||
final List<Graph.Block> todoBlocks = new ArrayList<>(graph.getAllBlocks());
|
||||
List<Graph.Block> doneBlocks = new ArrayList<>();
|
||||
|
||||
Map<LabelRef, LabelRef> splitBlockMap = new LinkedHashMap<>();
|
||||
|
||||
|
||||
while(!todoBlocks.isEmpty()) {
|
||||
final Graph.Block block = todoBlocks.get(0);
|
||||
todoBlocks.remove(0);
|
||||
@ -35,14 +45,13 @@ public class Pass1CallPhiParameters {
|
||||
final ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement statement = stmtIt.next();
|
||||
if(statement instanceof StatementCall) {
|
||||
StatementCall call = (StatementCall) statement;
|
||||
if(statement instanceof StatementCall call) {
|
||||
// Generate parameter passing assignments
|
||||
ProcedureRef procedureRef = call.getProcedure();
|
||||
Procedure procedure = getScope().getProcedure(procedureRef);
|
||||
// Handle PHI-calls
|
||||
if(Procedure.CallingConvention.PHI_CALL.equals(procedure.getCallingConvention())) {
|
||||
final ControlFlowBlock newBlock = handlePhiCall(call, procedure, stmtIt, block);
|
||||
final ControlFlowBlock newBlock = handlePhiCall(call, procedure, stmtIt, block, splitBlockMap);
|
||||
// The current block was split into two blocks - add the new block at the front of the todoBlocks
|
||||
todoBlocks.add(0, newBlock);
|
||||
}
|
||||
@ -57,18 +66,19 @@ public class Pass1CallPhiParameters {
|
||||
for(VariableRef modifiedVar : modifiedVars) {
|
||||
if(getScope().getVariable(modifiedVar).isKindLoadStore())
|
||||
continue;
|
||||
stmtIt.add(new StatementAssignment(modifiedVar, modifiedVar, false, ((StatementReturn) statement).getSource(), Comment.NO_COMMENTS));
|
||||
stmtIt.add(new StatementAssignment(modifiedVar, modifiedVar, false, statement.getSource(), Comment.NO_COMMENTS));
|
||||
}
|
||||
stmtIt.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update graph blocks to include the new blocks added
|
||||
program.getGraph().setAllBlocks(doneBlocks);
|
||||
procedureCompilation.setGraph(new ControlFlowGraph(doneBlocks));
|
||||
|
||||
// Fix phi predecessors for any blocks has a split block as predecessor
|
||||
for(Graph.Block block : getGraph().getAllBlocks()) {
|
||||
for(var block : procedureCompilation.getGraph().getAllBlocks()) {
|
||||
if(block.hasPhiBlock()) {
|
||||
for(StatementPhiBlock.PhiVariable phiVariable : block.getPhiBlock().getPhiVariables()) {
|
||||
for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
|
||||
@ -86,11 +96,7 @@ public class Pass1CallPhiParameters {
|
||||
return program.getScope();
|
||||
}
|
||||
|
||||
private Graph getGraph() {
|
||||
return program.getGraph();
|
||||
}
|
||||
|
||||
private ControlFlowBlock handlePhiCall(StatementCall call, Procedure procedure, ListIterator<Statement> stmtIt, Graph.Block block) {
|
||||
private ControlFlowBlock handlePhiCall(StatementCall call, Procedure procedure, ListIterator<Statement> stmtIt, Graph.Block block, Map<LabelRef, LabelRef> splitBlockMap) {
|
||||
|
||||
List<Variable> parameterDefs = procedure.getParameters();
|
||||
List<RValue> parameterValues = call.getParameters();
|
||||
|
@ -32,10 +32,10 @@ public class Pass1GenerateControlFlowGraph extends Pass1Base {
|
||||
// Empty procedures should not produce any blocks
|
||||
continue;
|
||||
|
||||
List<ControlFlowBlock> blocks = new ArrayList<>();
|
||||
List<Graph.Block> blocks = new ArrayList<>();
|
||||
|
||||
ControlFlowBlock currentBlock = null;
|
||||
ControlFlowBlock procBlock = getOrCreateBlock(procedure.getLabel().getRef(), procedure.getRef(), blocks);
|
||||
Graph.Block currentBlock;
|
||||
Graph.Block procBlock = getOrCreateBlock(procedure.getLabel().getRef(), procedure.getRef(), blocks);
|
||||
currentBlock = procBlock;
|
||||
for(Statement statement : sequence.getStatements()) {
|
||||
Symbol currentBlockLabel = getProgram().getScope().getSymbol(currentBlock.getLabel());
|
||||
@ -50,29 +50,25 @@ public class Pass1GenerateControlFlowGraph extends Pass1Base {
|
||||
} else if(statement instanceof StatementProcedureEnd) {
|
||||
// Procedure strategy implemented is currently variable-based transfer of parameters/return values
|
||||
currentBlock.setDefaultSuccessor(new Label(SymbolRef.PROCEXIT_BLOCK_NAME, programScope, false).getRef());
|
||||
} else if(statement instanceof StatementLabel) {
|
||||
StatementLabel statementLabel = (StatementLabel) statement;
|
||||
ControlFlowBlock nextBlock = getOrCreateBlock(statementLabel.getLabel(), currentBlock.getScope(), blocks);
|
||||
} else if(statement instanceof StatementLabel statementLabel) {
|
||||
Graph.Block nextBlock = getOrCreateBlock(statementLabel.getLabel(), currentBlock.getScope(), blocks);
|
||||
nextBlock.setComments(statementLabel.getComments());
|
||||
currentBlock.setDefaultSuccessor(nextBlock.getLabel());
|
||||
currentBlock = nextBlock;
|
||||
} else if(statement instanceof StatementJump) {
|
||||
StatementJump statementJump = (StatementJump) statement;
|
||||
ControlFlowBlock jmpBlock = getOrCreateBlock(statementJump.getDestination(), currentBlock.getScope(), blocks);
|
||||
} else if(statement instanceof StatementJump statementJump) {
|
||||
Graph.Block jmpBlock = getOrCreateBlock(statementJump.getDestination(), currentBlock.getScope(), blocks);
|
||||
currentBlock.setDefaultSuccessor(jmpBlock.getLabel());
|
||||
ControlFlowBlock nextBlock = getOrCreateBlock(currentBlockScope.addLabelIntermediate().getRef(), currentBlock.getScope(), blocks);
|
||||
Graph.Block nextBlock = getOrCreateBlock(currentBlockScope.addLabelIntermediate().getRef(), currentBlock.getScope(), blocks);
|
||||
currentBlock = nextBlock;
|
||||
} else if(statement instanceof StatementConditionalJump) {
|
||||
} else if(statement instanceof StatementConditionalJump statementConditionalJump) {
|
||||
currentBlock.addStatement(statement);
|
||||
StatementConditionalJump statementConditionalJump = (StatementConditionalJump) statement;
|
||||
ControlFlowBlock jmpBlock = getOrCreateBlock(statementConditionalJump.getDestination(), currentBlock.getScope(), blocks);
|
||||
ControlFlowBlock nextBlock = getOrCreateBlock(currentBlockScope.addLabelIntermediate().getRef(), currentBlock.getScope(), blocks);
|
||||
Graph.Block jmpBlock = getOrCreateBlock(statementConditionalJump.getDestination(), currentBlock.getScope(), blocks);
|
||||
Graph.Block nextBlock = getOrCreateBlock(currentBlockScope.addLabelIntermediate().getRef(), currentBlock.getScope(), blocks);
|
||||
currentBlock.setDefaultSuccessor(nextBlock.getLabel());
|
||||
currentBlock.setConditionalSuccessor(jmpBlock.getLabel());
|
||||
currentBlock = nextBlock;
|
||||
} else if(statement instanceof StatementReturn) {
|
||||
} else if(statement instanceof StatementReturn aReturn) {
|
||||
// Procedure strategy implemented is currently variable-based transfer of parameters/return values
|
||||
StatementReturn aReturn = (StatementReturn) statement;
|
||||
currentBlock.addStatement(aReturn);
|
||||
} else {
|
||||
currentBlock.addStatement(statement);
|
||||
@ -85,13 +81,13 @@ public class Pass1GenerateControlFlowGraph extends Pass1Base {
|
||||
return false;
|
||||
}
|
||||
|
||||
private ControlFlowBlock getOrCreateBlock(LabelRef label, ScopeRef scope, List<ControlFlowBlock> blocks) {
|
||||
for(ControlFlowBlock block : blocks) {
|
||||
private Graph.Block getOrCreateBlock(LabelRef label, ScopeRef scope, List<Graph.Block> blocks) {
|
||||
for(var block : blocks) {
|
||||
if(block.getLabel().equals(label)) {
|
||||
return block;
|
||||
}
|
||||
}
|
||||
ControlFlowBlock block = new ControlFlowBlock(label, scope);
|
||||
Graph.Block block = new ControlFlowBlock(label, scope);
|
||||
blocks.add(block);
|
||||
return block;
|
||||
}
|
||||
|
@ -23,16 +23,23 @@ public class Pass1ProcedureInline extends Pass1Base {
|
||||
|
||||
@Override
|
||||
public boolean step() {
|
||||
List<Graph.Block> allBlocks = getGraph().getAllBlocks();
|
||||
ListIterator<Graph.Block> blocksIt = allBlocks.listIterator();
|
||||
for(var procedureCompilation : getProgram().getProcedureCompilations())
|
||||
if(inlineProcedure(procedureCompilation))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean inlineProcedure(ProcedureCompilation procedureCompilation) {
|
||||
final ControlFlowGraph procedureGraph = procedureCompilation.getGraph();
|
||||
final List<Graph.Block> procedureBlocks = new ArrayList<>(procedureGraph.getAllBlocks());
|
||||
ListIterator<Graph.Block> blocksIt = procedureBlocks.listIterator();
|
||||
while(blocksIt.hasNext()) {
|
||||
Graph.Block block = blocksIt.next();
|
||||
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;
|
||||
if(statement instanceof StatementCall call) {
|
||||
ProcedureRef procedureRef = call.getProcedure();
|
||||
Procedure procedure = getProgramScope().getProcedure(procedureRef);
|
||||
if(procedure.isDeclaredInline()) {
|
||||
@ -41,6 +48,8 @@ public class Pass1ProcedureInline extends Pass1Base {
|
||||
throw new CompileError("Error! Interrupts cannot be inlined. "+procedure.getRef().toString());
|
||||
}
|
||||
inlineProcedureCall(call, procedure, statementsIt, block, blocksIt);
|
||||
// Update the procedure graph
|
||||
procedureCompilation.setGraph(new ControlFlowGraph(procedureBlocks));
|
||||
// Exit and restart
|
||||
return true;
|
||||
}
|
||||
@ -184,24 +193,17 @@ public class Pass1ProcedureInline extends Pass1Base {
|
||||
*/
|
||||
private Statement inlineStatement(Statement procStatement, Procedure procedure, Scope callScope, int serial) {
|
||||
Statement inlinedStatement;
|
||||
if(procStatement instanceof StatementAssignment) {
|
||||
StatementAssignment procAssignment = (StatementAssignment) procStatement;
|
||||
if(procStatement instanceof StatementAssignment procAssignment) {
|
||||
inlinedStatement = new StatementAssignment(procAssignment.getlValue(), procAssignment.getrValue1(), procAssignment.getOperator(), procAssignment.getrValue2(), procAssignment.isInitialAssignment(), procAssignment.getSource(), Comment.NO_COMMENTS);
|
||||
} else if(procStatement instanceof StatementCall) {
|
||||
StatementCall procCall = (StatementCall) procStatement;
|
||||
} else if(procStatement instanceof StatementCall procCall) {
|
||||
StatementCall inlinedCall = new StatementCall(procCall.getlValue(), procCall.getProcedureName(), new ArrayList<>(procCall.getParameters()), procCall.getSource(), procCall.getComments());
|
||||
inlinedCall.setProcedure(procCall.getProcedure());
|
||||
inlinedStatement = inlinedCall;
|
||||
} else if(procStatement instanceof StatementAsm) {
|
||||
StatementAsm procAsm = (StatementAsm) procStatement;
|
||||
StatementAsm inlinedAsm = new StatementAsm(procAsm.getAsmLines(), new LinkedHashMap<>(procAsm.getReferenced()), procAsm.getDeclaredClobber(), procAsm.getSource(), Comment.NO_COMMENTS);
|
||||
inlinedStatement = inlinedAsm;
|
||||
} else if(procStatement instanceof StatementKickAsm) {
|
||||
StatementKickAsm procKasm = (StatementKickAsm) procStatement;
|
||||
StatementKickAsm inlinedAsm = new StatementKickAsm(procKasm.getKickAsmCode(), procKasm.getBytes(), procKasm.getCycles(), procKasm.getUses(), procKasm.getDeclaredClobber(), procKasm.getSource(), Comment.NO_COMMENTS);
|
||||
inlinedStatement = inlinedAsm;
|
||||
} else if(procStatement instanceof StatementConditionalJump) {
|
||||
StatementConditionalJump procConditional = (StatementConditionalJump) procStatement;
|
||||
} else if(procStatement instanceof StatementAsm procAsm) {
|
||||
inlinedStatement = new StatementAsm(procAsm.getAsmLines(), new LinkedHashMap<>(procAsm.getReferenced()), procAsm.getDeclaredClobber(), procAsm.getSource(), Comment.NO_COMMENTS);
|
||||
} else if(procStatement instanceof StatementKickAsm procKasm) {
|
||||
inlinedStatement = new StatementKickAsm(procKasm.getKickAsmCode(), procKasm.getBytes(), procKasm.getCycles(), procKasm.getUses(), procKasm.getDeclaredClobber(), procKasm.getSource(), Comment.NO_COMMENTS);
|
||||
} else if(procStatement instanceof StatementConditionalJump procConditional) {
|
||||
LabelRef procDestinationRef = procConditional.getDestination();
|
||||
Label procDestination = getProgramScope().getLabel(procDestinationRef);
|
||||
Label inlinedDest = procDestination;
|
||||
@ -218,9 +220,7 @@ public class Pass1ProcedureInline extends Pass1Base {
|
||||
} else {
|
||||
throw new CompileError("Statement type of Inline function not handled " + procStatement, procStatement.getSource());
|
||||
}
|
||||
if(inlinedStatement!=null) {
|
||||
ProgramValueIterator.execute(inlinedStatement, new RValueInliner(procedure, serial, callScope), null, null);
|
||||
}
|
||||
ProgramValueIterator.execute(inlinedStatement, new RValueInliner(procedure, serial, callScope), null, null);
|
||||
return inlinedStatement;
|
||||
}
|
||||
|
||||
@ -246,8 +246,7 @@ public class Pass1ProcedureInline extends Pass1Base {
|
||||
@Override
|
||||
public void execute(ProgramValue programValue, Statement currentStmt, ListIterator<Statement> stmtIt, Graph.Block currentBlock) {
|
||||
Value rValue = programValue.get();
|
||||
if(rValue instanceof VariableRef) {
|
||||
VariableRef procVarRef = (VariableRef) rValue;
|
||||
if(rValue instanceof VariableRef procVarRef) {
|
||||
Variable procVar = Pass1ProcedureInline.this.getProgramScope().getVariable(procVarRef);
|
||||
if(procVar.getScope().equals(procedure)) {
|
||||
String inlineSymbolName = Pass1ProcedureInline.this.getInlineSymbolName(procedure, procVar, serial);
|
||||
@ -299,8 +298,7 @@ public class Pass1ProcedureInline extends Pass1Base {
|
||||
callScope.addLabel(procedure.getLocalName() + serial);
|
||||
// And copy all procedure symbols
|
||||
for(Symbol procSymbol : procedure.getAllSymbols()) {
|
||||
if(procSymbol instanceof Variable) {
|
||||
Variable procVar = (Variable) procSymbol;
|
||||
if(procSymbol instanceof Variable procVar) {
|
||||
String inlineVarName = getInlineSymbolName(procedure, procSymbol, serial);
|
||||
Variable inlineVar = Variable.createCopy(inlineVarName, callScope, procVar);
|
||||
callScope.add(inlineVar);
|
||||
|
@ -28,14 +28,22 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
||||
|
||||
@Override
|
||||
public boolean step() {
|
||||
boolean modified = false;
|
||||
for(ProcedureCompilation procedureCompilation : getProgram().getProcedureCompilations()) {
|
||||
modified |= findAndRewriteBooleanConditions(procedureCompilation.getGraph());
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
private boolean findAndRewriteBooleanConditions(Graph graph) {
|
||||
boolean done = false;
|
||||
boolean modified = false;
|
||||
while(!done) {
|
||||
VariableRef obsoleteConditionVar = findAndRewriteBooleanCondition();
|
||||
VariableRef obsoleteConditionVar = findAndRewriteBooleanCondition(graph);
|
||||
if(obsoleteConditionVar != null) {
|
||||
Collection<VariableRef> obsoleteVars = new ArrayList<>();
|
||||
obsoleteVars.add(obsoleteConditionVar);
|
||||
removeAssignments(getGraph(), obsoleteVars);
|
||||
removeAssignments(graph, obsoleteVars);
|
||||
deleteSymbols(getProgramScope(), obsoleteVars);
|
||||
modified = true;
|
||||
} else {
|
||||
@ -46,17 +54,17 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
||||
}
|
||||
|
||||
/**
|
||||
* Look through the entire program looking for an if() condition that uses &&, || or !.
|
||||
* Look through a control flow graph looking for an if() condition that uses &&, || or !.
|
||||
* When found rewrite it (adding blocks)
|
||||
*
|
||||
* @return Null if no condition was found to rewrite. The now obsolete variable containing the && / || / ! to be removed.
|
||||
* @param graph The control flow graph to modify
|
||||
*/
|
||||
private VariableRef findAndRewriteBooleanCondition() {
|
||||
private VariableRef findAndRewriteBooleanCondition(Graph graph) {
|
||||
final VariableReferenceInfos variableReferenceInfos = getProgram().getVariableReferenceInfos();
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
for(var block : graph.getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementConditionalJump) {
|
||||
StatementConditionalJump conditional = (StatementConditionalJump) statement;
|
||||
if(statement instanceof StatementConditionalJump conditional) {
|
||||
if(conditional.getrValue1() == null && conditional.getOperator() == null) {
|
||||
RValue conditionRValue = conditional.getrValue2();
|
||||
if(conditionRValue instanceof VariableRef) {
|
||||
@ -65,16 +73,15 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
||||
VariableRef conditionVar = (VariableRef) conditionRValue;
|
||||
final Integer conditionDefineStatementIdx = variableReferenceInfos.getVarDefineStatement(conditionVar);
|
||||
if(conditionDefineStatementIdx != null) {
|
||||
final Statement conditionDefineStatement = getGraph().getStatementByIndex(conditionDefineStatementIdx);
|
||||
if(conditionDefineStatement instanceof StatementAssignment) {
|
||||
StatementAssignment conditionAssignment = (StatementAssignment) conditionDefineStatement;
|
||||
final Statement conditionDefineStatement = graph.getStatementByIndex(conditionDefineStatementIdx);
|
||||
if(conditionDefineStatement instanceof StatementAssignment conditionAssignment) {
|
||||
if(Operators.LOGIC_AND.equals(conditionAssignment.getOperator())) {
|
||||
// Found if() with logical && condition - rewrite to if(c1) if(c2) { xx }
|
||||
rewriteLogicAnd(block, conditional, conditionAssignment);
|
||||
rewriteLogicAnd(block, conditional, conditionAssignment, getGraph());
|
||||
return conditionVar;
|
||||
} else if(Operators.LOGIC_OR.equals(conditionAssignment.getOperator())) {
|
||||
// Found if() with logical || condition - rewrite to if(c1) goto x else if(c2) goto x else goto end, x:{ xx } end:
|
||||
rewriteLogicOr(block, conditional, conditionAssignment);
|
||||
rewriteLogicOr(block, conditional, conditionAssignment, getGraph());
|
||||
return conditionVar;
|
||||
} else if(Operators.LOGIC_NOT.equals(conditionAssignment.getOperator())) {
|
||||
// Found if() with logical ! condition - rewrite to if(!c1) goto x else goto end, x:{ xx } end:
|
||||
@ -98,8 +105,9 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
||||
* @param block The block containing the current if()
|
||||
* @param conditional The if()-statement
|
||||
* @param conditionAssignment The assignment defining the condition variable.
|
||||
* @param graph The control flow graph to modify
|
||||
*/
|
||||
private void rewriteLogicAnd(Graph.Block block, StatementConditionalJump conditional, StatementAssignment conditionAssignment) {
|
||||
private void rewriteLogicAnd(Graph.Block block, StatementConditionalJump conditional, StatementAssignment conditionAssignment, Graph graph) {
|
||||
// Found an if with a logical && condition - rewrite to if(c1) if(c2) { xx }
|
||||
getLog().append("Rewriting && if()-condition to two if()s " + conditionAssignment.toString(getProgram(), false));
|
||||
ScopeRef currentScopeRef = block.getScope();
|
||||
@ -107,7 +115,7 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
||||
// Add a new block containing the second part of the && condition expression
|
||||
Label newBlockLabel = currentScope.addLabelIntermediate();
|
||||
ControlFlowBlock newBlock = new ControlFlowBlock(newBlockLabel.getRef(), currentScopeRef);
|
||||
getGraph().addBlock(newBlock);
|
||||
graph.addBlock(newBlock);
|
||||
LabelRef destLabel = conditional.getDestination();
|
||||
StatementConditionalJump newConditional = new StatementConditionalJump(conditionAssignment.getrValue2(), destLabel, conditional.getSource(), Comment.NO_COMMENTS);
|
||||
newConditional.setDeclaredUnroll(conditional.isDeclaredUnroll());
|
||||
@ -120,7 +128,7 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
||||
conditional.setrValue2(conditionAssignment.getrValue1());
|
||||
|
||||
// Replace the phi labels inside the destination block with the new block
|
||||
Graph.Block destBlock = getGraph().getBlock(destLabel);
|
||||
Graph.Block destBlock = graph.getBlock(destLabel);
|
||||
LinkedHashMap<LabelRef, LabelRef> replacements = new LinkedHashMap<>();
|
||||
replacements.put(block.getLabel(), newBlockLabel.getRef());
|
||||
replaceLabels(destBlock.getPhiBlock(), replacements);
|
||||
@ -133,15 +141,16 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
||||
* @param block The block containing the current if()
|
||||
* @param conditional The if()-statement
|
||||
* @param conditionAssignment The assignment defining the condition variable.
|
||||
* @param graph The control flow graph to modify
|
||||
*/
|
||||
private void rewriteLogicOr(Graph.Block block, StatementConditionalJump conditional, StatementAssignment conditionAssignment) {
|
||||
private void rewriteLogicOr(Graph.Block block, StatementConditionalJump conditional, StatementAssignment conditionAssignment, Graph graph) {
|
||||
getLog().append("Rewriting || if()-condition to two if()s " + conditionAssignment.toString(getProgram(), false));
|
||||
ScopeRef currentScopeRef = block.getScope();
|
||||
Scope currentScope = getProgramScope().getScope(currentScopeRef);
|
||||
// Add a new block containing the second part of the && condition expression
|
||||
Label newBlockLabel = currentScope.addLabelIntermediate();
|
||||
ControlFlowBlock newBlock = new ControlFlowBlock(newBlockLabel.getRef(), currentScopeRef);
|
||||
getGraph().addBlock(newBlock);
|
||||
graph.addBlock(newBlock);
|
||||
StatementConditionalJump newConditional = new StatementConditionalJump(conditionAssignment.getrValue2(), conditional.getDestination(), conditional.getSource(), Comment.NO_COMMENTS);
|
||||
// Copy unrolling to the new conditional
|
||||
newConditional.setDeclaredUnroll(conditional.isDeclaredUnroll());
|
||||
@ -155,7 +164,7 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
||||
conditional.setDeclaredUnroll(false);
|
||||
|
||||
// Update the default destination PHI block to reflect the last of the conditions
|
||||
Graph.Block defaultDestBlock = getGraph().getBlock(newBlock.getDefaultSuccessor());
|
||||
Graph.Block defaultDestBlock = graph.getBlock(newBlock.getDefaultSuccessor());
|
||||
if(defaultDestBlock.hasPhiBlock()) {
|
||||
StatementPhiBlock defaultDestPhiBlock = defaultDestBlock.getPhiBlock();
|
||||
for(StatementPhiBlock.PhiVariable phiVariable : defaultDestPhiBlock.getPhiVariables()) {
|
||||
@ -168,13 +177,13 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
||||
}
|
||||
}
|
||||
|
||||
Graph.Block conditionalDestBlock = getGraph().getBlock(conditional.getDestination());
|
||||
Graph.Block conditionalDestBlock = graph.getBlock(conditional.getDestination());
|
||||
if(conditionalDestBlock.hasPhiBlock()) {
|
||||
StatementPhiBlock conditionalDestPhiBlock = conditionalDestBlock.getPhiBlock();
|
||||
for(StatementPhiBlock.PhiVariable phiVariable : conditionalDestPhiBlock.getPhiVariables()) {
|
||||
for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
|
||||
if(phiRValue.getPredecessor().equals(block.getLabel())) {
|
||||
// Found phi-variable with current block as predecessor - copy the phivalue for the new block
|
||||
// Found phi-variable with current block as predecessor - copy the phi-value for the new block
|
||||
phiVariable.setrValue(newBlockLabel.getRef(), phiRValue.getrValue());
|
||||
break;
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ public class Pass2ConstantInlining extends Pass2SsaOptimization {
|
||||
private void removeParameters(Set<ConstantRef> inlineRefs) {
|
||||
for(ConstantRef inlineRef : inlineRefs) {
|
||||
final Scope scope = getProgramScope().getConstant(inlineRef).getScope();
|
||||
final Procedure procedure = getProcedure(scope);
|
||||
final Procedure procedure = scope.getProcedure();
|
||||
if(procedure!=null) {
|
||||
final List<Variable> parameters = procedure.getParameters();
|
||||
final boolean modified = parameters.removeIf(param -> param.getRef().equals(inlineRef));
|
||||
@ -83,15 +83,6 @@ public class Pass2ConstantInlining extends Pass2SsaOptimization {
|
||||
}
|
||||
}
|
||||
|
||||
private static Procedure getProcedure(Scope scope) {
|
||||
if(scope instanceof Procedure)
|
||||
return (Procedure) scope;
|
||||
else if(scope instanceof ProgramScope)
|
||||
return null;
|
||||
else
|
||||
return getProcedure(scope.getScope());
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace any aliases within the constant values themselves
|
||||
*
|
||||
|
@ -1,10 +1,7 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.CompileLog;
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.statements.*;
|
||||
import dk.camelot64.kickc.model.symbols.Label;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
@ -14,7 +11,7 @@ import dk.camelot64.kickc.model.values.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/** Pass that eliminates constant if's - they are either removed (if false) or replaces the default successor (if true). */
|
||||
/** Pass that eliminates blocks that are not referenced. */
|
||||
public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
||||
|
||||
public Pass2EliminateUnusedBlocks(Program program) {
|
||||
@ -28,9 +25,13 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
if(!referencedBlocks.contains(block.getLabel())) {
|
||||
unusedBlocks.add(block.getLabel());
|
||||
}
|
||||
}
|
||||
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
if(unusedBlocks.contains(block.getLabel())) {
|
||||
for(Statement stmt : block.getStatements()) {
|
||||
if(stmt instanceof StatementLValue) {
|
||||
StatementLValue assignment = (StatementLValue) stmt;
|
||||
if(stmt instanceof StatementLValue assignment) {
|
||||
LValue lValue = assignment.getlValue();
|
||||
if(lValue instanceof VariableRef) {
|
||||
Variable variable = getProgramScope().getVariable((VariableRef) lValue);
|
||||
@ -52,12 +53,14 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Set<LabelRef> removedBlocks = new HashSet<>();
|
||||
for(LabelRef unusedBlock : unusedBlocks) {
|
||||
Symbol unusedSymbol = getProgramScope().getSymbol(unusedBlock);
|
||||
if(unusedSymbol instanceof Label) {
|
||||
getGraph().remove(unusedBlock);
|
||||
final Procedure procedure = unusedSymbol.getScope().getProcedure();
|
||||
final ProcedureCompilation procedureCompilation = getProgram().getProcedureCompilation(procedure.getRef());
|
||||
final ControlFlowGraph procedureGraph = procedureCompilation.getGraph();
|
||||
procedureGraph.remove(unusedBlock);
|
||||
Label label = getProgramScope().getLabel(unusedBlock);
|
||||
label.getScope().remove(label);
|
||||
removePhiRValues(unusedBlock, getProgram());
|
||||
@ -85,31 +88,19 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
||||
public static void removeProcedure(ProcedureRef procedureRef, Set<LabelRef> removedBlocks, Program program) {
|
||||
program.getLog().append("Removing unused procedure " + procedureRef);
|
||||
Procedure unusedProcedure = program.getScope().getProcedure(procedureRef);
|
||||
List<Graph.Block> procedureBlocks = program.getGraph().getScopeBlocks(procedureRef);
|
||||
final ProcedureCompilation procedureCompilation = program.getProcedureCompilation(procedureRef);
|
||||
final ControlFlowGraph procedureGraph = procedureCompilation.getGraph();
|
||||
List<Graph.Block> procedureBlocks = new ArrayList<>(procedureGraph.getAllBlocks());
|
||||
for(var procedureBlock : procedureBlocks) {
|
||||
LabelRef blockLabelRef = procedureBlock.getLabel();
|
||||
program.getLog().append("Removing unused procedure block " + blockLabelRef);
|
||||
program.getGraph().remove(blockLabelRef);
|
||||
procedureGraph.remove(blockLabelRef);
|
||||
removePhiRValues(blockLabelRef, program);
|
||||
removedBlocks.add(blockLabelRef);
|
||||
}
|
||||
unusedProcedure.getScope().remove(unusedProcedure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all referenced blocks in the entire program
|
||||
*
|
||||
* @return All blocks referenced
|
||||
*/
|
||||
private Set<LabelRef> getReferencedBlocks() {
|
||||
Set<LabelRef> referencedBlocks = new LinkedHashSet<>();
|
||||
List<Graph.Block> entryPointBlocks = getProgram().getEntryPointBlocks();
|
||||
for(var entryPointBlock : entryPointBlocks) {
|
||||
findReferencedBlocks(entryPointBlock, referencedBlocks);
|
||||
}
|
||||
|
||||
return referencedBlocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all PHI RValues in any phi-statements referencing the passed block
|
||||
@ -143,6 +134,21 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all referenced blocks in the entire program
|
||||
*
|
||||
* @return All blocks referenced
|
||||
*/
|
||||
private Set<LabelRef> getReferencedBlocks() {
|
||||
Set<LabelRef> referencedBlocks = new LinkedHashSet<>();
|
||||
List<Graph.Block> entryPointBlocks = getProgram().getEntryPointBlocks();
|
||||
for(var entryPointBlock : entryPointBlocks) {
|
||||
findReferencedBlocks(entryPointBlock, referencedBlocks);
|
||||
}
|
||||
|
||||
return referencedBlocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all referenced block labels recursively
|
||||
*
|
||||
|
@ -31,10 +31,16 @@ public class Pass3PhiLifting {
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
Graph graph = program.getGraph();
|
||||
for(var procedureCompilation : program.getProcedureCompilations()) {
|
||||
upliftProcedure(procedureCompilation);
|
||||
}
|
||||
}
|
||||
|
||||
private void upliftProcedure(ProcedureCompilation procedureCompilation) {
|
||||
final ControlFlowGraph graph = procedureCompilation.getGraph();
|
||||
List<Graph.Block> liftedBlocks = new ArrayList<>(graph.getAllBlocks());
|
||||
ProgramScope programScope = program.getScope();
|
||||
List<Graph.Block> blocks = graph.getAllBlocks();
|
||||
ListIterator<Graph.Block> blocksIt = blocks.listIterator();
|
||||
ListIterator<Graph.Block> blocksIt = liftedBlocks.listIterator();
|
||||
while(blocksIt.hasNext()) {
|
||||
Graph.Block block = blocksIt.next();
|
||||
// Maps old predecessors to new blocks created
|
||||
@ -45,7 +51,11 @@ public class Pass3PhiLifting {
|
||||
for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
|
||||
if(!(phiRValue.getrValue() instanceof ConstantValue)) {
|
||||
LabelRef predecessorRef = phiRValue.getPredecessor();
|
||||
Graph.Block predecessorBlock = graph.getBlock(predecessorRef);
|
||||
Graph.Block predecessorBlock = getBlock(liftedBlocks, predecessorRef);
|
||||
if(predecessorBlock==null) {
|
||||
// Look for the predecessor in the entire graph
|
||||
predecessorBlock = program.getGraph().getBlock(predecessorRef);
|
||||
}
|
||||
//VariableRef rValVarRef = (VariableRef) phiRValue.getrValue();
|
||||
Variable newVar;
|
||||
if(phiVariable.getVariable().isVersion()) {
|
||||
@ -88,7 +98,7 @@ public class Pass3PhiLifting {
|
||||
}
|
||||
program.getLog().append("Added new block during phi lifting " + newBlock.getLabel() + "(between " + predecessorRef + " and " + block.getLabel() + ")");
|
||||
} else {
|
||||
newBlock = graph.getBlock(newBlockRef);
|
||||
newBlock = getBlock(liftedBlocks, newBlockRef);
|
||||
}
|
||||
List<Statement> newBlockStatements = newBlock.getStatements();
|
||||
newBlockStatements.add(newAssignment);
|
||||
@ -121,6 +131,14 @@ public class Pass3PhiLifting {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the procedure with the PHI-lifted blocks
|
||||
procedureCompilation.setGraph(new ControlFlowGraph(liftedBlocks));
|
||||
|
||||
}
|
||||
|
||||
private Graph.Block getBlock(List<Graph.Block> blocks, LabelRef blockRef) {
|
||||
return blocks.stream().filter(block -> block.getLabel().equals(blockRef)).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.symbols.Scope;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/** Plan the optimal sequence for the blocks of the control flow graph */
|
||||
public class PassNBlockSequencePlanner extends Pass2SsaOptimization {
|
||||
@ -62,7 +62,7 @@ public class PassNBlockSequencePlanner extends Pass2SsaOptimization {
|
||||
}
|
||||
|
||||
}
|
||||
getGraph().setSequence(sequence);
|
||||
setSequence(sequence);
|
||||
|
||||
if(getLog().isVerboseSequencePlan()) {
|
||||
StringBuilder entry = new StringBuilder();
|
||||
@ -78,6 +78,21 @@ public class PassNBlockSequencePlanner extends Pass2SsaOptimization {
|
||||
|
||||
}
|
||||
|
||||
public void setSequence(List<LabelRef> sequence) {
|
||||
if(sequence.size() != getGraph().getAllBlocks().size()) {
|
||||
throw new CompileError("ERROR! Sequence does not contain all blocks from the program. Sequence: " + sequence.size() + " Blocks: " + getGraph().getAllBlocks().size());
|
||||
}
|
||||
for(var procedureCompilation : getProgram().getProcedureCompilations()) {
|
||||
final ControlFlowGraph procedureGraph = procedureCompilation.getGraph();
|
||||
final List<LabelRef> procedureLabels = procedureGraph.getAllBlocks().stream().map(Graph.Block::getLabel).toList();
|
||||
final List<Graph.Block> procedureSequence = sequence.stream().filter(procedureLabels::contains).map(procedureGraph::getBlock).toList();
|
||||
if(procedureSequence.size() != procedureGraph.getAllBlocks().size()) {
|
||||
throw new CompileError("ERROR! Sequence does not contain all blocks for "+procedureCompilation.getProcedureRef()+". Sequence: " + procedureSequence.size() + " Blocks: " + procedureGraph.getAllBlocks().size());
|
||||
}
|
||||
procedureCompilation.setGraph(new ControlFlowGraph(procedureSequence));
|
||||
}
|
||||
}
|
||||
|
||||
void pushTodo(Graph.Block block) {
|
||||
LabelRef blockRef = block.getLabel();
|
||||
Scope blockScope = getProgramScope().getSymbol(blockRef).getScope();
|
||||
|
@ -1,10 +1,10 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.GraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
|
||||
import dk.camelot64.kickc.model.symbols.Label;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.symbols.Scope;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
import dk.camelot64.kickc.model.values.RValue;
|
||||
|
||||
@ -100,10 +100,19 @@ public class PassNCullEmptyBlocks extends Pass2SsaOptimization {
|
||||
}
|
||||
replaceLabels(predecessor, replace);
|
||||
}
|
||||
getGraph().getAllBlocks().remove(removeBlock);
|
||||
|
||||
|
||||
|
||||
LabelRef removeBlockLabelRef = removeBlock.getLabel();
|
||||
Label removeBlockLabel = getProgramScope().getLabel(removeBlockLabelRef);
|
||||
removeBlockLabel.getScope().remove(removeBlockLabel);
|
||||
final Scope removeBlockScope = removeBlockLabel.getScope();
|
||||
final Procedure procedure = removeBlockScope.getProcedure();
|
||||
final ProcedureCompilation procedureCompilation = getProgram().getProcedureCompilation(procedure.getRef());
|
||||
final List<Graph.Block> updatedBlocks = new ArrayList<>(procedureCompilation.getGraph().getAllBlocks());
|
||||
updatedBlocks.removeIf(block -> block.getLabel().equals(removeBlockLabelRef));
|
||||
procedureCompilation.setGraph(new ControlFlowGraph(updatedBlocks));
|
||||
|
||||
removeBlockScope.remove(removeBlockLabel);
|
||||
if(!pass1)
|
||||
getLog().append("Culled Empty Block " + removeBlockLabel.toString(getProgram()));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user