1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-12-03 13:49:25 +00:00

#815 working on moving control flow graphs into procedure compilation.

This commit is contained in:
jespergravgaard 2023-04-09 22:49:53 +02:00
parent 5905c1d5b6
commit 1fad48f8bc
15 changed files with 214 additions and 173 deletions

View File

@ -11,19 +11,19 @@ import java.util.*;
*/ */
public class ControlFlowGraph implements Graph { public class ControlFlowGraph implements Graph {
private List<ControlFlowBlock> blocks; private List<Graph.Block> blocks;
/** /**
* Sequence of blocks used when generating ASM * Sequence of blocks used when generating ASM
*/ */
private List<LabelRef> sequence; private List<LabelRef> sequence;
public ControlFlowGraph(List<ControlFlowBlock> blocks) { public ControlFlowGraph(List<Graph.Block> blocks) {
this.blocks = blocks; this.blocks = blocks;
} }
public ControlFlowBlock getBlock(LabelRef symbol) { public Graph.Block getBlock(LabelRef symbol) {
for(ControlFlowBlock block : blocks) { for(var block : blocks) {
if(block.getLabel().equals(symbol)) { if(block.getLabel().equals(symbol)) {
return block; return block;
} }
@ -31,7 +31,7 @@ public class ControlFlowGraph implements Graph {
return null; return null;
} }
public void addBlock(ControlFlowBlock block) { public void addBlock(Graph.Block block) {
blocks.add(block); blocks.add(block);
} }
@ -39,14 +39,10 @@ public class ControlFlowGraph implements Graph {
return Collections.unmodifiableList(blocks); return Collections.unmodifiableList(blocks);
} }
public void setAllBlocks(List<ControlFlowBlock> blocks) {
this.blocks = blocks;
}
public void remove(LabelRef label) { public void remove(LabelRef label) {
ListIterator<ControlFlowBlock> blocksIt = blocks.listIterator(); ListIterator<Graph.Block> blocksIt = blocks.listIterator();
while(blocksIt.hasNext()) { while(blocksIt.hasNext()) {
ControlFlowBlock block = blocksIt.next(); var block = blocksIt.next();
if(block.getLabel().equals(label)) { if(block.getLabel().equals(label)) {
blocksIt.remove(); blocksIt.remove();
return; 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 @Override
public String toString() { public String toString() {
return toString(null); return toString(null);
@ -95,7 +74,7 @@ public class ControlFlowGraph implements Graph {
* Clear all statement indices, * Clear all statement indices,
*/ */
public void clearStatementIndices() { public void clearStatementIndices() {
for(Graph.Block block : getAllBlocks()) { for(var block : getAllBlocks()) {
for(Statement statement : block.getStatements()) { for(Statement statement : block.getStatements()) {
statement.setIndex(null); statement.setIndex(null);
} }

View File

@ -16,6 +16,8 @@ public interface Graph {
List<Block> getAllBlocks(); List<Block> getAllBlocks();
void addBlock(Graph.Block block);
default List<Graph.Block> getPredecessors(Graph.Block block) { default List<Graph.Block> getPredecessors(Graph.Block block) {
ArrayList<Block> predecessorBlocks = new ArrayList<>(); ArrayList<Block> predecessorBlocks = new ArrayList<>();
for(Graph.Block other : getAllBlocks()) { for(Graph.Block other : getAllBlocks()) {

View File

@ -4,7 +4,6 @@ import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.OutputFileManager; import dk.camelot64.kickc.OutputFileManager;
import dk.camelot64.kickc.asm.AsmProgram; import dk.camelot64.kickc.asm.AsmProgram;
import dk.camelot64.kickc.fragment.synthesis.AsmFragmentTemplateMasterSynthesizer; 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.statements.StatementPhiBlock;
import dk.camelot64.kickc.model.symbols.*; import dk.camelot64.kickc.model.symbols.*;
import dk.camelot64.kickc.model.values.LabelRef; import dk.camelot64.kickc.model.values.LabelRef;
@ -158,12 +157,17 @@ public class Program {
@Override @Override
public List<Block> getAllBlocks() { 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(); return procedureCompilations.values();
} }

View File

@ -34,6 +34,19 @@ public abstract class Scope implements Symbol {
setFullName(); 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() { private void setFullName() {
String scopeName = (parentScope == null) ? "" : parentScope.getFullName(); String scopeName = (parentScope == null) ? "" : parentScope.getFullName();
fullName = (scopeName.length() > 0) ? scopeName + "::" + name : name; fullName = (scopeName.length() > 0) ? scopeName + "::" + name : name;

View File

@ -1,9 +1,6 @@
package dk.camelot64.kickc.passes; package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.CompileError; import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.ProcedureCompilation;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.symbols.Label; import dk.camelot64.kickc.model.symbols.Label;
import dk.camelot64.kickc.model.symbols.Procedure; import dk.camelot64.kickc.model.symbols.Procedure;
@ -29,7 +26,7 @@ public class Pass1AssertProcedureDefined extends Pass1Base {
final ProcedureCompilation procedureCompilation = getProgram().getProcedureCompilation(procedure.getRef()); final ProcedureCompilation procedureCompilation = getProgram().getProcedureCompilation(procedure.getRef());
if(procedureCompilation == null) if(procedureCompilation == null)
throw new CompileError("Error! Function body is never defined: " + procedure.getFullName()); 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) if(procedureBlock == null)
throw new CompileError("Error! Function body is never defined: " + procedure.getFullName()); throw new CompileError("Error! Function body is never defined: " + procedure.getFullName());
} }

View File

@ -31,7 +31,7 @@ public class Pass1AssertReturn extends Pass1Base {
final ProcedureCompilation procedureCompilation = getProgram().getProcedureCompilation(procedure.getRef()); final ProcedureCompilation procedureCompilation = getProgram().getProcedureCompilation(procedure.getRef());
final ControlFlowGraph graph = procedureCompilation.getGraph(); final ControlFlowGraph graph = procedureCompilation.getGraph();
LabelRef entryLabel = procedure.getRef().getLabelRef(); LabelRef entryLabel = procedure.getRef().getLabelRef();
ControlFlowBlock entryBlock = graph.getBlock(entryLabel); Graph.Block entryBlock = graph.getBlock(entryLabel);
assertReturn(graph, entryBlock, new LinkedHashSet<>()); assertReturn(graph, entryBlock, new LinkedHashSet<>());
} }
} }
@ -45,25 +45,23 @@ public class Pass1AssertReturn extends Pass1Base {
* @param block The block to examine * @param block The block to examine
* @param visited Blocks already visited * @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())) { if(visited.contains(block.getLabel())) {
return; return;
} }
visited.add(block.getLabel()); visited.add(block.getLabel());
for(Statement statement : block.getStatements()) { for(Statement statement : block.getStatements()) {
if(statement instanceof StatementAssignment) { if(statement instanceof StatementAssignment assignment) {
StatementAssignment assignment = (StatementAssignment) statement;
if(assignment.getlValue() instanceof VariableRef && ((VariableRef) assignment.getlValue()).getLocalName().equals("return")) { if(assignment.getlValue() instanceof VariableRef && ((VariableRef) assignment.getlValue()).getLocalName().equals("return")) {
// Happy days - return found! // Happy days - return found!
return; return;
} }
} else if(statement instanceof StatementConditionalJump) { } else if(statement instanceof StatementConditionalJump cond) {
StatementConditionalJump cond = (StatementConditionalJump) statement; Graph.Block jumpTo = graph.getBlock(cond.getDestination());
ControlFlowBlock jumpTo = graph.getBlock(cond.getDestination());
assertReturn(graph, jumpTo, visited); 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)) { 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())); throw new CompileError("Error! Method must end with a return statement. " + block.getScope().toString(getProgram()));
} else { } else {

View File

@ -15,18 +15,28 @@ import java.util.*;
/** Handle calling convention {@link Procedure.CallingConvention#PHI_CALL} by passing parameters through variables */ /** Handle calling convention {@link Procedure.CallingConvention#PHI_CALL} by passing parameters through variables */
public class Pass1CallPhiParameters { public class Pass1CallPhiParameters {
private Program program; private final Program program;
public Pass1CallPhiParameters(Program program) { public Pass1CallPhiParameters(Program program) {
this.program = program; this.program = program;
} }
private Map<LabelRef, LabelRef> splitBlockMap = new LinkedHashMap<>();
public void execute() { 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<>(); List<Graph.Block> doneBlocks = new ArrayList<>();
Map<LabelRef, LabelRef> splitBlockMap = new LinkedHashMap<>();
while(!todoBlocks.isEmpty()) { while(!todoBlocks.isEmpty()) {
final Graph.Block block = todoBlocks.get(0); final Graph.Block block = todoBlocks.get(0);
todoBlocks.remove(0); todoBlocks.remove(0);
@ -35,14 +45,13 @@ public class Pass1CallPhiParameters {
final ListIterator<Statement> stmtIt = block.getStatements().listIterator(); final ListIterator<Statement> stmtIt = block.getStatements().listIterator();
while(stmtIt.hasNext()) { while(stmtIt.hasNext()) {
Statement statement = stmtIt.next(); Statement statement = stmtIt.next();
if(statement instanceof StatementCall) { if(statement instanceof StatementCall call) {
StatementCall call = (StatementCall) statement;
// Generate parameter passing assignments // Generate parameter passing assignments
ProcedureRef procedureRef = call.getProcedure(); ProcedureRef procedureRef = call.getProcedure();
Procedure procedure = getScope().getProcedure(procedureRef); Procedure procedure = getScope().getProcedure(procedureRef);
// Handle PHI-calls // Handle PHI-calls
if(Procedure.CallingConvention.PHI_CALL.equals(procedure.getCallingConvention())) { 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 // The current block was split into two blocks - add the new block at the front of the todoBlocks
todoBlocks.add(0, newBlock); todoBlocks.add(0, newBlock);
} }
@ -57,18 +66,19 @@ public class Pass1CallPhiParameters {
for(VariableRef modifiedVar : modifiedVars) { for(VariableRef modifiedVar : modifiedVars) {
if(getScope().getVariable(modifiedVar).isKindLoadStore()) if(getScope().getVariable(modifiedVar).isKindLoadStore())
continue; 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(); stmtIt.next();
} }
} }
} }
} }
// Update graph blocks to include the new blocks added // 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 // 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()) { if(block.hasPhiBlock()) {
for(StatementPhiBlock.PhiVariable phiVariable : block.getPhiBlock().getPhiVariables()) { for(StatementPhiBlock.PhiVariable phiVariable : block.getPhiBlock().getPhiVariables()) {
for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) { for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
@ -86,11 +96,7 @@ public class Pass1CallPhiParameters {
return program.getScope(); return program.getScope();
} }
private Graph getGraph() { private ControlFlowBlock handlePhiCall(StatementCall call, Procedure procedure, ListIterator<Statement> stmtIt, Graph.Block block, Map<LabelRef, LabelRef> splitBlockMap) {
return program.getGraph();
}
private ControlFlowBlock handlePhiCall(StatementCall call, Procedure procedure, ListIterator<Statement> stmtIt, Graph.Block block) {
List<Variable> parameterDefs = procedure.getParameters(); List<Variable> parameterDefs = procedure.getParameters();
List<RValue> parameterValues = call.getParameters(); List<RValue> parameterValues = call.getParameters();

View File

@ -32,10 +32,10 @@ public class Pass1GenerateControlFlowGraph extends Pass1Base {
// Empty procedures should not produce any blocks // Empty procedures should not produce any blocks
continue; continue;
List<ControlFlowBlock> blocks = new ArrayList<>(); List<Graph.Block> blocks = new ArrayList<>();
ControlFlowBlock currentBlock = null; Graph.Block currentBlock;
ControlFlowBlock procBlock = getOrCreateBlock(procedure.getLabel().getRef(), procedure.getRef(), blocks); Graph.Block procBlock = getOrCreateBlock(procedure.getLabel().getRef(), procedure.getRef(), blocks);
currentBlock = procBlock; currentBlock = procBlock;
for(Statement statement : sequence.getStatements()) { for(Statement statement : sequence.getStatements()) {
Symbol currentBlockLabel = getProgram().getScope().getSymbol(currentBlock.getLabel()); Symbol currentBlockLabel = getProgram().getScope().getSymbol(currentBlock.getLabel());
@ -50,29 +50,25 @@ public class Pass1GenerateControlFlowGraph extends Pass1Base {
} else if(statement instanceof StatementProcedureEnd) { } else if(statement instanceof StatementProcedureEnd) {
// Procedure strategy implemented is currently variable-based transfer of parameters/return values // Procedure strategy implemented is currently variable-based transfer of parameters/return values
currentBlock.setDefaultSuccessor(new Label(SymbolRef.PROCEXIT_BLOCK_NAME, programScope, false).getRef()); currentBlock.setDefaultSuccessor(new Label(SymbolRef.PROCEXIT_BLOCK_NAME, programScope, false).getRef());
} else if(statement instanceof StatementLabel) { } else if(statement instanceof StatementLabel statementLabel) {
StatementLabel statementLabel = (StatementLabel) statement; Graph.Block nextBlock = getOrCreateBlock(statementLabel.getLabel(), currentBlock.getScope(), blocks);
ControlFlowBlock nextBlock = getOrCreateBlock(statementLabel.getLabel(), currentBlock.getScope(), blocks);
nextBlock.setComments(statementLabel.getComments()); nextBlock.setComments(statementLabel.getComments());
currentBlock.setDefaultSuccessor(nextBlock.getLabel()); currentBlock.setDefaultSuccessor(nextBlock.getLabel());
currentBlock = nextBlock; currentBlock = nextBlock;
} else if(statement instanceof StatementJump) { } else if(statement instanceof StatementJump statementJump) {
StatementJump statementJump = (StatementJump) statement; Graph.Block jmpBlock = getOrCreateBlock(statementJump.getDestination(), currentBlock.getScope(), blocks);
ControlFlowBlock jmpBlock = getOrCreateBlock(statementJump.getDestination(), currentBlock.getScope(), blocks);
currentBlock.setDefaultSuccessor(jmpBlock.getLabel()); 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; currentBlock = nextBlock;
} else if(statement instanceof StatementConditionalJump) { } else if(statement instanceof StatementConditionalJump statementConditionalJump) {
currentBlock.addStatement(statement); currentBlock.addStatement(statement);
StatementConditionalJump statementConditionalJump = (StatementConditionalJump) statement; Graph.Block jmpBlock = getOrCreateBlock(statementConditionalJump.getDestination(), currentBlock.getScope(), blocks);
ControlFlowBlock jmpBlock = getOrCreateBlock(statementConditionalJump.getDestination(), currentBlock.getScope(), blocks); Graph.Block nextBlock = getOrCreateBlock(currentBlockScope.addLabelIntermediate().getRef(), currentBlock.getScope(), blocks);
ControlFlowBlock nextBlock = getOrCreateBlock(currentBlockScope.addLabelIntermediate().getRef(), currentBlock.getScope(), blocks);
currentBlock.setDefaultSuccessor(nextBlock.getLabel()); currentBlock.setDefaultSuccessor(nextBlock.getLabel());
currentBlock.setConditionalSuccessor(jmpBlock.getLabel()); currentBlock.setConditionalSuccessor(jmpBlock.getLabel());
currentBlock = nextBlock; 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 // Procedure strategy implemented is currently variable-based transfer of parameters/return values
StatementReturn aReturn = (StatementReturn) statement;
currentBlock.addStatement(aReturn); currentBlock.addStatement(aReturn);
} else { } else {
currentBlock.addStatement(statement); currentBlock.addStatement(statement);
@ -85,13 +81,13 @@ public class Pass1GenerateControlFlowGraph extends Pass1Base {
return false; return false;
} }
private ControlFlowBlock getOrCreateBlock(LabelRef label, ScopeRef scope, List<ControlFlowBlock> blocks) { private Graph.Block getOrCreateBlock(LabelRef label, ScopeRef scope, List<Graph.Block> blocks) {
for(ControlFlowBlock block : blocks) { for(var block : blocks) {
if(block.getLabel().equals(label)) { if(block.getLabel().equals(label)) {
return block; return block;
} }
} }
ControlFlowBlock block = new ControlFlowBlock(label, scope); Graph.Block block = new ControlFlowBlock(label, scope);
blocks.add(block); blocks.add(block);
return block; return block;
} }

View File

@ -23,16 +23,23 @@ public class Pass1ProcedureInline extends Pass1Base {
@Override @Override
public boolean step() { public boolean step() {
List<Graph.Block> allBlocks = getGraph().getAllBlocks(); for(var procedureCompilation : getProgram().getProcedureCompilations())
ListIterator<Graph.Block> blocksIt = allBlocks.listIterator(); 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()) { while(blocksIt.hasNext()) {
Graph.Block block = blocksIt.next(); Graph.Block block = blocksIt.next();
List<Statement> blockStatements = block.getStatements(); List<Statement> blockStatements = block.getStatements();
ListIterator<Statement> statementsIt = blockStatements.listIterator(); ListIterator<Statement> statementsIt = blockStatements.listIterator();
while(statementsIt.hasNext()) { while(statementsIt.hasNext()) {
Statement statement = statementsIt.next(); Statement statement = statementsIt.next();
if(statement instanceof StatementCall) { if(statement instanceof StatementCall call) {
StatementCall call = (StatementCall) statement;
ProcedureRef procedureRef = call.getProcedure(); ProcedureRef procedureRef = call.getProcedure();
Procedure procedure = getProgramScope().getProcedure(procedureRef); Procedure procedure = getProgramScope().getProcedure(procedureRef);
if(procedure.isDeclaredInline()) { if(procedure.isDeclaredInline()) {
@ -41,6 +48,8 @@ public class Pass1ProcedureInline extends Pass1Base {
throw new CompileError("Error! Interrupts cannot be inlined. "+procedure.getRef().toString()); throw new CompileError("Error! Interrupts cannot be inlined. "+procedure.getRef().toString());
} }
inlineProcedureCall(call, procedure, statementsIt, block, blocksIt); inlineProcedureCall(call, procedure, statementsIt, block, blocksIt);
// Update the procedure graph
procedureCompilation.setGraph(new ControlFlowGraph(procedureBlocks));
// Exit and restart // Exit and restart
return true; return true;
} }
@ -184,24 +193,17 @@ public class Pass1ProcedureInline extends Pass1Base {
*/ */
private Statement inlineStatement(Statement procStatement, Procedure procedure, Scope callScope, int serial) { private Statement inlineStatement(Statement procStatement, Procedure procedure, Scope callScope, int serial) {
Statement inlinedStatement; Statement inlinedStatement;
if(procStatement instanceof StatementAssignment) { if(procStatement instanceof StatementAssignment procAssignment) {
StatementAssignment procAssignment = (StatementAssignment) procStatement;
inlinedStatement = new StatementAssignment(procAssignment.getlValue(), procAssignment.getrValue1(), procAssignment.getOperator(), procAssignment.getrValue2(), procAssignment.isInitialAssignment(), procAssignment.getSource(), Comment.NO_COMMENTS); inlinedStatement = new StatementAssignment(procAssignment.getlValue(), procAssignment.getrValue1(), procAssignment.getOperator(), procAssignment.getrValue2(), procAssignment.isInitialAssignment(), procAssignment.getSource(), Comment.NO_COMMENTS);
} else if(procStatement instanceof StatementCall) { } else if(procStatement instanceof StatementCall procCall) {
StatementCall procCall = (StatementCall) procStatement;
StatementCall inlinedCall = new StatementCall(procCall.getlValue(), procCall.getProcedureName(), new ArrayList<>(procCall.getParameters()), procCall.getSource(), procCall.getComments()); StatementCall inlinedCall = new StatementCall(procCall.getlValue(), procCall.getProcedureName(), new ArrayList<>(procCall.getParameters()), procCall.getSource(), procCall.getComments());
inlinedCall.setProcedure(procCall.getProcedure()); inlinedCall.setProcedure(procCall.getProcedure());
inlinedStatement = inlinedCall; inlinedStatement = inlinedCall;
} else if(procStatement instanceof StatementAsm) { } else if(procStatement instanceof StatementAsm procAsm) {
StatementAsm procAsm = (StatementAsm) procStatement; inlinedStatement = new StatementAsm(procAsm.getAsmLines(), new LinkedHashMap<>(procAsm.getReferenced()), procAsm.getDeclaredClobber(), procAsm.getSource(), Comment.NO_COMMENTS);
StatementAsm inlinedAsm = new StatementAsm(procAsm.getAsmLines(), new LinkedHashMap<>(procAsm.getReferenced()), procAsm.getDeclaredClobber(), procAsm.getSource(), Comment.NO_COMMENTS); } else if(procStatement instanceof StatementKickAsm procKasm) {
inlinedStatement = inlinedAsm; inlinedStatement = new StatementKickAsm(procKasm.getKickAsmCode(), procKasm.getBytes(), procKasm.getCycles(), procKasm.getUses(), procKasm.getDeclaredClobber(), procKasm.getSource(), Comment.NO_COMMENTS);
} else if(procStatement instanceof StatementKickAsm) { } else if(procStatement instanceof StatementConditionalJump procConditional) {
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;
LabelRef procDestinationRef = procConditional.getDestination(); LabelRef procDestinationRef = procConditional.getDestination();
Label procDestination = getProgramScope().getLabel(procDestinationRef); Label procDestination = getProgramScope().getLabel(procDestinationRef);
Label inlinedDest = procDestination; Label inlinedDest = procDestination;
@ -218,9 +220,7 @@ public class Pass1ProcedureInline extends Pass1Base {
} else { } else {
throw new CompileError("Statement type of Inline function not handled " + procStatement, procStatement.getSource()); 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; return inlinedStatement;
} }
@ -246,8 +246,7 @@ public class Pass1ProcedureInline extends Pass1Base {
@Override @Override
public void execute(ProgramValue programValue, Statement currentStmt, ListIterator<Statement> stmtIt, Graph.Block currentBlock) { public void execute(ProgramValue programValue, Statement currentStmt, ListIterator<Statement> stmtIt, Graph.Block currentBlock) {
Value rValue = programValue.get(); Value rValue = programValue.get();
if(rValue instanceof VariableRef) { if(rValue instanceof VariableRef procVarRef) {
VariableRef procVarRef = (VariableRef) rValue;
Variable procVar = Pass1ProcedureInline.this.getProgramScope().getVariable(procVarRef); Variable procVar = Pass1ProcedureInline.this.getProgramScope().getVariable(procVarRef);
if(procVar.getScope().equals(procedure)) { if(procVar.getScope().equals(procedure)) {
String inlineSymbolName = Pass1ProcedureInline.this.getInlineSymbolName(procedure, procVar, serial); String inlineSymbolName = Pass1ProcedureInline.this.getInlineSymbolName(procedure, procVar, serial);
@ -299,8 +298,7 @@ public class Pass1ProcedureInline extends Pass1Base {
callScope.addLabel(procedure.getLocalName() + serial); callScope.addLabel(procedure.getLocalName() + serial);
// And copy all procedure symbols // And copy all procedure symbols
for(Symbol procSymbol : procedure.getAllSymbols()) { for(Symbol procSymbol : procedure.getAllSymbols()) {
if(procSymbol instanceof Variable) { if(procSymbol instanceof Variable procVar) {
Variable procVar = (Variable) procSymbol;
String inlineVarName = getInlineSymbolName(procedure, procSymbol, serial); String inlineVarName = getInlineSymbolName(procedure, procSymbol, serial);
Variable inlineVar = Variable.createCopy(inlineVarName, callScope, procVar); Variable inlineVar = Variable.createCopy(inlineVarName, callScope, procVar);
callScope.add(inlineVar); callScope.add(inlineVar);

View File

@ -28,14 +28,22 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
@Override @Override
public boolean step() { 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 done = false;
boolean modified = false; boolean modified = false;
while(!done) { while(!done) {
VariableRef obsoleteConditionVar = findAndRewriteBooleanCondition(); VariableRef obsoleteConditionVar = findAndRewriteBooleanCondition(graph);
if(obsoleteConditionVar != null) { if(obsoleteConditionVar != null) {
Collection<VariableRef> obsoleteVars = new ArrayList<>(); Collection<VariableRef> obsoleteVars = new ArrayList<>();
obsoleteVars.add(obsoleteConditionVar); obsoleteVars.add(obsoleteConditionVar);
removeAssignments(getGraph(), obsoleteVars); removeAssignments(graph, obsoleteVars);
deleteSymbols(getProgramScope(), obsoleteVars); deleteSymbols(getProgramScope(), obsoleteVars);
modified = true; modified = true;
} else { } 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) * When found rewrite it (adding blocks)
* *
* @return Null if no condition was found to rewrite. The now obsolete variable containing the && / || / ! to be removed. * @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(); final VariableReferenceInfos variableReferenceInfos = getProgram().getVariableReferenceInfos();
for(var block : getGraph().getAllBlocks()) { for(var block : graph.getAllBlocks()) {
for(Statement statement : block.getStatements()) { for(Statement statement : block.getStatements()) {
if(statement instanceof StatementConditionalJump) { if(statement instanceof StatementConditionalJump conditional) {
StatementConditionalJump conditional = (StatementConditionalJump) statement;
if(conditional.getrValue1() == null && conditional.getOperator() == null) { if(conditional.getrValue1() == null && conditional.getOperator() == null) {
RValue conditionRValue = conditional.getrValue2(); RValue conditionRValue = conditional.getrValue2();
if(conditionRValue instanceof VariableRef) { if(conditionRValue instanceof VariableRef) {
@ -65,16 +73,15 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
VariableRef conditionVar = (VariableRef) conditionRValue; VariableRef conditionVar = (VariableRef) conditionRValue;
final Integer conditionDefineStatementIdx = variableReferenceInfos.getVarDefineStatement(conditionVar); final Integer conditionDefineStatementIdx = variableReferenceInfos.getVarDefineStatement(conditionVar);
if(conditionDefineStatementIdx != null) { if(conditionDefineStatementIdx != null) {
final Statement conditionDefineStatement = getGraph().getStatementByIndex(conditionDefineStatementIdx); final Statement conditionDefineStatement = graph.getStatementByIndex(conditionDefineStatementIdx);
if(conditionDefineStatement instanceof StatementAssignment) { if(conditionDefineStatement instanceof StatementAssignment conditionAssignment) {
StatementAssignment conditionAssignment = (StatementAssignment) conditionDefineStatement;
if(Operators.LOGIC_AND.equals(conditionAssignment.getOperator())) { if(Operators.LOGIC_AND.equals(conditionAssignment.getOperator())) {
// Found if() with logical && condition - rewrite to if(c1) if(c2) { xx } // Found if() with logical && condition - rewrite to if(c1) if(c2) { xx }
rewriteLogicAnd(block, conditional, conditionAssignment); rewriteLogicAnd(block, conditional, conditionAssignment, getGraph());
return conditionVar; return conditionVar;
} else if(Operators.LOGIC_OR.equals(conditionAssignment.getOperator())) { } 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: // 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; return conditionVar;
} else if(Operators.LOGIC_NOT.equals(conditionAssignment.getOperator())) { } 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: // 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 block The block containing the current if()
* @param conditional The if()-statement * @param conditional The if()-statement
* @param conditionAssignment The assignment defining the condition variable. * @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 } // 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)); getLog().append("Rewriting && if()-condition to two if()s " + conditionAssignment.toString(getProgram(), false));
ScopeRef currentScopeRef = block.getScope(); 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 // Add a new block containing the second part of the && condition expression
Label newBlockLabel = currentScope.addLabelIntermediate(); Label newBlockLabel = currentScope.addLabelIntermediate();
ControlFlowBlock newBlock = new ControlFlowBlock(newBlockLabel.getRef(), currentScopeRef); ControlFlowBlock newBlock = new ControlFlowBlock(newBlockLabel.getRef(), currentScopeRef);
getGraph().addBlock(newBlock); graph.addBlock(newBlock);
LabelRef destLabel = conditional.getDestination(); LabelRef destLabel = conditional.getDestination();
StatementConditionalJump newConditional = new StatementConditionalJump(conditionAssignment.getrValue2(), destLabel, conditional.getSource(), Comment.NO_COMMENTS); StatementConditionalJump newConditional = new StatementConditionalJump(conditionAssignment.getrValue2(), destLabel, conditional.getSource(), Comment.NO_COMMENTS);
newConditional.setDeclaredUnroll(conditional.isDeclaredUnroll()); newConditional.setDeclaredUnroll(conditional.isDeclaredUnroll());
@ -120,7 +128,7 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
conditional.setrValue2(conditionAssignment.getrValue1()); conditional.setrValue2(conditionAssignment.getrValue1());
// Replace the phi labels inside the destination block with the new block // 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<>(); LinkedHashMap<LabelRef, LabelRef> replacements = new LinkedHashMap<>();
replacements.put(block.getLabel(), newBlockLabel.getRef()); replacements.put(block.getLabel(), newBlockLabel.getRef());
replaceLabels(destBlock.getPhiBlock(), replacements); replaceLabels(destBlock.getPhiBlock(), replacements);
@ -133,15 +141,16 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
* @param block The block containing the current if() * @param block The block containing the current if()
* @param conditional The if()-statement * @param conditional The if()-statement
* @param conditionAssignment The assignment defining the condition variable. * @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)); getLog().append("Rewriting || if()-condition to two if()s " + conditionAssignment.toString(getProgram(), false));
ScopeRef currentScopeRef = block.getScope(); ScopeRef currentScopeRef = block.getScope();
Scope currentScope = getProgramScope().getScope(currentScopeRef); Scope currentScope = getProgramScope().getScope(currentScopeRef);
// Add a new block containing the second part of the && condition expression // Add a new block containing the second part of the && condition expression
Label newBlockLabel = currentScope.addLabelIntermediate(); Label newBlockLabel = currentScope.addLabelIntermediate();
ControlFlowBlock newBlock = new ControlFlowBlock(newBlockLabel.getRef(), currentScopeRef); 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); StatementConditionalJump newConditional = new StatementConditionalJump(conditionAssignment.getrValue2(), conditional.getDestination(), conditional.getSource(), Comment.NO_COMMENTS);
// Copy unrolling to the new conditional // Copy unrolling to the new conditional
newConditional.setDeclaredUnroll(conditional.isDeclaredUnroll()); newConditional.setDeclaredUnroll(conditional.isDeclaredUnroll());
@ -155,7 +164,7 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
conditional.setDeclaredUnroll(false); conditional.setDeclaredUnroll(false);
// Update the default destination PHI block to reflect the last of the conditions // 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()) { if(defaultDestBlock.hasPhiBlock()) {
StatementPhiBlock defaultDestPhiBlock = defaultDestBlock.getPhiBlock(); StatementPhiBlock defaultDestPhiBlock = defaultDestBlock.getPhiBlock();
for(StatementPhiBlock.PhiVariable phiVariable : defaultDestPhiBlock.getPhiVariables()) { 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()) { if(conditionalDestBlock.hasPhiBlock()) {
StatementPhiBlock conditionalDestPhiBlock = conditionalDestBlock.getPhiBlock(); StatementPhiBlock conditionalDestPhiBlock = conditionalDestBlock.getPhiBlock();
for(StatementPhiBlock.PhiVariable phiVariable : conditionalDestPhiBlock.getPhiVariables()) { for(StatementPhiBlock.PhiVariable phiVariable : conditionalDestPhiBlock.getPhiVariables()) {
for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) { for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
if(phiRValue.getPredecessor().equals(block.getLabel())) { 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()); phiVariable.setrValue(newBlockLabel.getRef(), phiRValue.getrValue());
break; break;
} }

View File

@ -71,7 +71,7 @@ public class Pass2ConstantInlining extends Pass2SsaOptimization {
private void removeParameters(Set<ConstantRef> inlineRefs) { private void removeParameters(Set<ConstantRef> inlineRefs) {
for(ConstantRef inlineRef : inlineRefs) { for(ConstantRef inlineRef : inlineRefs) {
final Scope scope = getProgramScope().getConstant(inlineRef).getScope(); final Scope scope = getProgramScope().getConstant(inlineRef).getScope();
final Procedure procedure = getProcedure(scope); final Procedure procedure = scope.getProcedure();
if(procedure!=null) { if(procedure!=null) {
final List<Variable> parameters = procedure.getParameters(); final List<Variable> parameters = procedure.getParameters();
final boolean modified = parameters.removeIf(param -> param.getRef().equals(inlineRef)); 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 * Replace any aliases within the constant values themselves
* *

View File

@ -1,10 +1,7 @@
package dk.camelot64.kickc.passes; package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.CompileLog; import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.model.CompileError; import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.Graph;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.statements.*; import dk.camelot64.kickc.model.statements.*;
import dk.camelot64.kickc.model.symbols.Label; import dk.camelot64.kickc.model.symbols.Label;
import dk.camelot64.kickc.model.symbols.Procedure; import dk.camelot64.kickc.model.symbols.Procedure;
@ -14,7 +11,7 @@ import dk.camelot64.kickc.model.values.*;
import java.util.*; 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 class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
public Pass2EliminateUnusedBlocks(Program program) { public Pass2EliminateUnusedBlocks(Program program) {
@ -28,9 +25,13 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
for(var block : getGraph().getAllBlocks()) { for(var block : getGraph().getAllBlocks()) {
if(!referencedBlocks.contains(block.getLabel())) { if(!referencedBlocks.contains(block.getLabel())) {
unusedBlocks.add(block.getLabel()); unusedBlocks.add(block.getLabel());
}
}
for(var block : getGraph().getAllBlocks()) {
if(unusedBlocks.contains(block.getLabel())) {
for(Statement stmt : block.getStatements()) { for(Statement stmt : block.getStatements()) {
if(stmt instanceof StatementLValue) { if(stmt instanceof StatementLValue assignment) {
StatementLValue assignment = (StatementLValue) stmt;
LValue lValue = assignment.getlValue(); LValue lValue = assignment.getlValue();
if(lValue instanceof VariableRef) { if(lValue instanceof VariableRef) {
Variable variable = getProgramScope().getVariable((VariableRef) lValue); Variable variable = getProgramScope().getVariable((VariableRef) lValue);
@ -52,12 +53,14 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
} }
} }
Set<LabelRef> removedBlocks = new HashSet<>(); Set<LabelRef> removedBlocks = new HashSet<>();
for(LabelRef unusedBlock : unusedBlocks) { for(LabelRef unusedBlock : unusedBlocks) {
Symbol unusedSymbol = getProgramScope().getSymbol(unusedBlock); Symbol unusedSymbol = getProgramScope().getSymbol(unusedBlock);
if(unusedSymbol instanceof Label) { 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 label = getProgramScope().getLabel(unusedBlock);
label.getScope().remove(label); label.getScope().remove(label);
removePhiRValues(unusedBlock, getProgram()); removePhiRValues(unusedBlock, getProgram());
@ -85,31 +88,19 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
public static void removeProcedure(ProcedureRef procedureRef, Set<LabelRef> removedBlocks, Program program) { public static void removeProcedure(ProcedureRef procedureRef, Set<LabelRef> removedBlocks, Program program) {
program.getLog().append("Removing unused procedure " + procedureRef); program.getLog().append("Removing unused procedure " + procedureRef);
Procedure unusedProcedure = program.getScope().getProcedure(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) { for(var procedureBlock : procedureBlocks) {
LabelRef blockLabelRef = procedureBlock.getLabel(); LabelRef blockLabelRef = procedureBlock.getLabel();
program.getLog().append("Removing unused procedure block " + blockLabelRef); program.getLog().append("Removing unused procedure block " + blockLabelRef);
program.getGraph().remove(blockLabelRef); procedureGraph.remove(blockLabelRef);
removePhiRValues(blockLabelRef, program); removePhiRValues(blockLabelRef, program);
removedBlocks.add(blockLabelRef); removedBlocks.add(blockLabelRef);
} }
unusedProcedure.getScope().remove(unusedProcedure); 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 * 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 * Find all referenced block labels recursively
* *

View File

@ -31,10 +31,16 @@ public class Pass3PhiLifting {
} }
public void perform() { 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(); ProgramScope programScope = program.getScope();
List<Graph.Block> blocks = graph.getAllBlocks(); ListIterator<Graph.Block> blocksIt = liftedBlocks.listIterator();
ListIterator<Graph.Block> blocksIt = blocks.listIterator();
while(blocksIt.hasNext()) { while(blocksIt.hasNext()) {
Graph.Block block = blocksIt.next(); Graph.Block block = blocksIt.next();
// Maps old predecessors to new blocks created // Maps old predecessors to new blocks created
@ -45,7 +51,11 @@ public class Pass3PhiLifting {
for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) { for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
if(!(phiRValue.getrValue() instanceof ConstantValue)) { if(!(phiRValue.getrValue() instanceof ConstantValue)) {
LabelRef predecessorRef = phiRValue.getPredecessor(); 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(); //VariableRef rValVarRef = (VariableRef) phiRValue.getrValue();
Variable newVar; Variable newVar;
if(phiVariable.getVariable().isVersion()) { 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() + ")"); program.getLog().append("Added new block during phi lifting " + newBlock.getLabel() + "(between " + predecessorRef + " and " + block.getLabel() + ")");
} else { } else {
newBlock = graph.getBlock(newBlockRef); newBlock = getBlock(liftedBlocks, newBlockRef);
} }
List<Statement> newBlockStatements = newBlock.getStatements(); List<Statement> newBlockStatements = newBlock.getStatements();
newBlockStatements.add(newAssignment); 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);
} }
} }

View File

@ -1,12 +1,12 @@
package dk.camelot64.kickc.passes; package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.ControlFlowBlock; import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.Graph;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.symbols.Scope; import dk.camelot64.kickc.model.symbols.Scope;
import dk.camelot64.kickc.model.values.LabelRef; import dk.camelot64.kickc.model.values.LabelRef;
import java.util.*; 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 */ /** Plan the optimal sequence for the blocks of the control flow graph */
public class PassNBlockSequencePlanner extends Pass2SsaOptimization { public class PassNBlockSequencePlanner extends Pass2SsaOptimization {
@ -62,7 +62,7 @@ public class PassNBlockSequencePlanner extends Pass2SsaOptimization {
} }
} }
getGraph().setSequence(sequence); setSequence(sequence);
if(getLog().isVerboseSequencePlan()) { if(getLog().isVerboseSequencePlan()) {
StringBuilder entry = new StringBuilder(); 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) { void pushTodo(Graph.Block block) {
LabelRef blockRef = block.getLabel(); LabelRef blockRef = block.getLabel();
Scope blockScope = getProgramScope().getSymbol(blockRef).getScope(); Scope blockScope = getProgramScope().getSymbol(blockRef).getScope();

View File

@ -1,10 +1,10 @@
package dk.camelot64.kickc.passes; package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.GraphBaseVisitor; import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.Graph;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.statements.StatementPhiBlock; import dk.camelot64.kickc.model.statements.StatementPhiBlock;
import dk.camelot64.kickc.model.symbols.Label; 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.LabelRef;
import dk.camelot64.kickc.model.values.RValue; import dk.camelot64.kickc.model.values.RValue;
@ -100,10 +100,19 @@ public class PassNCullEmptyBlocks extends Pass2SsaOptimization {
} }
replaceLabels(predecessor, replace); replaceLabels(predecessor, replace);
} }
getGraph().getAllBlocks().remove(removeBlock);
LabelRef removeBlockLabelRef = removeBlock.getLabel(); LabelRef removeBlockLabelRef = removeBlock.getLabel();
Label removeBlockLabel = getProgramScope().getLabel(removeBlockLabelRef); 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) if(!pass1)
getLog().append("Culled Empty Block " + removeBlockLabel.toString(getProgram())); getLog().append("Culled Empty Block " + removeBlockLabel.toString(getProgram()));
} }