mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-14 23:04:57 +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 library for fast multiply (mul.asm)
|
||||||
- Implement spline library (spline.asm)
|
- Implement spline library (spline.asm)
|
||||||
- Implement polygon filler for complex polygons.
|
- 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());
|
splitCurrentBlock(scope.addLabelIntermediate());
|
||||||
if(!SymbolTypeBasic.VOID.equals(procedure.getReturnType())) {
|
if(!SymbolTypeBasic.VOID.equals(procedure.getReturnType())) {
|
||||||
addStatementToCurrentBlock(new StatementAssignment(origCall.getLValue(), procReturnVar));
|
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;
|
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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/** Test my KickC Grammar */
|
/** Perform KickC compilation ans optimization*/
|
||||||
public class Main {
|
public class Main {
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
final String fileName = "src/dk/camelot64/kickc/test/flipper-rex2.kc";
|
final String fileName = "src/dk/camelot64/kickc/test/flipper-rex2.kc";
|
||||||
@ -30,7 +30,8 @@ public class Main {
|
|||||||
pass1GenerateStatementSequence.generate(file);
|
pass1GenerateStatementSequence.generate(file);
|
||||||
StatementSequence statementSequence = pass1GenerateStatementSequence.getSequence();
|
StatementSequence statementSequence = pass1GenerateStatementSequence.getSequence();
|
||||||
Scope programScope = pass1GenerateStatementSequence.getProgramScope();
|
Scope programScope = pass1GenerateStatementSequence.getProgramScope();
|
||||||
new Pass1TypeInference().inferTypes(statementSequence, programScope);
|
Pass1TypeInference pass1TypeInference = new Pass1TypeInference();
|
||||||
|
pass1TypeInference.inferTypes(statementSequence, programScope);
|
||||||
|
|
||||||
System.out.println("PROGRAM");
|
System.out.println("PROGRAM");
|
||||||
System.out.println(statementSequence.toString());
|
System.out.println(statementSequence.toString());
|
||||||
@ -42,7 +43,8 @@ public class Main {
|
|||||||
System.out.println("INITIAL CONTROL FLOW GRAPH");
|
System.out.println("INITIAL CONTROL FLOW GRAPH");
|
||||||
System.out.println(controlFlowGraph.toString());
|
System.out.println(controlFlowGraph.toString());
|
||||||
|
|
||||||
Pass1ProcedureCallParameters pass1ProcedureCallParameters = new Pass1ProcedureCallParameters(programScope, controlFlowGraph);
|
Pass1ProcedureCallParameters pass1ProcedureCallParameters =
|
||||||
|
new Pass1ProcedureCallParameters(programScope, controlFlowGraph);
|
||||||
controlFlowGraph = pass1ProcedureCallParameters.generate();
|
controlFlowGraph = pass1ProcedureCallParameters.generate();
|
||||||
System.out.println("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL");
|
System.out.println("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL");
|
||||||
System.out.println(controlFlowGraph.toString());
|
System.out.println(controlFlowGraph.toString());
|
||||||
@ -54,13 +56,12 @@ public class Main {
|
|||||||
System.out.println("CONTROL FLOW GRAPH SSA");
|
System.out.println("CONTROL FLOW GRAPH SSA");
|
||||||
System.out.println(controlFlowGraph.toString());
|
System.out.println(controlFlowGraph.toString());
|
||||||
|
|
||||||
Pass1ProcedureCallsReturnValue pass1ProcedureCallsReturnValue = new Pass1ProcedureCallsReturnValue(programScope, controlFlowGraph);
|
Pass1ProcedureCallsReturnValue pass1ProcedureCallsReturnValue =
|
||||||
|
new Pass1ProcedureCallsReturnValue(programScope, controlFlowGraph);
|
||||||
controlFlowGraph = pass1ProcedureCallsReturnValue.generate();
|
controlFlowGraph = pass1ProcedureCallsReturnValue.generate();
|
||||||
System.out.println("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN");
|
System.out.println("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN");
|
||||||
System.out.println(controlFlowGraph.toString());
|
System.out.println(controlFlowGraph.toString());
|
||||||
|
|
||||||
//if(1==1) return;
|
|
||||||
|
|
||||||
List<Pass2SsaOptimization> optimizations = new ArrayList<>();
|
List<Pass2SsaOptimization> optimizations = new ArrayList<>();
|
||||||
optimizations.add(new Pass2CullEmptyBlocks(controlFlowGraph, programScope));
|
optimizations.add(new Pass2CullEmptyBlocks(controlFlowGraph, programScope));
|
||||||
optimizations.add(new Pass2ConstantPropagation(controlFlowGraph, programScope));
|
optimizations.add(new Pass2ConstantPropagation(controlFlowGraph, programScope));
|
||||||
@ -70,8 +71,14 @@ public class Main {
|
|||||||
optimizations.add(new Pass2SelfPhiElimination(controlFlowGraph, programScope));
|
optimizations.add(new Pass2SelfPhiElimination(controlFlowGraph, programScope));
|
||||||
optimizations.add(new Pass2ConditionalJumpSimplification(controlFlowGraph, programScope));
|
optimizations.add(new Pass2ConditionalJumpSimplification(controlFlowGraph, programScope));
|
||||||
|
|
||||||
|
List<Pass2SsaAssertion> assertions = new ArrayList<>();
|
||||||
|
assertions.add(new Pass2AssertSymbols(controlFlowGraph, programScope));
|
||||||
|
|
||||||
boolean ssaOptimized = true;
|
boolean ssaOptimized = true;
|
||||||
while (ssaOptimized) {
|
while (ssaOptimized) {
|
||||||
|
for (Pass2SsaAssertion assertion : assertions) {
|
||||||
|
assertion.check();
|
||||||
|
}
|
||||||
ssaOptimized = false;
|
ssaOptimized = false;
|
||||||
for (Pass2SsaOptimization optimization : optimizations) {
|
for (Pass2SsaOptimization optimization : optimizations) {
|
||||||
boolean stepOptimized = optimization.optimize();
|
boolean stepOptimized = optimization.optimize();
|
||||||
|
Loading…
Reference in New Issue
Block a user