mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-18 08:30:18 +00:00
Added a phase 2 symbol assertion checking that the program always matches the symbol table.
This commit is contained in:
parent
2e90516f34
commit
56cf4c80ef
@ -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.
|
@ -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;
|
||||
}
|
||||
|
||||
|
150
src/dk/camelot64/kickc/icl/Pass2AssertSymbols.java
Normal file
150
src/dk/camelot64/kickc/icl/Pass2AssertSymbols.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
30
src/dk/camelot64/kickc/icl/Pass2SsaAssertion.java
Normal file
30
src/dk/camelot64/kickc/icl/Pass2SsaAssertion.java
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user