diff --git a/src/main/java/dk/camelot64/kickc/Compiler.java b/src/main/java/dk/camelot64/kickc/Compiler.java index 6e0c82f0b..0929ad956 100644 --- a/src/main/java/dk/camelot64/kickc/Compiler.java +++ b/src/main/java/dk/camelot64/kickc/Compiler.java @@ -140,6 +140,8 @@ public class Compiler { new Pass1ModifiedVarsAnalysis(program).execute(); getLog().append(program.getProcedureModifiedVars().toString(program)); + new Pass1ProcedureInline(program).execute(); + new Pass1ProcedureCallParameters(program).generate(); //getLog().append("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL"); //getLog().append(program.getGraph().toString(program)); diff --git a/src/main/java/dk/camelot64/kickc/model/ControlFlowGraph.java b/src/main/java/dk/camelot64/kickc/model/ControlFlowGraph.java index b46279ca5..ecf703069 100644 --- a/src/main/java/dk/camelot64/kickc/model/ControlFlowGraph.java +++ b/src/main/java/dk/camelot64/kickc/model/ControlFlowGraph.java @@ -15,7 +15,7 @@ import java.util.*; */ public class ControlFlowGraph { - private Map blocks; + private List blocks; private LabelRef firstBlockRef; /** @@ -23,37 +23,41 @@ public class ControlFlowGraph { */ private List sequence; - public ControlFlowGraph(Map blocks, LabelRef firstBlockRef) { + public ControlFlowGraph(List blocks, LabelRef firstBlockRef) { this.blocks = blocks; this.firstBlockRef = firstBlockRef; } public ControlFlowBlock getBlock(LabelRef symbol) { - return blocks.get(symbol); + for(ControlFlowBlock block : blocks) { + if(block.getLabel().equals(symbol)) { + return block; + } + } + return null; } public void addBlock(ControlFlowBlock block) { - blocks.put(block.getLabel(), block); + blocks.add(block); } public ControlFlowBlock getFirstBlock() { return getBlock(firstBlockRef); } - public Collection getAllBlocks() { - if(sequence != null) { - ArrayList blocks = new ArrayList<>(); - for(LabelRef labelRef : sequence) { - blocks.add(getBlock(labelRef)); - } + public List getAllBlocks() { return blocks; - } else { - return blocks.values(); - } } public void remove(LabelRef label) { - blocks.remove(label); + ListIterator blocksIt = blocks.listIterator(); + while(blocksIt.hasNext()) { + ControlFlowBlock block = blocksIt.next(); + if(block.getLabel().equals(label)) { + blocksIt.remove(); + return; + } + } } /** @@ -105,7 +109,7 @@ public class ControlFlowGraph { public ControlFlowBlock getDefaultSuccessor(ControlFlowBlock block) { if(block.getDefaultSuccessor() != null) { - return blocks.get(block.getDefaultSuccessor()); + return getBlock(block.getDefaultSuccessor()); } else { return null; } @@ -113,7 +117,7 @@ public class ControlFlowGraph { public ControlFlowBlock getCallSuccessor(ControlFlowBlock block) { if(block.getCallSuccessor() != null) { - return blocks.get(block.getCallSuccessor()); + return getBlock(block.getCallSuccessor()); } else { return null; } @@ -121,7 +125,7 @@ public class ControlFlowGraph { public ControlFlowBlock getConditionalSuccessor(ControlFlowBlock block) { if(block.getConditionalSuccessor() != null) { - return blocks.get(block.getConditionalSuccessor()); + return getBlock(block.getConditionalSuccessor()); } else { return null; } @@ -150,7 +154,15 @@ public class ControlFlowGraph { } public void setSequence(List 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 seqBlocks = new ArrayList<>(); + for(LabelRef labelRef : sequence) { + seqBlocks.add(getBlock(labelRef)); + } + this.blocks = seqBlocks; } public ControlFlowBlock getMainBlock() { diff --git a/src/main/java/dk/camelot64/kickc/model/ControlFlowGraphCopyVisitor.java b/src/main/java/dk/camelot64/kickc/model/ControlFlowGraphCopyVisitor.java index 96adcee5b..a5a157de2 100644 --- a/src/main/java/dk/camelot64/kickc/model/ControlFlowGraphCopyVisitor.java +++ b/src/main/java/dk/camelot64/kickc/model/ControlFlowGraphCopyVisitor.java @@ -1,13 +1,13 @@ package dk.camelot64.kickc.model; import dk.camelot64.kickc.model.operators.Operator; +import dk.camelot64.kickc.model.statements.*; import dk.camelot64.kickc.model.values.LValue; import dk.camelot64.kickc.model.values.LabelRef; import dk.camelot64.kickc.model.values.RValue; import dk.camelot64.kickc.model.values.VariableRef; -import dk.camelot64.kickc.model.statements.*; -import java.util.LinkedHashMap; +import java.util.ArrayList; import java.util.List; /** @@ -23,7 +23,7 @@ public class ControlFlowGraphCopyVisitor extends ControlFlowGraphBaseVisitor copyBlockMap; + private List copyBlockList; /** * The current block being copied. @@ -39,15 +39,14 @@ public class ControlFlowGraphCopyVisitor extends ControlFlowGraphBaseVisitor(); + this.copyBlockList = new ArrayList<>(); for(ControlFlowBlock origBlock : origGraph.getAllBlocks()) { ControlFlowBlock copyBlock = visitBlock(origBlock); if(copyBlock != null) { - copyBlockMap.put(copyBlock.getLabel(), copyBlock); + copyBlockList.add(copyBlock); } } - ControlFlowBlock copyFirstBlock = copyBlockMap.get(origGraph.getFirstBlock().getLabel()); - ControlFlowGraph copyGraph = new ControlFlowGraph(copyBlockMap, copyFirstBlock.getLabel()); + ControlFlowGraph copyGraph = new ControlFlowGraph(copyBlockList, origGraph.getFirstBlock().getLabel()); return copyGraph; } @@ -101,7 +100,7 @@ public class ControlFlowGraphCopyVisitor extends ControlFlowGraphBaseVisitor blocks; + private List blocks; public Pass1GenerateControlFlowGraph(Program program) { super(program); @@ -23,7 +26,7 @@ public class Pass1GenerateControlFlowGraph extends Pass1Base { @Override public boolean step() { - this.blocks = new LinkedHashMap<>(); + this.blocks = new ArrayList<>(); ProgramScope scope = getScope(); StatementSequence sequence = getProgram().getStatementSequence(); ControlFlowBlock firstBlock = getOrCreateBlock(scope.addLabel(SymbolRef.BEGIN_BLOCK_NAME).getRef(), ScopeRef.ROOT); @@ -92,11 +95,13 @@ public class Pass1GenerateControlFlowGraph extends Pass1Base { } private ControlFlowBlock getOrCreateBlock(LabelRef label, ScopeRef scope) { - ControlFlowBlock block = blocks.get(label); - if(block == null) { - block = new ControlFlowBlock(label, scope); - blocks.put(block.getLabel(), block); + for(ControlFlowBlock block : blocks) { + if(block.getLabel().equals(label)) { + return block; + } } + ControlFlowBlock block = new ControlFlowBlock(label, scope); + blocks.add(block); return block; } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1ProcedureInline.java b/src/main/java/dk/camelot64/kickc/passes/Pass1ProcedureInline.java new file mode 100644 index 000000000..d94f7c19c --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1ProcedureInline.java @@ -0,0 +1,117 @@ +package dk.camelot64.kickc.passes; + +import dk.camelot64.kickc.model.*; +import dk.camelot64.kickc.model.statements.Statement; +import dk.camelot64.kickc.model.statements.StatementAssignment; +import dk.camelot64.kickc.model.statements.StatementCall; +import dk.camelot64.kickc.model.statements.StatementReturn; +import dk.camelot64.kickc.model.symbols.*; +import dk.camelot64.kickc.model.types.SymbolType; +import dk.camelot64.kickc.model.values.LValue; +import dk.camelot64.kickc.model.values.ProcedureRef; +import dk.camelot64.kickc.model.values.RValue; +import dk.camelot64.kickc.model.values.VariableRef; + +import java.util.Collection; +import java.util.List; +import java.util.ListIterator; +import java.util.Set; + +/** Pass that modifies a control flow graph to inline any procedures declared as inline */ +public class Pass1ProcedureInline extends Pass1Base { + + public Pass1ProcedureInline(Program program) { + super(program); + } + + @Override + public boolean step() { + List allBlocks = getGraph().getAllBlocks(); + for(ControlFlowBlock block : allBlocks) { + List blockStatements = block.getStatements(); + ListIterator statementsIt = blockStatements.listIterator(); + while(statementsIt.hasNext()) { + Statement statement = statementsIt.next(); + if(statement instanceof StatementCall) { + StatementCall call = (StatementCall) statement; + ProcedureRef procedureRef = call.getProcedure(); + Procedure procedure = getScope().getProcedure(procedureRef); + if(procedure.isDeclaredInline()) { + // Generate parameter assignments + // Copy all procedure blocks + // Generate return assignment + throw new CompileError("Inline functions not implemented!"); + } + } + } + } + return false; + } + + /* + public StatementCall visitCall(StatementCall origCall) { + // Procedure strategy implemented is currently variable-based transfer of parameters/return values + // Generate parameter passing assignments + ProcedureRef procedureRef = origCall.getProcedure(); + Procedure procedure = getScope().getProcedure(procedureRef); + List parameterDecls = procedure.getParameters(); + List parameterValues = origCall.getParameters(); + for(int i = 0; i < parameterDecls.size(); i++) { + Variable parameterDecl = parameterDecls.get(i); + RValue parameterValue = parameterValues.get(i); + addStatementToCurrentBlock(new StatementAssignment(parameterDecl.getRef(), parameterValue)); + } + String procedureName = origCall.getProcedureName(); + Variable procReturnVar = procedure.getVariable("return"); + VariableRef procReturnVarRef = null; + if(procReturnVar != null) { + procReturnVarRef = procReturnVar.getRef(); + } + StatementCall copyCall = new StatementCall(procReturnVarRef, procedureName, null); + copyCall.setParametersByAssignment(true); + copyCall.setProcedure(procedureRef); + addStatementToCurrentBlock(copyCall); + getCurrentBlock().setCallSuccessor(procedure.getLabel().getRef()); + Symbol currentBlockSymbol = getScope().getSymbol(getCurrentBlock().getLabel()); + Scope currentBlockScope; + if(currentBlockSymbol instanceof Procedure) { + currentBlockScope = (Scope) currentBlockSymbol; + } else { + currentBlockScope = currentBlockSymbol.getScope(); + } + splitCurrentBlock(currentBlockScope.addLabelIntermediate().getRef()); + if(!SymbolType.VOID.equals(procedure.getReturnType()) && origCall.getlValue() != null) { + addStatementToCurrentBlock(new StatementAssignment(origCall.getlValue(), procReturnVarRef)); + } else { + // No return type. Remove variable receiving the result. + LValue lValue = origCall.getlValue(); + if(lValue instanceof VariableRef) { + VariableRef lValueRef = (VariableRef) lValue; + Variable lValueVar = getScope().getVariable(lValueRef); + lValueVar.getScope().remove(lValueVar); + } + } + // Add self-assignments for all variables modified in the procedure + Set modifiedVars = program.getProcedureModifiedVars().getModifiedVars(procedure.getRef()); + for(VariableRef modifiedVar : modifiedVars) { + addStatementToCurrentBlock(new StatementAssignment(modifiedVar, modifiedVar)); + } + return null; + } + + @Override + public StatementReturn visitReturn(StatementReturn origReturn) { + ControlFlowBlock currentBlock = getCurrentBlock(); + String currentProcName = currentBlock.getLabel().getScopeNames(); + Procedure procedure = program.getScope().getProcedure(currentProcName); + // Add self-assignments for all variables modified in the procedure + Set modifiedVars = program.getProcedureModifiedVars().getModifiedVars(procedure.getRef()); + for(VariableRef modifiedVar : modifiedVars) { + addStatementToCurrentBlock(new StatementAssignment(modifiedVar, modifiedVar)); + } + return super.visitReturn(origReturn); + } + */ + + +} diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass3PhiLifting.java b/src/main/java/dk/camelot64/kickc/passes/Pass3PhiLifting.java index 92d66d546..96d7da596 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass3PhiLifting.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass3PhiLifting.java @@ -9,10 +9,7 @@ import dk.camelot64.kickc.model.statements.StatementPhiBlock; import dk.camelot64.kickc.model.symbols.*; import dk.camelot64.kickc.model.values.LabelRef; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; /** * Perform PhiLifting to greatly reduce overlapping of alive intervals for variables. @@ -35,8 +32,10 @@ public class Pass3PhiLifting { public void perform() { ControlFlowGraph graph = program.getGraph(); ProgramScope programScope = program.getScope(); - Collection blocks = graph.getAllBlocks(); - for(ControlFlowBlock block : blocks) { + List blocks = graph.getAllBlocks(); + ListIterator blocksIt = blocks.listIterator(); + while(blocksIt.hasNext()) { + ControlFlowBlock block = blocksIt.next(); // Maps old predecessors to new blocks created Map newBlocks = new HashMap<>(); if(block.hasPhiBlock()) { @@ -73,7 +72,7 @@ public class Pass3PhiLifting { Scope currentScope = programScope.getSymbol(currentBlockLabel).getScope(); Label newBlockLabel = currentScope.addLabelIntermediate(); newBlock = new ControlFlowBlock(newBlockLabel.getRef(), currentScope.getRef()); - graph.addBlock(newBlock); + blocksIt.add(newBlock); newBlock.setDefaultSuccessor(block.getLabel()); newBlocks.put(predecessorRef, newBlock.getLabel()); StatementConditionalJump previousConditionalJump = (StatementConditionalJump) lastPredecessorStatement;