diff --git a/src/main/java/dk/camelot64/kickc/Compiler.java b/src/main/java/dk/camelot64/kickc/Compiler.java index f6aaa2e51..d5892af01 100644 --- a/src/main/java/dk/camelot64/kickc/Compiler.java +++ b/src/main/java/dk/camelot64/kickc/Compiler.java @@ -155,6 +155,10 @@ public class Compiler { new Pass1FixLValuesLoHi(program).execute(); new Pass1AssertNoLValueIntermediate(program).execute(); new Pass1AddTypePromotions(program).execute(); + + new PassNStatementIndices(program).step(); + new PassNCallGraphAnalysis(program).step(); + new Pass1AssertNoRecursion(program).execute(); new Pass1AssertInterrupts(program).execute(); @@ -347,7 +351,7 @@ public class Compiler { new PassNStatementIndices(program).execute(); getLog().append("CALL GRAPH"); - new Pass3CallGraphAnalysis(program).findCallGraph(); + new PassNCallGraphAnalysis(program).step(); getLog().append(program.getCallGraph().toString()); //getLog().setVerboseLiveRanges(true); @@ -367,7 +371,7 @@ public class Compiler { new PassNBlockSequencePlanner(program).step(); new Pass3AddNopBeforeCallOns(program).generate(); new PassNStatementIndices(program).execute(); - new Pass3CallGraphAnalysis(program).findCallGraph(); + new PassNCallGraphAnalysis(program).step(); new PassNStatementInfos(program).execute(); new PassNVariableReferenceInfos(program).execute(); new Pass3SymbolInfos(program).generateSymbolInfos(); diff --git a/src/main/java/dk/camelot64/kickc/model/CallGraph.java b/src/main/java/dk/camelot64/kickc/model/CallGraph.java index cb2ded560..0f4668183 100644 --- a/src/main/java/dk/camelot64/kickc/model/CallGraph.java +++ b/src/main/java/dk/camelot64/kickc/model/CallGraph.java @@ -1,7 +1,9 @@ package dk.camelot64.kickc.model; import dk.camelot64.kickc.model.statements.StatementCall; -import dk.camelot64.kickc.model.values.LabelRef; +import dk.camelot64.kickc.model.values.ProcedureRef; +import dk.camelot64.kickc.model.values.ScopeRef; +import dk.camelot64.kickc.passes.PassNCallGraphAnalysis; import java.util.ArrayList; import java.util.Collection; @@ -10,7 +12,7 @@ import java.util.List; /** * The call graph for the entire control flow graph. - * Created by {@link dk.camelot64.kickc.passes.Pass3CallGraphAnalysis} + * Created by {@link PassNCallGraphAnalysis} */ public class CallGraph { @@ -26,7 +28,7 @@ public class CallGraph { * @param scopeLabel The label for the scope. * @return The call block for the scope */ - public CallBlock getOrCreateCallBlock(LabelRef scopeLabel) { + public CallBlock getOrCreateCallBlock(ScopeRef scopeLabel) { CallBlock callBlock = getCallBlock(scopeLabel); if(callBlock != null) { return callBlock; @@ -43,7 +45,7 @@ public class CallGraph { * @param scopeLabel The label for the scope. * @return The call block for the scope. Null if the call block does not exist (no calls are made from it). */ - public CallBlock getCallBlock(LabelRef scopeLabel) { + public CallBlock getCallBlock(ScopeRef scopeLabel) { for(CallBlock callBlock : callBlocks) { if(callBlock.getScopeLabel().equals(scopeLabel)) { return callBlock; @@ -52,8 +54,8 @@ public class CallGraph { return null; } - public LabelRef getFirstCallBlock() { - return new LabelRef(""); + public ScopeRef getFirstCallBlock() { + return ScopeRef.ROOT; } /** @@ -63,9 +65,9 @@ public class CallGraph { * @return The sub call blocks called from the passed block */ public Collection getCalledBlocks(CallBlock block) { - Collection calledLabels = block.getCalledBlocks(); + Collection calledLabels = block.getCalledBlocks(); LinkedHashSet called = new LinkedHashSet<>(); - for(LabelRef calledLabel : calledLabels) { + for(ScopeRef calledLabel : calledLabels) { called.add(getOrCreateCallBlock(calledLabel)); } return called; @@ -77,8 +79,8 @@ public class CallGraph { * @param scopeLabel The label of scope (the call block) * @return The scope labels of call blocks that call the passed block */ - public Collection getCallingBlocks(LabelRef scopeLabel) { - ArrayList callingBlocks = new ArrayList<>(); + public Collection getCallingBlocks(ScopeRef scopeLabel) { + ArrayList callingBlocks = new ArrayList<>(); for(CallBlock callBlock : callBlocks) { if(callBlock.getCalledBlocks().contains(scopeLabel)) { callingBlocks.add(callBlock.getScopeLabel()); @@ -102,7 +104,7 @@ public class CallGraph { * @param label The label of the procedure * @return All calls */ - public Collection getCallers(LabelRef label) { + public Collection getCallers(ScopeRef label) { Collection callers = new ArrayList<>(); for(CallBlock callBlock : callBlocks) { for(CallBlock.Call call : callBlock.getCalls()) { @@ -122,20 +124,20 @@ public class CallGraph { /** * The label of the scope. (Program scope has label "" and procedure scopes have their respective labels). */ - private LabelRef scopeLabel; + private ScopeRef scopeLabel; private List calls; - public CallBlock(LabelRef scopeLabel) { + public CallBlock(ScopeRef scopeLabel) { this.scopeLabel = scopeLabel; this.calls = new ArrayList<>(); } - public LabelRef getScopeLabel() { + public ScopeRef getScopeLabel() { return scopeLabel; } - public void addCall(LabelRef procedureLabel, StatementCall statementCall) { + public void addCall(ProcedureRef procedureLabel, StatementCall statementCall) { this.calls.add(new Call(procedureLabel, statementCall)); } @@ -144,8 +146,8 @@ public class CallGraph { * * @return The scope labels of all call blocks called from this one. */ - public Collection getCalledBlocks() { - LinkedHashSet called = new LinkedHashSet<>(); + public Collection getCalledBlocks() { + LinkedHashSet called = new LinkedHashSet<>(); for(Call call : calls) { called.add(call.getProcedure()); } @@ -177,7 +179,7 @@ public class CallGraph { * @param scope The scope label of the block * @return All calls to the passed scope */ - public Collection getCalls(LabelRef scope) { + public Collection getCalls(ScopeRef scope) { ArrayList callsToScope = new ArrayList<>(); for(Call call : calls) { if(call.getProcedure().equals(scope)) { @@ -200,14 +202,14 @@ public class CallGraph { /** * The label of the called procedure. */ - private LabelRef procedure; + private ProcedureRef procedure; - public Call(LabelRef procedure, StatementCall statementCall) { + Call(ProcedureRef procedure, StatementCall statementCall) { this.callStatementIdx = statementCall.getIndex(); this.procedure = procedure; } - public LabelRef getProcedure() { + public ProcedureRef getProcedure() { return procedure; } diff --git a/src/main/java/dk/camelot64/kickc/model/LiveRangeVariables.java b/src/main/java/dk/camelot64/kickc/model/LiveRangeVariables.java index 6f1beb7f2..689f1ff16 100644 --- a/src/main/java/dk/camelot64/kickc/model/LiveRangeVariables.java +++ b/src/main/java/dk/camelot64/kickc/model/LiveRangeVariables.java @@ -2,6 +2,8 @@ package dk.camelot64.kickc.model; import dk.camelot64.kickc.model.values.VariableRef; import dk.camelot64.kickc.model.statements.Statement; +import dk.camelot64.kickc.passes.Pass3LiveRangesAnalysis; +import dk.camelot64.kickc.passes.PassNCallGraphAnalysis; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -9,7 +11,7 @@ import java.util.List; /** * Live ranges for all variables. - * Created by {@link dk.camelot64.kickc.passes.Pass3CallGraphAnalysis} + * Created by {@link Pass3LiveRangesAnalysis} */ public class LiveRangeVariables { diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass3LiveRangesAnalysis.java b/src/main/java/dk/camelot64/kickc/passes/Pass3LiveRangesAnalysis.java index e36f11f19..5b0c0a47a 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass3LiveRangesAnalysis.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass3LiveRangesAnalysis.java @@ -229,7 +229,7 @@ public class Pass3LiveRangesAnalysis extends Pass2Base { ControlFlowBlock block = getProgram().getStatementInfos().getBlock(statement); if(block.isProcedureEntry(getProgram())) { // Current is first statement of a call - add the statement preceding the call. - Collection callers = getProgram().getCallGraph().getCallers(block.getLabel()); + Collection callers = getProgram().getCallGraph().getCallers(block.getScope()); for(CallGraph.CallBlock.Call call : callers) { Statement callStmt = getProgram().getStatementInfos().getStatement(call.getCallStatementIdx()); Collection precedingCallStmt = getPrecedingStatement(callStmt); diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass3LiveRangesEffectiveAnalysis.java b/src/main/java/dk/camelot64/kickc/passes/Pass3LiveRangesEffectiveAnalysis.java index 81ad08830..780b4d945 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass3LiveRangesEffectiveAnalysis.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass3LiveRangesEffectiveAnalysis.java @@ -72,7 +72,7 @@ public class Pass3LiveRangesEffectiveAnalysis extends Pass2Base { } Collection callers = - getProgram().getCallGraph().getCallers(procedure.getLabel().getRef()); + getProgram().getCallGraph().getCallers(procedure.getRef()); for(CallGraph.CallBlock.Call caller : callers) { // Each caller creates its own call-paths StatementCall callStatement = diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass3LoopDepthAnalysis.java b/src/main/java/dk/camelot64/kickc/passes/Pass3LoopDepthAnalysis.java index 256c069fc..4fb6ec931 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass3LoopDepthAnalysis.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass3LoopDepthAnalysis.java @@ -1,9 +1,8 @@ package dk.camelot64.kickc.passes; import dk.camelot64.kickc.model.*; -import dk.camelot64.kickc.model.symbols.Label; -import dk.camelot64.kickc.model.symbols.Procedure; import dk.camelot64.kickc.model.values.LabelRef; +import dk.camelot64.kickc.model.values.ScopeRef; import java.util.*; @@ -27,25 +26,28 @@ public class Pass3LoopDepthAnalysis extends Pass2Base { * Uses the call graph and natural loops of the control flow graph. */ public void findLoopDepths() { - Deque todo = new ArrayDeque<>(); - Set done = new LinkedHashSet<>(); + Deque todo = new ArrayDeque<>(); + Set done = new LinkedHashSet<>(); List entryPointBlocks = getGraph().getEntryPointBlocks(getProgram()); for(ControlFlowBlock entryPointBlock : entryPointBlocks) { LabelRef label = entryPointBlock.getLabel(); + ScopeRef scope; if(label.getFullName().equals(LabelRef.BEGIN_BLOCK_NAME)) { - label = callGraph.getFirstCallBlock(); + scope = callGraph.getFirstCallBlock(); + } else { + scope = entryPointBlock.getScope(); } - todo.push(label); + todo.push(scope); } while(!todo.isEmpty()) { - LabelRef currentScope = todo.pop(); + ScopeRef currentScope = todo.pop(); done.add(currentScope); CallGraph.CallBlock currentCallBlock = callGraph.getOrCreateCallBlock(currentScope); // Add called sub blocks for later processing - Collection subBlocks = currentCallBlock.getCalledBlocks(); - for(LabelRef subBlock : subBlocks) { + Collection subBlocks = currentCallBlock.getCalledBlocks(); + for(ScopeRef subBlock : subBlocks) { if(!done.contains(subBlock) && !todo.contains(subBlock)) { todo.add(subBlock); } @@ -56,10 +58,10 @@ public class Pass3LoopDepthAnalysis extends Pass2Base { } } - private int getCallingDepth(LabelRef currentScope) { + private int getCallingDepth(ScopeRef currentScope) { int callingDepth = 1; - Collection callingScopes = callGraph.getCallingBlocks(currentScope); - for(LabelRef callingScope : callingScopes) { + Collection callingScopes = callGraph.getCallingBlocks(currentScope); + for(ScopeRef callingScope : callingScopes) { CallGraph.CallBlock callingBlock = callGraph.getCallBlock(callingScope); Collection calls = callingBlock.getCalls(currentScope); for(CallGraph.CallBlock.Call call : calls) { @@ -88,14 +90,14 @@ public class Pass3LoopDepthAnalysis extends Pass2Base { return callingDepth; } - private void findLoopDepth(LabelRef currentScope, int initialDepth) { + private void findLoopDepth(ScopeRef currentScope, int initialDepth) { NaturalLoopSet loopSet = getProgram().getLoopSet(); // Find loops in the current scope block List currentScopeLoops = new ArrayList<>(); for(NaturalLoop loop : loopSet.getLoops()) { LabelRef loopHead = loop.getHead(); ControlFlowBlock loopHeadBlock = getGraph().getBlock(loopHead); - LabelRef scopeRef = Pass3CallGraphAnalysis.getScopeRef(loopHeadBlock, getProgram()); + ScopeRef scopeRef = PassNCallGraphAnalysis.getScopeRef(loopHeadBlock, getProgram()); if(scopeRef.equals(currentScope)) { // Loop is inside current scope block! currentScopeLoops.add(loop); @@ -110,9 +112,8 @@ public class Pass3LoopDepthAnalysis extends Pass2Base { } // Find loop nesting depths in current scope loops - Deque todo = new ArrayDeque<>(); Set done = new LinkedHashSet<>(); - todo.addAll(currentScopeLoops); + Deque todo = new ArrayDeque<>(currentScopeLoops); while(!todo.isEmpty()) { NaturalLoop loop = todo.getFirst(); todo.removeFirst(); diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4InterruptClobberFix.java b/src/main/java/dk/camelot64/kickc/passes/Pass4InterruptClobberFix.java index e563f5b59..a392fb889 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4InterruptClobberFix.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4InterruptClobberFix.java @@ -7,8 +7,8 @@ import dk.camelot64.kickc.asm.AsmSegment; import dk.camelot64.kickc.model.CallGraph; import dk.camelot64.kickc.model.Program; import dk.camelot64.kickc.model.symbols.Procedure; -import dk.camelot64.kickc.model.values.LabelRef; import dk.camelot64.kickc.model.values.ProcedureRef; +import dk.camelot64.kickc.model.values.ScopeRef; import java.util.ArrayList; import java.util.Collection; @@ -83,10 +83,10 @@ public class Pass4InterruptClobberFix extends Pass2Base { } CallGraph callGraph = getProgram().getCallGraph(); - CallGraph.CallBlock callBlock = callGraph.getCallBlock(procedure.getLabel().getRef()); + CallGraph.CallBlock callBlock = callGraph.getCallBlock(procedure.getRef()); List calls = callBlock.getCalls(); for(CallGraph.CallBlock.Call call : calls) { - LabelRef calledProcLabel = call.getProcedure(); + ScopeRef calledProcLabel = call.getProcedure(); ProcedureRef calledProcRef = new ProcedureRef(calledProcLabel.getFullName()); Procedure calledProc = getProgram().getScope().getProcedure(calledProcRef); AsmClobber calledClobber = getProcedureClobber(calledProc); diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass3CallGraphAnalysis.java b/src/main/java/dk/camelot64/kickc/passes/PassNCallGraphAnalysis.java similarity index 59% rename from src/main/java/dk/camelot64/kickc/passes/Pass3CallGraphAnalysis.java rename to src/main/java/dk/camelot64/kickc/passes/PassNCallGraphAnalysis.java index b411d681f..08aee974f 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass3CallGraphAnalysis.java +++ b/src/main/java/dk/camelot64/kickc/passes/PassNCallGraphAnalysis.java @@ -1,54 +1,56 @@ package dk.camelot64.kickc.passes; -import dk.camelot64.kickc.model.*; +import dk.camelot64.kickc.model.CallGraph; +import dk.camelot64.kickc.model.ControlFlowBlock; +import dk.camelot64.kickc.model.Program; import dk.camelot64.kickc.model.statements.Statement; import dk.camelot64.kickc.model.statements.StatementCall; import dk.camelot64.kickc.model.symbols.Procedure; import dk.camelot64.kickc.model.symbols.Scope; import dk.camelot64.kickc.model.symbols.Symbol; -import dk.camelot64.kickc.model.values.LabelRef; import dk.camelot64.kickc.model.values.ProcedureRef; +import dk.camelot64.kickc.model.values.ScopeRef; /** Finds the call graph for the control flow graph - identifies all calls in all scopes and creates a graph from these. */ -public class Pass3CallGraphAnalysis extends Pass2Base { +public class PassNCallGraphAnalysis extends Pass2SsaOptimization { - public Pass3CallGraphAnalysis(Program program) { + public PassNCallGraphAnalysis(Program program) { super(program); } - /** - * Gets a label reference representing the scope of a block - * - * @param block The block - * @return The label of the scope containing the block. The outermost scope has a label containing an empty string. - */ - public static LabelRef getScopeRef(ControlFlowBlock block, Program program) { - Symbol blockSymbol = program.getScope().getSymbol(block.getLabel()); - LabelRef scopeRef; - if(blockSymbol instanceof Procedure) { - scopeRef = ((Procedure) blockSymbol).getRef().getLabelRef(); - } else { - Scope blockScope = blockSymbol.getScope(); - scopeRef = new LabelRef(blockScope.getFullName()); - } - return scopeRef; - } - - public void findCallGraph() { + @Override + public boolean step() { CallGraph callGraph = new CallGraph(); for(ControlFlowBlock block : getGraph().getAllBlocks()) { - LabelRef scopeRef = getScopeRef(block, getProgram()); + ScopeRef scopeRef = getScopeRef(block, getProgram()); for(Statement statement : block.getStatements()) { if(statement instanceof StatementCall) { ProcedureRef procedure = ((StatementCall) statement).getProcedure(); - LabelRef procedureLabel = procedure.getLabelRef(); CallGraph.CallBlock callBlock = callGraph.getOrCreateCallBlock(scopeRef); - callBlock.addCall(procedureLabel, (StatementCall) statement); + callBlock.addCall(procedure, (StatementCall) statement); } } } getProgram().setCallGraph(callGraph); + return false; } + /** + * Gets a reference to the scope of a block + * + * @param block The block + * @return The scope containing the block. The outermost scope has a label containing an empty string. + */ + public static ScopeRef getScopeRef(ControlFlowBlock block, Program program) { + Symbol blockSymbol = program.getScope().getSymbol(block.getLabel()); + if(blockSymbol instanceof Procedure) { + return ((Procedure) blockSymbol).getRef(); + } else { + Scope blockScope = blockSymbol.getScope(); + return blockScope.getRef(); + } + } + + }