1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-10-11 12:23:45 +00:00

Control Flow Graph now handles procs & sub sprocs

This commit is contained in:
jespergravgaard 2017-06-11 19:15:09 +02:00
parent 40d44da2fc
commit 12bff79433
11 changed files with 128 additions and 57 deletions

View File

@ -16,7 +16,7 @@ public class ConstantInteger implements Constant {
} }
public SymbolType getType() { public SymbolType getType() {
return PassTypeInference.inferType(this); return Pass1TypeInference.inferType(this);
} }
@Override @Override

View File

@ -86,8 +86,8 @@ public class ControlFlowBlock {
if(defaultSuccessor!=null) { if(defaultSuccessor!=null) {
out.append(" to:"); out.append(" to:");
out.append(defaultSuccessor.getLabel().getLocalName()); out.append(defaultSuccessor.getLabel().getLocalName());
out.append("\n");
} }
out.append("\n");
return out.toString(); return out.toString();
} }

View File

@ -28,7 +28,7 @@ public class ControlFlowGraph {
public String toString() { public String toString() {
StringBuffer out = new StringBuffer(); StringBuffer out = new StringBuffer();
for (ControlFlowBlock block : blocks.values()) { for (ControlFlowBlock block : blocks.values()) {
out.append(block); out.append(block.toString());
} }
return out.toString(); return out.toString();
} }

View File

@ -2,6 +2,7 @@ package dk.camelot64.kickc.icl;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Stack;
/** Pass that generates a control flow graph for the program */ /** Pass that generates a control flow graph for the program */
public class Pass1GenerateControlFlowGraph { public class Pass1GenerateControlFlowGraph {
@ -19,22 +20,26 @@ public class Pass1GenerateControlFlowGraph {
public ControlFlowGraph generate(StatementSequence sequence) { public ControlFlowGraph generate(StatementSequence sequence) {
this.firstBlock = getOrCreateBlock(scope.addLabel(BEGIN_BLOCK_NAME)); this.firstBlock = getOrCreateBlock(scope.addLabel(BEGIN_BLOCK_NAME));
ControlFlowBlock currentBlock = this.firstBlock; Stack<ControlFlowBlock> blockStack = new Stack<>();
blockStack.push(firstBlock);
sequence.addStatement(new StatementLabel(scope.addLabel(END_BLOCK_NAME))); sequence.addStatement(new StatementLabel(scope.addLabel(END_BLOCK_NAME)));
for (Statement statement : sequence.getStatements()) { for (Statement statement : sequence.getStatements()) {
ControlFlowBlock currentBlock = blockStack.peek();
if(statement instanceof StatementLabel) { if(statement instanceof StatementLabel) {
StatementLabel statementLabel = (StatementLabel) statement; StatementLabel statementLabel = (StatementLabel) statement;
ControlFlowBlock nextBlock = getOrCreateBlock(statementLabel.getLabel()); ControlFlowBlock nextBlock = getOrCreateBlock(statementLabel.getLabel());
currentBlock.setDefaultSuccessor(nextBlock); currentBlock.setDefaultSuccessor(nextBlock);
nextBlock.addPredecessor(currentBlock); nextBlock.addPredecessor(currentBlock);
currentBlock = nextBlock; blockStack.pop();
blockStack.push(nextBlock);
} else if(statement instanceof StatementJump) { } else if(statement instanceof StatementJump) {
StatementJump statementJump = (StatementJump) statement; StatementJump statementJump = (StatementJump) statement;
ControlFlowBlock jmpBlock = getOrCreateBlock(statementJump.getDestination()); ControlFlowBlock jmpBlock = getOrCreateBlock(statementJump.getDestination());
currentBlock.setDefaultSuccessor(jmpBlock); currentBlock.setDefaultSuccessor(jmpBlock);
jmpBlock.addPredecessor(currentBlock); jmpBlock.addPredecessor(currentBlock);
ControlFlowBlock nextBlock = getOrCreateBlock(scope.addLabelIntermediate()); ControlFlowBlock nextBlock = getOrCreateBlock(scope.addLabelIntermediate());
currentBlock = nextBlock; blockStack.pop();
blockStack.push(nextBlock);
} else if(statement instanceof StatementConditionalJump) { } else if(statement instanceof StatementConditionalJump) {
currentBlock.addStatement(statement); currentBlock.addStatement(statement);
StatementConditionalJump statementConditionalJump = (StatementConditionalJump) statement; StatementConditionalJump statementConditionalJump = (StatementConditionalJump) statement;
@ -44,8 +49,25 @@ public class Pass1GenerateControlFlowGraph {
currentBlock.setConditionalSuccessor(jmpBlock); currentBlock.setConditionalSuccessor(jmpBlock);
nextBlock.addPredecessor(currentBlock); nextBlock.addPredecessor(currentBlock);
jmpBlock.addPredecessor(currentBlock); jmpBlock.addPredecessor(currentBlock);
currentBlock = nextBlock; blockStack.pop();
} else { blockStack.push(nextBlock);
} else if(statement instanceof StatementProcedureBegin) {
// Procedure strategy implemented is currently variable-based transfer of parameters/return values
StatementProcedureBegin procedure = (StatementProcedureBegin) statement;
procedure.setStrategy(StatementProcedureBegin.Strategy.PASS_BY_REGISTER);
Label procedureLabel = procedure.getProcedure().getLabel();
ControlFlowBlock procBlock = getOrCreateBlock(procedureLabel);
blockStack.push(procBlock);
} else if(statement instanceof StatementProcedureEnd) {
// Procedure strategy implemented is currently variable-based transfer of parameters/return values
currentBlock.setDefaultSuccessor(new ControlFlowBlock(new Label("@RETURN", scope, false)));
ControlFlowBlock nextBlock = getOrCreateBlock(scope.addLabelIntermediate());
blockStack.pop();
ControlFlowBlock prevBlock = blockStack.pop();
prevBlock.setDefaultSuccessor(nextBlock);
nextBlock.addPredecessor(prevBlock);
blockStack.push(nextBlock);
} else {
currentBlock.addStatement(statement); currentBlock.addStatement(statement);
} }
} }

View File

@ -13,23 +13,23 @@ import java.util.Stack;
*/ */
public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> { public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
private Scope programSymbols; private Scope programScope;
private Stack<Scope> symbolsStack; private Stack<Scope> scopeStack;
private StatementSequence sequence; private StatementSequence sequence;
public Pass1GenerateStatementSequence() { public Pass1GenerateStatementSequence() {
this.programSymbols = new Scope(); this.programScope = new Scope();
this.symbolsStack = new Stack<>(); this.scopeStack = new Stack<>();
symbolsStack.push(programSymbols); scopeStack.push(programScope);
this.sequence = new StatementSequence(); this.sequence = new StatementSequence();
} }
public Scope getProgramSymbols() { public Scope getProgramScope() {
return programSymbols; return programScope;
} }
private Scope getCurrentSymbols() { private Scope getCurrentSymbols() {
return symbolsStack.peek(); return scopeStack.peek();
} }
public void generate(KickCParser.FileContext file) { public void generate(KickCParser.FileContext file) {
@ -130,12 +130,15 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
SymbolType type = (SymbolType) visit(ctx.typeDecl()); SymbolType type = (SymbolType) visit(ctx.typeDecl());
String name = ctx.NAME().getText(); String name = ctx.NAME().getText();
Procedure procedure = getCurrentSymbols().addProcedure(name, type); Procedure procedure = getCurrentSymbols().addProcedure(name, type);
symbolsStack.push(procedure); scopeStack.push(procedure);
List<Variable> parameterList = (List<Variable>) this.visit(ctx.parameterListDecl()); List<Variable> parameterList = new ArrayList<>();
if(ctx.parameterListDecl()!=null) {
parameterList = (List<Variable>) this.visit(ctx.parameterListDecl());
}
procedure.setParameters(parameterList); procedure.setParameters(parameterList);
sequence.addStatement(new StatementProcedureBegin(procedure)); sequence.addStatement(new StatementProcedureBegin(procedure));
this.visit(ctx.stmtSeq()); this.visit(ctx.stmtSeq());
symbolsStack.pop(); scopeStack.pop();
sequence.addStatement(new StatementProcedureEnd(procedure)); sequence.addStatement(new StatementProcedureEnd(procedure));
return null; return null;
} }
@ -260,10 +263,9 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
@Override @Override
public Object visitExprCall(KickCParser.ExprCallContext ctx) { public Object visitExprCall(KickCParser.ExprCallContext ctx) {
Label label = new Label(ctx.NAME().getText(), getCurrentSymbols(), false);
List<RValue> parameters = (List<RValue>) this.visit(ctx.parameterList()); List<RValue> parameters = (List<RValue>) this.visit(ctx.parameterList());
VariableIntermediate tmpVar = getCurrentSymbols().addVariableIntermediate(); VariableIntermediate tmpVar = getCurrentSymbols().addVariableIntermediate();
sequence.addStatement(new StatementCallLValue(tmpVar, label, parameters)); sequence.addStatement(new StatementCallLValue(tmpVar, ctx.NAME().getText(), parameters));
return tmpVar; return tmpVar;
} }

View File

@ -1,13 +1,23 @@
package dk.camelot64.kickc.icl; package dk.camelot64.kickc.icl;
/** import java.util.Stack;
* Pass through the SSA statements inferring types of unresolved variables.
*/
public class PassTypeInference {
public void inferTypes(StatementSequence sequence, Scope symbols) { /**
* Pass through the generated statements inferring types of unresolved variables.
* Also updates procedure calls to point to the actual procedure called.
*/
public class Pass1TypeInference {
public void inferTypes(StatementSequence sequence, Scope programScope) {
Stack<Scope> scopes = new Stack<>();
scopes.add(programScope);
for (Statement statement : sequence.getStatements()) { for (Statement statement : sequence.getStatements()) {
if (statement instanceof StatementAssignment) { if(statement instanceof StatementProcedureBegin) {
StatementProcedureBegin procedureBegin = (StatementProcedureBegin) statement;
scopes.push(procedureBegin.getProcedure());
} else if(statement instanceof StatementProcedureEnd) {
scopes.pop();
} else if (statement instanceof StatementAssignment) {
StatementAssignment assignment = (StatementAssignment) statement; StatementAssignment assignment = (StatementAssignment) statement;
LValue lValue = assignment.getLValue(); LValue lValue = assignment.getLValue();
if (lValue instanceof Variable) { if (lValue instanceof Variable) {
@ -31,11 +41,12 @@ public class PassTypeInference {
} }
} }
} else if(statement instanceof StatementCallLValue) { } else if(statement instanceof StatementCallLValue) {
StatementCallLValue callLValue = (StatementCallLValue) statement; StatementCallLValue call = (StatementCallLValue) statement;
LValue lValue = callLValue.getLValue(); LValue lValue = call.getLValue();
if(lValue instanceof Variable) { if(lValue instanceof Variable) {
Label label = callLValue.getCallLabel(); String procedureName = call.getProcedureName();
Procedure procedure = symbols.getProcedure(label.getLocalName()); Procedure procedure = scopes.peek().getProcedure(procedureName);
call.setProcedure(procedure);
((Variable) lValue).setInferredType(procedure.getReturnType()); ((Variable) lValue).setInferredType(procedure.getReturnType());
} }
} }

View File

@ -21,7 +21,7 @@ public class Procedure extends Scope {
} }
public Label getLabel() { public Label getLabel() {
return new Label(getLocalName(), this, false); return new Label(getFullName(), getScope(), false);
} }
public SymbolType getReturnType() { public SymbolType getReturnType() {

View File

@ -11,12 +11,13 @@ public class StatementCallLValue implements StatementLValue {
/** The variable being assigned a value by the call. */ /** The variable being assigned a value by the call. */
private LValue lValue; private LValue lValue;
private Label callLabel; private String procedureName;
private List<RValue> parameters; private List<RValue> parameters;
private Procedure procedure;
public StatementCallLValue(LValue lValue, Label callLabel, List<RValue> parameters) { public StatementCallLValue(LValue lValue, String procedureName, List<RValue> parameters) {
this.lValue = lValue; this.lValue = lValue;
this.callLabel = callLabel; this.procedureName = procedureName;
this.parameters = parameters; this.parameters = parameters;
} }
@ -28,8 +29,16 @@ public class StatementCallLValue implements StatementLValue {
this.lValue = lValue; this.lValue = lValue;
} }
public Label getCallLabel() { public String getProcedureName() {
return callLabel; return procedureName;
}
public Procedure getProcedure() {
return procedure;
}
public void setProcedure(Procedure procedure) {
this.procedure = procedure;
} }
public List<RValue> getParameters() { public List<RValue> getParameters() {
@ -50,7 +59,11 @@ public class StatementCallLValue implements StatementLValue {
res.append(lValue); res.append(lValue);
res.append(""); res.append("");
res.append("call "); res.append("call ");
res.append(callLabel+" "); if(procedure!=null) {
res.append(procedure.getFullName()+ " ");
} else {
res.append(procedureName + " ");
}
for (RValue parameter : parameters) { for (RValue parameter : parameters) {
res.append(parameter+" "); res.append(parameter+" ");
} }

View File

@ -5,6 +5,13 @@ public class StatementProcedureBegin implements Statement {
private Procedure procedure; private Procedure procedure;
private Strategy strategy;
public static enum Strategy {
PASS_BY_REGISTER,
INLINE
}
public StatementProcedureBegin(Procedure procedure) { public StatementProcedureBegin(Procedure procedure) {
this.procedure = procedure; this.procedure = procedure;
} }
@ -13,6 +20,14 @@ public class StatementProcedureBegin implements Statement {
return procedure; return procedure;
} }
public Strategy getStrategy() {
return strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
@Override @Override
public String toString() { public String toString() {
return "proc "+procedure.toString(); return "proc "+procedure.toString();

View File

@ -29,32 +29,37 @@ public class Main {
Pass1GenerateStatementSequence pass1GenerateStatementSequence = new Pass1GenerateStatementSequence(); Pass1GenerateStatementSequence pass1GenerateStatementSequence = new Pass1GenerateStatementSequence();
pass1GenerateStatementSequence.generate(file); pass1GenerateStatementSequence.generate(file);
StatementSequence statementSequence = pass1GenerateStatementSequence.getSequence(); StatementSequence statementSequence = pass1GenerateStatementSequence.getSequence();
Scope scope = pass1GenerateStatementSequence.getProgramSymbols(); Scope programScope = pass1GenerateStatementSequence.getProgramScope();
new PassTypeInference().inferTypes(statementSequence, scope); new Pass1TypeInference().inferTypes(statementSequence, programScope);
System.out.println("PROGRAM"); System.out.println("PROGRAM");
System.out.println(statementSequence.toString()); System.out.println(statementSequence.toString());
System.out.println("SYMBOLS"); System.out.println("SYMBOLS");
System.out.println(scope.getSymbolTableContents()); System.out.println(programScope.getSymbolTableContents());
Pass1GenerateControlFlowGraph pass1GenerateControlFlowGraph = new Pass1GenerateControlFlowGraph(scope); Pass1GenerateControlFlowGraph pass1GenerateControlFlowGraph = new Pass1GenerateControlFlowGraph(programScope);
ControlFlowGraph controlFlowGraph = pass1GenerateControlFlowGraph.generate(statementSequence); ControlFlowGraph controlFlowGraph = pass1GenerateControlFlowGraph.generate(statementSequence);
System.out.println("INITIAL CONTROL FLOW GRAPH");
System.out.println(controlFlowGraph.toString());
if(1==1) return;
Pass1GenerateSingleStaticAssignmentForm pass1GenerateSingleStaticAssignmentForm = Pass1GenerateSingleStaticAssignmentForm pass1GenerateSingleStaticAssignmentForm =
new Pass1GenerateSingleStaticAssignmentForm(scope, controlFlowGraph); new Pass1GenerateSingleStaticAssignmentForm(programScope, controlFlowGraph);
pass1GenerateSingleStaticAssignmentForm.generate(); pass1GenerateSingleStaticAssignmentForm.generate();
List<Pass2SsaOptimization> optimizations = new ArrayList<>(); List<Pass2SsaOptimization> optimizations = new ArrayList<>();
optimizations.add(new Pass2CullEmptyBlocks(controlFlowGraph, scope)); optimizations.add(new Pass2CullEmptyBlocks(controlFlowGraph, programScope));
optimizations.add(new Pass2ConstantPropagation(controlFlowGraph, scope)); optimizations.add(new Pass2ConstantPropagation(controlFlowGraph, programScope));
optimizations.add(new Pass2ConstantAdditionElimination(controlFlowGraph, scope)); optimizations.add(new Pass2ConstantAdditionElimination(controlFlowGraph, programScope));
optimizations.add(new Pass2AliasElimination(controlFlowGraph, scope)); optimizations.add(new Pass2AliasElimination(controlFlowGraph, programScope));
optimizations.add(new Pass2RedundantPhiElimination(controlFlowGraph, scope)); optimizations.add(new Pass2RedundantPhiElimination(controlFlowGraph, programScope));
optimizations.add(new Pass2SelfPhiElimination(controlFlowGraph, scope)); optimizations.add(new Pass2SelfPhiElimination(controlFlowGraph, programScope));
optimizations.add(new Pass2ConditionalJumpSimplification(controlFlowGraph, scope)); optimizations.add(new Pass2ConditionalJumpSimplification(controlFlowGraph, programScope));
System.out.println("INITIAL CONTROL FLOW GRAPH");
System.out.println(controlFlowGraph.toString());
boolean ssaOptimized = true; boolean ssaOptimized = true;
while (ssaOptimized) { while (ssaOptimized) {
@ -70,9 +75,9 @@ public class Main {
} }
} }
Pass3RegisterAllocation pass3RegisterAllocation = new Pass3RegisterAllocation(controlFlowGraph, scope); Pass3RegisterAllocation pass3RegisterAllocation = new Pass3RegisterAllocation(controlFlowGraph, programScope);
pass3RegisterAllocation.allocate(); pass3RegisterAllocation.allocate();
Pass3CodeGeneration pass3CodeGeneration = new Pass3CodeGeneration(controlFlowGraph, scope); Pass3CodeGeneration pass3CodeGeneration = new Pass3CodeGeneration(controlFlowGraph, programScope);
AsmProgram asmProgram = pass3CodeGeneration.generate(); AsmProgram asmProgram = pass3CodeGeneration.generate();
System.out.println("INITIAL ASM"); System.out.println("INITIAL ASM");
@ -96,7 +101,7 @@ public class Main {
} }
System.out.println("SYMBOLS"); System.out.println("SYMBOLS");
System.out.println(scope.toString()); System.out.println(programScope.toString());
System.out.println("CONTROL FLOW GRAPH"); System.out.println("CONTROL FLOW GRAPH");
System.out.println(controlFlowGraph.toString()); System.out.println(controlFlowGraph.toString());
System.out.println("ASSEMBLER"); System.out.println("ASSEMBLER");

View File

@ -5,5 +5,8 @@ a = sum(s, a);
return; return;
byte sum(byte b1, byte b2) { byte sum(byte b1, byte b2) {
return b1+b2; byte b = b1+b2;
} byte inc( byte c) { return c+1;}
return inc(b);
}