1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-08-02 09:29:35 +00:00

Added a phase 2 symbol assertion checking that the program always matches the symbol table.

This commit is contained in:
Jesper Gravgaard 2017-07-13 21:35:43 +02:00
parent 2e90516f34
commit 56cf4c80ef
5 changed files with 201 additions and 7 deletions

View File

@ -40,4 +40,4 @@ Real Usage
- Implement library for fast multiply (mul.asm)
- Implement spline library (spline.asm)
- Implement polygon filler for complex polygons.
- Implement true type font renderer.
- Implement a true type font renderer.

View File

@ -40,7 +40,14 @@ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
splitCurrentBlock(scope.addLabelIntermediate());
if(!SymbolTypeBasic.VOID.equals(procedure.getReturnType())) {
addStatementToCurrentBlock(new StatementAssignment(origCall.getLValue(), procReturnVar));
} {
// No return type. Remove variable receiving the result.
LValue lValue = origCall.getLValue();
if(lValue instanceof Variable) {
scope.remove((Variable) lValue);
}
}
return null;
}

View File

@ -0,0 +1,150 @@
package dk.camelot64.kickc.icl;
import java.util.HashSet;
/** Asserts that the symbols in the symbol table match exactly the symbols in the program */
public class Pass2AssertSymbols extends Pass2SsaAssertion {
public Pass2AssertSymbols(ControlFlowGraph graph, Scope scope) {
super(graph, scope);
}
@Override
public void check() throws AssertionFailed {
SymbolFinder symbolFinder = new SymbolFinder();
symbolFinder.visitGraph(getGraph());
HashSet<Symbol> codeSymbols = symbolFinder.getSymbols();
// Check that all symbols found in the code is also oin the symbol tabel
for (Symbol codeSymbol : codeSymbols) {
if(codeSymbol.getFullName().equals("@RETURN")) continue;
Symbol tableSymbol = getSymbols().getSymbol(codeSymbol.getFullName());
if(tableSymbol==null) {
throw new AssertionFailed("Compile process error. Symbol found in code, but not in symbol table. "+codeSymbol.getFullName());
}
}
// Check that all symbols in the symbol table is also in the code
HashSet<Symbol> tableSymbols = getAllSymbols(getSymbols());
for (Symbol tableSymbol : tableSymbols) {
if(tableSymbol instanceof VariableUnversioned) continue;
Symbol codeSymbol = null;
String codeSymbolFullName = tableSymbol.getFullName();
for (Symbol symbol : codeSymbols) {
if(codeSymbolFullName.equals(symbol.getFullName())) {
codeSymbol = symbol;
break;
}
}
if(codeSymbol==null) {
throw new AssertionFailed("Compile process error. Symbol found in symbol table, but not in code. "+ codeSymbolFullName);
}
}
}
private HashSet<Symbol> getAllSymbols(Scope symbols) {
HashSet<Symbol> allSymbols = new HashSet<>();
for (Symbol symbol : symbols.getSymbols()) {
allSymbols.add(symbol);
if(symbol instanceof Scope) {
HashSet<Symbol> subSymbols = getAllSymbols((Scope) symbol);
allSymbols.addAll(subSymbols);
}
}
return allSymbols;
}
private static class SymbolFinder extends ControlFlowGraphBaseVisitor<Void> {
private HashSet<Symbol> symbols = new HashSet<>();
public HashSet<Symbol> getSymbols() {
return symbols;
}
private void addSymbol(Value symbol) {
if (symbol instanceof Symbol) {
symbols.add((Symbol) symbol);
} else if(symbol instanceof PointerDereferenceIndexed) {
addSymbol(((PointerDereferenceIndexed) symbol).getPointer());
addSymbol(((PointerDereferenceIndexed) symbol).getIndex());
} else if(symbol instanceof PointerDereference) {
addSymbol(((PointerDereference) symbol).getPointer());
}
}
@Override
public Void visitBlock(ControlFlowBlock block) {
addSymbol(block.getLabel());
addSymbol(block.getDefaultSuccessor());
addSymbol(block.getConditionalSuccessor());
addSymbol(block.getCallSuccessor());
return super.visitBlock(block);
}
@Override
public Void visitProcedureBegin(StatementProcedureBegin statement) {
symbols.add(statement.getProcedure());
return super.visitProcedureBegin(statement);
}
@Override
public Void visitProcedureEnd(StatementProcedureEnd statement) {
symbols.add(statement.getProcedure());
return super.visitProcedureEnd(statement);
}
@Override
public Void visitReturn(StatementReturn aReturn) {
addSymbol(aReturn.getValue());
return super.visitReturn(aReturn);
}
@Override
public Void visitConditionalJump(StatementConditionalJump conditionalJump) {
addSymbol(conditionalJump.getRValue1());
addSymbol(conditionalJump.getRValue2());
addSymbol(conditionalJump.getDestination());
return super.visitConditionalJump(conditionalJump);
}
@Override
public Void visitAssignment(StatementAssignment assignment) {
addSymbol(assignment.getLValue());
addSymbol(assignment.getRValue1());
addSymbol(assignment.getRValue2());
return super.visitAssignment(assignment);
}
@Override
public Void visitJump(StatementJump jump) {
addSymbol(jump.getDestination());
return super.visitJump(jump);
}
@Override
public Void visitJumpTarget(StatementLabel jumpTarget) {
addSymbol(jumpTarget.getLabel());
return super.visitJumpTarget(jumpTarget);
}
@Override
public Void visitCall(StatementCall callLValue) {
addSymbol(callLValue.getLValue());
addSymbol(callLValue.getProcedure());
if(callLValue.getParameters()!=null) {
for (RValue param : callLValue.getParameters()) {
addSymbol(param);
}
}
return super.visitCall(callLValue);
}
@Override
public Void visitPhi(StatementPhi phi) {
addSymbol(phi.getLValue());
for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) {
addSymbol(previousSymbol.getRValue());
}
return super.visitPhi(phi);
}
}
}

View File

@ -0,0 +1,30 @@
package dk.camelot64.kickc.icl;
/** Assertion checking that a pass 2 representation of the program is consistent */
public abstract class Pass2SsaAssertion {
private ControlFlowGraph graph;
private Scope scope;
public Pass2SsaAssertion(ControlFlowGraph graph, Scope scope) {
this.graph = graph;
this.scope = scope;
}
public ControlFlowGraph getGraph() {
return graph;
}
public Scope getSymbols() {
return scope;
}
public abstract void check() throws AssertionFailed;
public static class AssertionFailed extends RuntimeException {
public AssertionFailed(String message) {
super(message);
}
}
}

View File

@ -10,7 +10,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/** Test my KickC Grammar */
/** Perform KickC compilation ans optimization*/
public class Main {
public static void main(String[] args) throws IOException {
final String fileName = "src/dk/camelot64/kickc/test/flipper-rex2.kc";
@ -30,7 +30,8 @@ public class Main {
pass1GenerateStatementSequence.generate(file);
StatementSequence statementSequence = pass1GenerateStatementSequence.getSequence();
Scope programScope = pass1GenerateStatementSequence.getProgramScope();
new Pass1TypeInference().inferTypes(statementSequence, programScope);
Pass1TypeInference pass1TypeInference = new Pass1TypeInference();
pass1TypeInference.inferTypes(statementSequence, programScope);
System.out.println("PROGRAM");
System.out.println(statementSequence.toString());
@ -42,7 +43,8 @@ public class Main {
System.out.println("INITIAL CONTROL FLOW GRAPH");
System.out.println(controlFlowGraph.toString());
Pass1ProcedureCallParameters pass1ProcedureCallParameters = new Pass1ProcedureCallParameters(programScope, controlFlowGraph);
Pass1ProcedureCallParameters pass1ProcedureCallParameters =
new Pass1ProcedureCallParameters(programScope, controlFlowGraph);
controlFlowGraph = pass1ProcedureCallParameters.generate();
System.out.println("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL");
System.out.println(controlFlowGraph.toString());
@ -54,13 +56,12 @@ public class Main {
System.out.println("CONTROL FLOW GRAPH SSA");
System.out.println(controlFlowGraph.toString());
Pass1ProcedureCallsReturnValue pass1ProcedureCallsReturnValue = new Pass1ProcedureCallsReturnValue(programScope, controlFlowGraph);
Pass1ProcedureCallsReturnValue pass1ProcedureCallsReturnValue =
new Pass1ProcedureCallsReturnValue(programScope, controlFlowGraph);
controlFlowGraph = pass1ProcedureCallsReturnValue.generate();
System.out.println("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN");
System.out.println(controlFlowGraph.toString());
//if(1==1) return;
List<Pass2SsaOptimization> optimizations = new ArrayList<>();
optimizations.add(new Pass2CullEmptyBlocks(controlFlowGraph, programScope));
optimizations.add(new Pass2ConstantPropagation(controlFlowGraph, programScope));
@ -70,8 +71,14 @@ public class Main {
optimizations.add(new Pass2SelfPhiElimination(controlFlowGraph, programScope));
optimizations.add(new Pass2ConditionalJumpSimplification(controlFlowGraph, programScope));
List<Pass2SsaAssertion> assertions = new ArrayList<>();
assertions.add(new Pass2AssertSymbols(controlFlowGraph, programScope));
boolean ssaOptimized = true;
while (ssaOptimized) {
for (Pass2SsaAssertion assertion : assertions) {
assertion.check();
}
ssaOptimized = false;
for (Pass2SsaOptimization optimization : optimizations) {
boolean stepOptimized = optimization.optimize();