diff --git a/src/dk/camelot64/kickc/Compiler.java b/src/dk/camelot64/kickc/Compiler.java index 119d88554..14f961f27 100644 --- a/src/dk/camelot64/kickc/Compiler.java +++ b/src/dk/camelot64/kickc/Compiler.java @@ -46,128 +46,149 @@ public class Compiler { public CompilationResult compile(final CharStream input) { CompileLog log = new CompileLog(); try { - log.append(input.toString()); - KickCLexer lexer = new KickCLexer(input); - KickCParser parser = new KickCParser(new CommonTokenStream(lexer)); - parser.setBuildParseTree(true); - parser.addErrorListener(new BaseErrorListener() { - @Override - public void syntaxError( - Recognizer recognizer, - Object offendingSymbol, - int line, - int charPositionInLine, - String msg, - RecognitionException e) { - throw new RuntimeException("Error parsing file " + input.getSourceName() + "\n - Line: " + line + "\n - Message: " + msg); - } - }); - KickCParser.FileContext file = parser.file(); - Pass1GenerateStatementSequence pass1GenerateStatementSequence = new Pass1GenerateStatementSequence(log); - pass1GenerateStatementSequence.generate(file); - StatementSequence statementSequence = pass1GenerateStatementSequence.getSequence(); - ProgramScope programScope = pass1GenerateStatementSequence.getProgramScope(); - Pass1TypeInference pass1TypeInference = new Pass1TypeInference(programScope); - pass1TypeInference.inferTypes(statementSequence); - - log.append("PROGRAM"); - log.append(statementSequence.getAsTypedString(programScope)); - log.append("SYMBOLS"); - log.append(programScope.getSymbolTableContents()); - - Pass1GenerateControlFlowGraph pass1GenerateControlFlowGraph = new Pass1GenerateControlFlowGraph(programScope); - ControlFlowGraph controlFlowGraph = pass1GenerateControlFlowGraph.generate(statementSequence); - log.append("INITIAL CONTROL FLOW GRAPH"); - log.append(controlFlowGraph.getAsTypedString(programScope)); - - Pass1ProcedureCallParameters pass1ProcedureCallParameters = - new Pass1ProcedureCallParameters(programScope, controlFlowGraph); - controlFlowGraph = pass1ProcedureCallParameters.generate(); - log.append("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL"); - log.append(controlFlowGraph.getAsTypedString(programScope)); - - Pass1GenerateSingleStaticAssignmentForm pass1GenerateSingleStaticAssignmentForm = - new Pass1GenerateSingleStaticAssignmentForm(log, programScope, controlFlowGraph); - pass1GenerateSingleStaticAssignmentForm.generate(); - - log.append("CONTROL FLOW GRAPH SSA"); - log.append(controlFlowGraph.getAsTypedString(programScope)); - - Pass1ProcedureCallsReturnValue pass1ProcedureCallsReturnValue = - new Pass1ProcedureCallsReturnValue(programScope, controlFlowGraph); - controlFlowGraph = pass1ProcedureCallsReturnValue.generate(); - log.append("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN"); - log.append(controlFlowGraph.getAsTypedString(programScope)); - - List optimizations = new ArrayList<>(); - optimizations.add(new Pass2CullEmptyBlocks(controlFlowGraph, programScope, log)); - optimizations.add(new Pass2ConstantPropagation(controlFlowGraph, programScope, log)); - optimizations.add(new Pass2ConstantAdditionElimination(controlFlowGraph, programScope, log)); - optimizations.add(new Pass2AliasElimination(controlFlowGraph, programScope, log)); - optimizations.add(new Pass2RedundantPhiElimination(controlFlowGraph, programScope, log)); - optimizations.add(new Pass2SelfPhiElimination(controlFlowGraph, programScope, log)); - optimizations.add(new Pass2ConditionalJumpSimplification(controlFlowGraph, programScope, log)); - - List assertions = new ArrayList<>(); - assertions.add(new Pass2AssertSymbols(controlFlowGraph, programScope)); - assertions.add(new Pass2AssertBlocks(controlFlowGraph, programScope)); - - boolean ssaOptimized = true; - while (ssaOptimized) { - for (Pass2SsaAssertion assertion : assertions) { - assertion.check(); - } - ssaOptimized = false; - for (Pass2SsaOptimization optimization : optimizations) { - boolean stepOptimized = optimization.optimize(); - if (stepOptimized) { - log.append("Succesful SSA optimization " + optimization.getClass().getSimpleName() + ""); - ssaOptimized = true; - log.append("CONTROL FLOW GRAPH"); - log.append(controlFlowGraph.getAsTypedString(programScope)); - } - } - } - - Pass3BlockSequencePlanner pass3BlockSequencePlanner = new Pass3BlockSequencePlanner( - controlFlowGraph, - programScope); - pass3BlockSequencePlanner.plan(); - Pass3RegisterAllocation pass3RegisterAllocation = new Pass3RegisterAllocation(controlFlowGraph, programScope); - pass3RegisterAllocation.allocate(); - Pass3CodeGeneration pass3CodeGeneration = new Pass3CodeGeneration(controlFlowGraph, programScope); - AsmProgram asmProgram = pass3CodeGeneration.generate(); - - log.append("INITIAL ASM"); - log.append(asmProgram.toString()); - - List pass4Optimizations = new ArrayList<>(); - pass4Optimizations.add(new Pass4NextJumpElimination(asmProgram, log)); - pass4Optimizations.add(new Pass4UnnecesaryLoadElimination(asmProgram, log)); - boolean asmOptimized = true; - while (asmOptimized) { - asmOptimized = false; - for (Pass4AsmOptimization optimization : pass4Optimizations) { - boolean stepOtimized = optimization.optimize(); - if (stepOtimized) { - log.append("Succesful ASM optimization " + optimization.getClass().getSimpleName()); - asmOptimized = true; - log.append("ASSEMBLER"); - log.append(asmProgram.toString()); - } - } - } + KickCParser.FileContext file = pass0ParseInput(input, log); + Program program = pass1GenerateSSA(file, log); + pass2OptimizeSSA(program, log); + AsmProgram asmProgram = pass3GenerateAsm(program, log); + pass4OptimizeAsm(asmProgram, log); log.append("FINAL SYMBOL TABLE"); - log.append(programScope.getSymbolTableContents()); + log.append(program.getScope().getSymbolTableContents()); log.append("FINAL CODE"); log.append(asmProgram.toString()); - return new CompilationResult(asmProgram, controlFlowGraph, programScope, log); + return new CompilationResult(asmProgram, program.getGraph(), program.getScope(), log); } catch (Exception e) { System.out.println(log.getLog()); throw e; } } + public void pass4OptimizeAsm(AsmProgram asmProgram, CompileLog log) { + List pass4Optimizations = new ArrayList<>(); + pass4Optimizations.add(new Pass4NextJumpElimination(asmProgram, log)); + pass4Optimizations.add(new Pass4UnnecesaryLoadElimination(asmProgram, log)); + boolean asmOptimized = true; + while (asmOptimized) { + asmOptimized = false; + for (Pass4AsmOptimization optimization : pass4Optimizations) { + boolean stepOtimized = optimization.optimize(); + if (stepOtimized) { + log.append("Succesful ASM optimization " + optimization.getClass().getSimpleName()); + asmOptimized = true; + log.append("ASSEMBLER"); + log.append(asmProgram.toString()); + } + } + } + } + + public AsmProgram pass3GenerateAsm(Program program, CompileLog log) { + Pass3BlockSequencePlanner pass3BlockSequencePlanner = new Pass3BlockSequencePlanner(program); + pass3BlockSequencePlanner.plan(); + Pass3RegisterAllocation pass3RegisterAllocation = new Pass3RegisterAllocation(program); + pass3RegisterAllocation.allocate(); + Pass3CodeGeneration pass3CodeGeneration = new Pass3CodeGeneration(program); + AsmProgram asmProgram = pass3CodeGeneration.generate(); + + log.append("INITIAL ASM"); + log.append(asmProgram.toString()); + return asmProgram; + } + + public void pass2OptimizeSSA(Program program, CompileLog log) { + List optimizations = new ArrayList<>(); + optimizations.add(new Pass2CullEmptyBlocks(program, log)); + optimizations.add(new Pass2ConstantPropagation(program, log)); + optimizations.add(new Pass2ConstantAdditionElimination(program, log)); + optimizations.add(new Pass2AliasElimination(program, log)); + optimizations.add(new Pass2RedundantPhiElimination(program, log)); + optimizations.add(new Pass2SelfPhiElimination(program, log)); + optimizations.add(new Pass2ConditionalJumpSimplification(program, log)); + + List assertions = new ArrayList<>(); + assertions.add(new Pass2AssertSymbols(program)); + assertions.add(new Pass2AssertBlocks(program)); + + boolean ssaOptimized = true; + while (ssaOptimized) { + for (Pass2SsaAssertion assertion : assertions) { + assertion.check(); + } + ssaOptimized = false; + for (Pass2SsaOptimization optimization : optimizations) { + boolean stepOptimized = optimization.optimize(); + if (stepOptimized) { + log.append("Succesful SSA optimization " + optimization.getClass().getSimpleName() + ""); + ssaOptimized = true; + log.append("CONTROL FLOW GRAPH"); + log.append(program.getGraph().getAsTypedString(program.getScope())); + } + } + } + } + + public Program pass1GenerateSSA(KickCParser.FileContext file, CompileLog log) { + Pass1GenerateStatementSequence pass1GenerateStatementSequence1 = new Pass1GenerateStatementSequence(log); + pass1GenerateStatementSequence1.generate(file); + Pass1GenerateStatementSequence pass1GenerateStatementSequence = pass1GenerateStatementSequence1; + StatementSequence statementSequence = pass1GenerateStatementSequence.getSequence(); + ProgramScope programScope = pass1GenerateStatementSequence.getProgramScope(); + Pass1TypeInference pass1TypeInference = new Pass1TypeInference(programScope); + pass1TypeInference.inferTypes(statementSequence); + + log.append("PROGRAM"); + log.append(statementSequence.getAsTypedString(programScope)); + log.append("SYMBOLS"); + log.append(programScope.getSymbolTableContents()); + + Pass1GenerateControlFlowGraph pass1GenerateControlFlowGraph = new Pass1GenerateControlFlowGraph(programScope); + ControlFlowGraph controlFlowGraph = pass1GenerateControlFlowGraph.generate(statementSequence); + + Program program = new Program(programScope, controlFlowGraph); + + log.append("INITIAL CONTROL FLOW GRAPH"); + log.append(program.getGraph().getAsTypedString(program.getScope())); + + Pass1ProcedureCallParameters pass1ProcedureCallParameters = + new Pass1ProcedureCallParameters(program); + program.setGraph(pass1ProcedureCallParameters.generate()); + log.append("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL"); + log.append(program.getGraph().getAsTypedString(program.getScope())); + + Pass1GenerateSingleStaticAssignmentForm pass1GenerateSingleStaticAssignmentForm = + new Pass1GenerateSingleStaticAssignmentForm(log, program); + pass1GenerateSingleStaticAssignmentForm.generate(); + + log.append("CONTROL FLOW GRAPH SSA"); + log.append(program.getGraph().getAsTypedString(program.getScope())); + + Pass1ProcedureCallsReturnValue pass1ProcedureCallsReturnValue = + new Pass1ProcedureCallsReturnValue(program); + program.setGraph(pass1ProcedureCallsReturnValue.generate()); + log.append("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN"); + log.append(program.getGraph().getAsTypedString(program.getScope())); + return program; + } + + public KickCParser.FileContext pass0ParseInput(final CharStream input, CompileLog log) { + log.append(input.toString()); + KickCLexer lexer = new KickCLexer(input); + KickCParser parser = new KickCParser(new CommonTokenStream(lexer)); + parser.setBuildParseTree(true); + parser.addErrorListener(new BaseErrorListener() { + @Override + public void syntaxError( + Recognizer recognizer, + Object offendingSymbol, + int line, + int charPositionInLine, + String msg, + RecognitionException e) { + throw new RuntimeException("Error parsing file " + input.getSourceName() + "\n - Line: " + line + "\n - Message: " + msg); + } + }); + return parser.file(); + } + } diff --git a/src/dk/camelot64/kickc/icl/ConstantInteger.java b/src/dk/camelot64/kickc/icl/ConstantInteger.java index 920c40406..2cde006e2 100644 --- a/src/dk/camelot64/kickc/icl/ConstantInteger.java +++ b/src/dk/camelot64/kickc/icl/ConstantInteger.java @@ -1,5 +1,9 @@ package dk.camelot64.kickc.icl; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + /** * SSA form constant integer value */ @@ -7,7 +11,9 @@ public class ConstantInteger implements Constant { private Integer number; - public ConstantInteger(Integer number) { + @JsonCreator + public ConstantInteger( + @JsonProperty("number") Integer number) { this.number = number; } @@ -15,6 +21,7 @@ public class ConstantInteger implements Constant { return number; } + @JsonIgnore public SymbolType getType() { SymbolType type; if (getNumber() < 256) { @@ -35,6 +42,23 @@ public class ConstantInteger implements Constant { return "("+getType().getTypeName()+") "+Integer.toString(number); } @Override + @JsonIgnore public String getAsString() { - return Integer.toString(number); } + return Integer.toString(number); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ConstantInteger that = (ConstantInteger) o; + + return number != null ? number.equals(that.number) : that.number == null; + } + + @Override + public int hashCode() { + return number != null ? number.hashCode() : 0; + } } diff --git a/src/dk/camelot64/kickc/icl/ControlFlowBlock.java b/src/dk/camelot64/kickc/icl/ControlFlowBlock.java index 39a4f23ed..383c92e42 100644 --- a/src/dk/camelot64/kickc/icl/ControlFlowBlock.java +++ b/src/dk/camelot64/kickc/icl/ControlFlowBlock.java @@ -1,5 +1,8 @@ package dk.camelot64.kickc.icl; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + import java.util.ArrayList; import java.util.List; @@ -25,6 +28,20 @@ public class ControlFlowBlock { this.conditionalSuccessor = null; } + @JsonCreator + public ControlFlowBlock( + @JsonProperty("label") LabelRef label, + @JsonProperty("statements") List statements, + @JsonProperty("defaultSuccessor") LabelRef defaultSuccessor, + @JsonProperty("conditionalSuccessor") LabelRef conditionalSuccessor, + @JsonProperty("callSuccessor") LabelRef callSuccessor) { + this.label = label; + this.statements = statements; + this.defaultSuccessor = defaultSuccessor; + this.conditionalSuccessor = conditionalSuccessor; + this.callSuccessor = callSuccessor; + } + public LabelRef getLabel() { return label; } @@ -117,20 +134,6 @@ public class ControlFlowBlock { return out.toString(); } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ControlFlowBlock that = (ControlFlowBlock) o; - return label.equals(that.label); - } - - @Override - public int hashCode() { - return label.hashCode(); - } - public boolean hasPhiStatements() { if(statements.size()>0) { if(statements.get(0) instanceof StatementPhi) { @@ -140,4 +143,29 @@ public class ControlFlowBlock { return false; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ControlFlowBlock that = (ControlFlowBlock) o; + + if (!label.equals(that.label)) return false; + if (statements != null ? !statements.equals(that.statements) : that.statements != null) return false; + if (defaultSuccessor != null ? !defaultSuccessor.equals(that.defaultSuccessor) : that.defaultSuccessor != null) + return false; + if (conditionalSuccessor != null ? !conditionalSuccessor.equals(that.conditionalSuccessor) : that.conditionalSuccessor != null) + return false; + return callSuccessor != null ? callSuccessor.equals(that.callSuccessor) : that.callSuccessor == null; + } + + @Override + public int hashCode() { + int result = label.hashCode(); + result = 31 * result + (statements != null ? statements.hashCode() : 0); + result = 31 * result + (defaultSuccessor != null ? defaultSuccessor.hashCode() : 0); + result = 31 * result + (conditionalSuccessor != null ? conditionalSuccessor.hashCode() : 0); + result = 31 * result + (callSuccessor != null ? callSuccessor.hashCode() : 0); + return result; + } } diff --git a/src/dk/camelot64/kickc/icl/ControlFlowGraph.java b/src/dk/camelot64/kickc/icl/ControlFlowGraph.java index 74297c778..427345cb4 100644 --- a/src/dk/camelot64/kickc/icl/ControlFlowGraph.java +++ b/src/dk/camelot64/kickc/icl/ControlFlowGraph.java @@ -1,28 +1,44 @@ package dk.camelot64.kickc.icl; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + import java.util.*; /** The control flow graph of the program. * The control flow graph is a set of connected basic blocks. */ public class ControlFlowGraph { - private Map blocks; - private ControlFlowBlock firstBlock; - private List sequence; + private Map blocks; + private LabelRef firstBlockRef; + private List sequence; - public ControlFlowGraph(Map blocks, ControlFlowBlock firstBlock) { + public ControlFlowGraph(Map blocks, LabelRef firstBlockRef) { this.blocks = blocks; - this.firstBlock = firstBlock; + this.firstBlockRef = firstBlockRef; } - public ControlFlowBlock getBlock(SymbolRef symbol) { + @JsonCreator + public ControlFlowGraph( + @JsonProperty("blocks") Map blocks, + @JsonProperty("firstBlockRef") LabelRef firstBlockRef, + @JsonProperty("sequence") List sequence) { + this.blocks = blocks; + this.firstBlockRef = firstBlockRef; + this.sequence = sequence; + } + + public ControlFlowBlock getBlock(LabelRef symbol) { return blocks.get(symbol); } + @JsonIgnore public ControlFlowBlock getFirstBlock() { - return firstBlock; + return getBlock(firstBlockRef); } + @JsonIgnore public Collection getAllBlocks() { return blocks.values(); } @@ -96,14 +112,15 @@ public class ControlFlowGraph { return predecessorBlocks; } - public void setBlockSequence(List sequence) { - this.sequence = sequence; - } - - public List getBlockSequence() { + public List getSequence() { return sequence; } + public void setSequence(List sequence) { + this.sequence = sequence; + } + + @JsonIgnore public ControlFlowBlock getMainBlock() { for (ControlFlowBlock block : getAllBlocks()) { LabelRef label = block.getLabel(); @@ -122,6 +139,7 @@ public class ControlFlowGraph { return out.toString(); } + @JsonIgnore public String getAsString() { StringBuffer out = new StringBuffer(); for (ControlFlowBlock block : blocks.values()) { @@ -131,5 +149,23 @@ public class ControlFlowGraph { } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ControlFlowGraph that = (ControlFlowGraph) o; + + if (!blocks.equals(that.blocks)) return false; + if (!firstBlockRef.equals(that.firstBlockRef)) return false; + return sequence != null ? sequence.equals(that.sequence) : that.sequence == null; + } + + @Override + public int hashCode() { + int result = blocks.hashCode(); + result = 31 * result + firstBlockRef.hashCode(); + result = 31 * result + (sequence != null ? sequence.hashCode() : 0); + return result; + } } diff --git a/src/dk/camelot64/kickc/icl/ControlFlowGraphCopyVisitor.java b/src/dk/camelot64/kickc/icl/ControlFlowGraphCopyVisitor.java index 13ae05413..862312dfd 100644 --- a/src/dk/camelot64/kickc/icl/ControlFlowGraphCopyVisitor.java +++ b/src/dk/camelot64/kickc/icl/ControlFlowGraphCopyVisitor.java @@ -16,7 +16,7 @@ public class ControlFlowGraphCopyVisitor extends ControlFlowGraphBaseVisitor copyBlockMap; + private LinkedHashMap copyBlockMap; /** * The current block being copied. @@ -40,7 +40,7 @@ public class ControlFlowGraphCopyVisitor extends ControlFlowGraphBaseVisitor(); } + @JsonCreator + StatementPhi( + @JsonProperty("lValue") VariableRef lValue, + @JsonProperty("previousVersions") List previousVersions) { + this.lValue = lValue; + this.previousVersions = previousVersions; + } + public PreviousSymbol getPreviousVersion(int i) { return previousVersions.get(i); } @@ -34,7 +45,10 @@ public class StatementPhi implements StatementLValue { private LabelRef block; private RValue rValue; - public PreviousSymbol(LabelRef block, RValue rValue) { + @JsonCreator + public PreviousSymbol( + @JsonProperty("block") LabelRef block, + @JsonProperty("rValue") RValue rValue) { this.block = block; this.rValue = rValue; } @@ -43,17 +57,35 @@ public class StatementPhi implements StatementLValue { return block; } - public RValue getRValue() { + public RValue getrValue() { return rValue; } - public void setRValue(RValue RValue) { + public void setrValue(RValue RValue) { this.rValue = RValue; } public void setBlock(LabelRef block) { this.block = block; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + PreviousSymbol that = (PreviousSymbol) o; + + if (!block.equals(that.block)) return false; + return rValue.equals(that.rValue); + } + + @Override + public int hashCode() { + int result = block.hashCode(); + result = 31 * result + rValue.hashCode(); + return result; + } } public VariableRef getlValue() { @@ -86,7 +118,7 @@ public class StatementPhi implements StatementLValue { StringBuilder out = new StringBuilder(); out.append(lValue.getAsTypedString(scope) + " ← " + "phi("); for (PreviousSymbol previousSymbol : previousVersions) { - out.append(" "+previousSymbol.getBlock().getFullName()+"/"+previousSymbol.getRValue().getAsTypedString(scope)); + out.append(" "+previousSymbol.getBlock().getFullName()+"/"+previousSymbol.getrValue().getAsTypedString(scope)); } out.append(" )"); return out.toString(); @@ -97,9 +129,27 @@ public class StatementPhi implements StatementLValue { StringBuilder out = new StringBuilder(); out.append(lValue + " ← " + "phi("); for (PreviousSymbol previousSymbol : previousVersions) { - out.append(" "+previousSymbol.getBlock().getFullName()+"/"+previousSymbol.getRValue()); + out.append(" "+previousSymbol.getBlock().getFullName()+"/"+previousSymbol.getrValue()); } out.append(" )"); return out.toString(); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + StatementPhi that = (StatementPhi) o; + + if (!lValue.equals(that.lValue)) return false; + return previousVersions.equals(that.previousVersions); + } + + @Override + public int hashCode() { + int result = lValue.hashCode(); + result = 31 * result + previousVersions.hashCode(); + return result; + } } diff --git a/src/dk/camelot64/kickc/icl/Value.java b/src/dk/camelot64/kickc/icl/Value.java index 38423b5da..71a1d9180 100644 --- a/src/dk/camelot64/kickc/icl/Value.java +++ b/src/dk/camelot64/kickc/icl/Value.java @@ -14,6 +14,9 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; @JsonSubTypes.Type(value = VariableVersion.class, name = "variable_versioned"), @JsonSubTypes.Type(value = VariableIntermediate.class, name = "variable_intermediate"), @JsonSubTypes.Type(value = Label.class, name = "label"), + @JsonSubTypes.Type(value = VariableRef.class, name = "varref"), + @JsonSubTypes.Type(value = LabelRef.class, name = "labelref"), + @JsonSubTypes.Type(value = ProcedureRef.class, name = "procref"), @JsonSubTypes.Type(value = PointerDereferenceIndexed.class, name = "pointer_indexed"), @JsonSubTypes.Type(value = PointerDereferenceSimple.class, name = "pointer_simple"), @JsonSubTypes.Type(value = ProgramScope.class, name = "program"), diff --git a/src/dk/camelot64/kickc/icl/VariableRef.java b/src/dk/camelot64/kickc/icl/VariableRef.java index cbf7c1a0b..cd6ece211 100644 --- a/src/dk/camelot64/kickc/icl/VariableRef.java +++ b/src/dk/camelot64/kickc/icl/VariableRef.java @@ -1,9 +1,14 @@ package dk.camelot64.kickc.icl; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + /** A reference to a variable from the symbol table */ public class VariableRef extends SymbolRef implements RValue, LValue { - public VariableRef(String fullName) { + @JsonCreator + public VariableRef( + @JsonProperty("fullName") String fullName) { super(fullName); } diff --git a/src/dk/camelot64/kickc/passes/Pass1GenerateControlFlowGraph.java b/src/dk/camelot64/kickc/passes/Pass1GenerateControlFlowGraph.java index 4693746a6..638fc6f9b 100644 --- a/src/dk/camelot64/kickc/passes/Pass1GenerateControlFlowGraph.java +++ b/src/dk/camelot64/kickc/passes/Pass1GenerateControlFlowGraph.java @@ -12,7 +12,7 @@ public class Pass1GenerateControlFlowGraph { public static final String BEGIN_BLOCK_NAME = "@BEGIN"; public static final String END_BLOCK_NAME = "@END"; private Scope scope; - private Map blocks; + private Map blocks; private ControlFlowBlock firstBlock; public Pass1GenerateControlFlowGraph(Scope scope) { @@ -75,7 +75,7 @@ public class Pass1GenerateControlFlowGraph { } } - return new ControlFlowGraph(blocks, firstBlock); + return new ControlFlowGraph(blocks, firstBlock.getLabel()); } private ControlFlowBlock getOrCreateBlock(LabelRef label) { diff --git a/src/dk/camelot64/kickc/passes/Pass1GenerateSingleStaticAssignmentForm.java b/src/dk/camelot64/kickc/passes/Pass1GenerateSingleStaticAssignmentForm.java index 1dccb206e..267305497 100644 --- a/src/dk/camelot64/kickc/passes/Pass1GenerateSingleStaticAssignmentForm.java +++ b/src/dk/camelot64/kickc/passes/Pass1GenerateSingleStaticAssignmentForm.java @@ -14,13 +14,13 @@ import java.util.Map; public class Pass1GenerateSingleStaticAssignmentForm { private CompileLog log; - private Scope symbols; + private ProgramScope symbols; private ControlFlowGraph controlFlowGraph; - public Pass1GenerateSingleStaticAssignmentForm(CompileLog log, Scope symbols, ControlFlowGraph controlFlowGraph) { + public Pass1GenerateSingleStaticAssignmentForm(CompileLog log, Program program) { this.log = log; - this.symbols = symbols; - this.controlFlowGraph = controlFlowGraph; + this.symbols = program.getScope(); + this.controlFlowGraph = program.getGraph(); } public void generate() { diff --git a/src/dk/camelot64/kickc/passes/Pass1ProcedureCallParameters.java b/src/dk/camelot64/kickc/passes/Pass1ProcedureCallParameters.java index 593a1aa1f..030241e30 100644 --- a/src/dk/camelot64/kickc/passes/Pass1ProcedureCallParameters.java +++ b/src/dk/camelot64/kickc/passes/Pass1ProcedureCallParameters.java @@ -7,12 +7,12 @@ import java.util.List; /** Pass that modifies a control flow graph to call procedures by passing parameters through registers */ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor { - private Scope scope; + private ProgramScope scope; private ControlFlowGraph graph; - public Pass1ProcedureCallParameters(Scope scope, ControlFlowGraph graph ) { - this.scope = scope; - this.graph= graph; + public Pass1ProcedureCallParameters(Program program) { + this.scope = program.getScope(); + this.graph = program.getGraph(); } public ControlFlowGraph generate() { diff --git a/src/dk/camelot64/kickc/passes/Pass1ProcedureCallsReturnValue.java b/src/dk/camelot64/kickc/passes/Pass1ProcedureCallsReturnValue.java index 8244e2b6a..9a9acb78c 100644 --- a/src/dk/camelot64/kickc/passes/Pass1ProcedureCallsReturnValue.java +++ b/src/dk/camelot64/kickc/passes/Pass1ProcedureCallsReturnValue.java @@ -8,9 +8,9 @@ public class Pass1ProcedureCallsReturnValue extends ControlFlowGraphCopyVisitor private ProgramScope scope; private ControlFlowGraph graph; - public Pass1ProcedureCallsReturnValue(ProgramScope scope, ControlFlowGraph graph) { - this.scope = scope; - this.graph = graph; + public Pass1ProcedureCallsReturnValue(Program program) { + this.scope = program.getScope(); + this.graph = program.getGraph(); } public ControlFlowGraph generate() { diff --git a/src/dk/camelot64/kickc/passes/Pass1TypeInference.java b/src/dk/camelot64/kickc/passes/Pass1TypeInference.java index 2331cc03c..5a8a2b7a3 100644 --- a/src/dk/camelot64/kickc/passes/Pass1TypeInference.java +++ b/src/dk/camelot64/kickc/passes/Pass1TypeInference.java @@ -10,12 +10,16 @@ import java.util.Stack; */ public class Pass1TypeInference { - private Scope programScope; + private ProgramScope programScope; - public Pass1TypeInference(Scope programScope) { + public Pass1TypeInference(ProgramScope programScope) { this.programScope = programScope; } + public ProgramScope getProgramScope() { + return programScope; + } + public void inferTypes(StatementSequence sequence) { Stack scopes = new Stack<>(); scopes.add(programScope); diff --git a/src/dk/camelot64/kickc/passes/Pass2AliasElimination.java b/src/dk/camelot64/kickc/passes/Pass2AliasElimination.java index cd4bd32c3..0669bb4c3 100644 --- a/src/dk/camelot64/kickc/passes/Pass2AliasElimination.java +++ b/src/dk/camelot64/kickc/passes/Pass2AliasElimination.java @@ -10,8 +10,8 @@ import java.util.*; */ public class Pass2AliasElimination extends Pass2SsaOptimization { - public Pass2AliasElimination(ControlFlowGraph graph, ProgramScope scope, CompileLog log) { - super(graph, scope, log); + public Pass2AliasElimination(Program program, CompileLog log) { + super(program, log); } @@ -58,7 +58,7 @@ public class Pass2AliasElimination extends Pass2SsaOptimization { StatementPhi phi = (StatementPhi) statement; AliasSet aliasSet = aliases.findAliasSet(phi.getlValue()); if (aliasSet != null) { - if (phi.getPreviousVersions().size() == 1 && aliasSet.contains(phi.getPreviousVersion(0).getRValue())) { + if (phi.getPreviousVersions().size() == 1 && aliasSet.contains(phi.getPreviousVersion(0).getrValue())) { iterator.remove(); } } @@ -233,7 +233,7 @@ public class Pass2AliasElimination extends Pass2SsaOptimization { public Void visitPhi(StatementPhi phi) { if(lMatch[0]) { for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) { - RValue phiRValue = previousSymbol.getRValue(); + RValue phiRValue = previousSymbol.getrValue(); if (aliasSet.contains(phiRValue)) { log.append("Alias candidate removed " + phiRValue.getAsTypedString(getSymbols())); aliasSet.remove(phiRValue); @@ -276,9 +276,9 @@ public class Pass2AliasElimination extends Pass2SsaOptimization { public Void visitPhi(StatementPhi phi) { if (phi.getPreviousVersions().size() == 1) { StatementPhi.PreviousSymbol previousSymbol = phi.getPreviousVersions().get(0); - if (previousSymbol.getRValue() instanceof VariableRef) { + if (previousSymbol.getrValue() instanceof VariableRef) { VariableRef variable = phi.getlValue(); - VariableRef alias = (VariableRef) previousSymbol.getRValue(); + VariableRef alias = (VariableRef) previousSymbol.getrValue(); aliases.add(variable, alias); } } diff --git a/src/dk/camelot64/kickc/passes/Pass2AssertBlocks.java b/src/dk/camelot64/kickc/passes/Pass2AssertBlocks.java index 4142f927d..e3597cb9d 100644 --- a/src/dk/camelot64/kickc/passes/Pass2AssertBlocks.java +++ b/src/dk/camelot64/kickc/passes/Pass2AssertBlocks.java @@ -5,8 +5,8 @@ import dk.camelot64.kickc.icl.*; /** Assert that all referenced blocks exist in the program */ public class Pass2AssertBlocks extends Pass2SsaAssertion { - public Pass2AssertBlocks(ControlFlowGraph graph, ProgramScope scope) { - super(graph, scope); + public Pass2AssertBlocks(Program program) { + super(program); } @Override diff --git a/src/dk/camelot64/kickc/passes/Pass2AssertSymbols.java b/src/dk/camelot64/kickc/passes/Pass2AssertSymbols.java index e3de49d78..dd9fe5fb6 100644 --- a/src/dk/camelot64/kickc/passes/Pass2AssertSymbols.java +++ b/src/dk/camelot64/kickc/passes/Pass2AssertSymbols.java @@ -7,8 +7,8 @@ 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, ProgramScope scope) { - super(graph, scope); + public Pass2AssertSymbols(Program program) { + super(program); } @Override @@ -156,7 +156,7 @@ public class Pass2AssertSymbols extends Pass2SsaAssertion { public Void visitPhi(StatementPhi phi) { addSymbol(phi.getlValue()); for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) { - addSymbol(previousSymbol.getRValue()); + addSymbol(previousSymbol.getrValue()); } return super.visitPhi(phi); } diff --git a/src/dk/camelot64/kickc/passes/Pass2ConditionalJumpSimplification.java b/src/dk/camelot64/kickc/passes/Pass2ConditionalJumpSimplification.java index 29f89f4b8..b033cbca2 100644 --- a/src/dk/camelot64/kickc/passes/Pass2ConditionalJumpSimplification.java +++ b/src/dk/camelot64/kickc/passes/Pass2ConditionalJumpSimplification.java @@ -12,10 +12,8 @@ import java.util.Map; */ public class Pass2ConditionalJumpSimplification extends Pass2SsaOptimization { - private Map> allUsages; - - public Pass2ConditionalJumpSimplification(ControlFlowGraph graph, ProgramScope scope, CompileLog log) { - super(graph, scope, log); + public Pass2ConditionalJumpSimplification(Program program, CompileLog log) { + super(program, log); } /** diff --git a/src/dk/camelot64/kickc/passes/Pass2ConstantAdditionElimination.java b/src/dk/camelot64/kickc/passes/Pass2ConstantAdditionElimination.java index 05a303272..86fd68fdc 100644 --- a/src/dk/camelot64/kickc/passes/Pass2ConstantAdditionElimination.java +++ b/src/dk/camelot64/kickc/passes/Pass2ConstantAdditionElimination.java @@ -19,8 +19,8 @@ public class Pass2ConstantAdditionElimination extends Pass2SsaOptimization { private Map usages; - public Pass2ConstantAdditionElimination(ControlFlowGraph graph, ProgramScope scope, CompileLog log) { - super(graph, scope, log); + public Pass2ConstantAdditionElimination(Program program, CompileLog log) { + super(program, log); } /** diff --git a/src/dk/camelot64/kickc/passes/Pass2ConstantPropagation.java b/src/dk/camelot64/kickc/passes/Pass2ConstantPropagation.java index e57a9bd4e..c3d689789 100644 --- a/src/dk/camelot64/kickc/passes/Pass2ConstantPropagation.java +++ b/src/dk/camelot64/kickc/passes/Pass2ConstantPropagation.java @@ -9,8 +9,8 @@ import java.util.Map; /** Compiler Pass propagating constants in expressions eliminating constant variables */ public class Pass2ConstantPropagation extends Pass2SsaOptimization { - public Pass2ConstantPropagation(ControlFlowGraph graph, ProgramScope scope, CompileLog log) { - super(graph, scope, log); + public Pass2ConstantPropagation(Program program, CompileLog log) { + super(program, log); } /** @@ -71,9 +71,9 @@ public class Pass2ConstantPropagation extends Pass2SsaOptimization { public Void visitPhi(StatementPhi phi) { if (phi.getPreviousVersions().size() == 1) { StatementPhi.PreviousSymbol previousSymbol = phi.getPreviousVersions().get(0); - if (previousSymbol.getRValue() instanceof Constant) { + if (previousSymbol.getrValue() instanceof Constant) { VariableRef variable = phi.getlValue(); - Constant constant = (Constant) previousSymbol.getRValue(); + Constant constant = (Constant) previousSymbol.getrValue(); constants.put(variable, constant); } } diff --git a/src/dk/camelot64/kickc/passes/Pass2CullEmptyBlocks.java b/src/dk/camelot64/kickc/passes/Pass2CullEmptyBlocks.java index e2e7e837c..761a5ef0f 100644 --- a/src/dk/camelot64/kickc/passes/Pass2CullEmptyBlocks.java +++ b/src/dk/camelot64/kickc/passes/Pass2CullEmptyBlocks.java @@ -8,8 +8,8 @@ import java.util.*; /** Pass that culls empty control flow blocks from the program */ public class Pass2CullEmptyBlocks extends Pass2SsaOptimization { - public Pass2CullEmptyBlocks(ControlFlowGraph graph, ProgramScope scope, CompileLog log) { - super(graph, scope, log); + public Pass2CullEmptyBlocks(Program program, CompileLog log) { + super(program, log); } @Override @@ -46,7 +46,7 @@ public class Pass2CullEmptyBlocks extends Pass2SsaOptimization { for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) { if(previousSymbol.getBlock().equals(removeBlock.getLabel())) { // Found a phi function referencing the remove block - add copies for each predecessor - RValue previousRValue = previousSymbol.getRValue(); + RValue previousRValue = previousSymbol.getrValue(); for (ControlFlowBlock predecessor : predecessors) { if(previousSymbol!=null) { previousSymbol.setBlock(predecessor.getLabel()); diff --git a/src/dk/camelot64/kickc/passes/Pass2RedundantPhiElimination.java b/src/dk/camelot64/kickc/passes/Pass2RedundantPhiElimination.java index e563861fa..c56deac5c 100644 --- a/src/dk/camelot64/kickc/passes/Pass2RedundantPhiElimination.java +++ b/src/dk/camelot64/kickc/passes/Pass2RedundantPhiElimination.java @@ -9,8 +9,8 @@ import java.util.Map; /** Compiler Pass eliminating redundant phi functions */ public class Pass2RedundantPhiElimination extends Pass2SsaOptimization { - public Pass2RedundantPhiElimination(ControlFlowGraph graph, ProgramScope scope, CompileLog log) { - super(graph, scope, log); + public Pass2RedundantPhiElimination(Program program, CompileLog log) { + super(program, log); } /** @@ -42,9 +42,9 @@ public class Pass2RedundantPhiElimination extends Pass2SsaOptimization { RValue phiRValue = null; for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) { if(phiRValue==null) { - phiRValue = previousSymbol.getRValue(); + phiRValue = previousSymbol.getrValue(); } else { - if(!phiRValue.equals(previousSymbol.getRValue())) { + if(!phiRValue.equals(previousSymbol.getrValue())) { found = false; break; } diff --git a/src/dk/camelot64/kickc/passes/Pass2SelfPhiElimination.java b/src/dk/camelot64/kickc/passes/Pass2SelfPhiElimination.java index ed1252abc..014ae93f4 100644 --- a/src/dk/camelot64/kickc/passes/Pass2SelfPhiElimination.java +++ b/src/dk/camelot64/kickc/passes/Pass2SelfPhiElimination.java @@ -8,8 +8,8 @@ import java.util.Iterator; /** Compiler Pass eliminating phi self assignments */ public class Pass2SelfPhiElimination extends Pass2SsaOptimization { - public Pass2SelfPhiElimination(ControlFlowGraph graph, ProgramScope scope, CompileLog log) { - super(graph, scope, log); + public Pass2SelfPhiElimination(Program program, CompileLog log) { + super(program, log); } /** @@ -23,7 +23,7 @@ public class Pass2SelfPhiElimination extends Pass2SsaOptimization { public Void visitPhi(StatementPhi phi) { for (Iterator iterator = phi.getPreviousVersions().iterator(); iterator.hasNext(); ) { StatementPhi.PreviousSymbol previousSymbol = iterator.next(); - if (previousSymbol.getRValue().equals(phi.getlValue())) { + if (previousSymbol.getrValue().equals(phi.getlValue())) { iterator.remove(); optimized[0] = Boolean.TRUE; log.append("Self Phi Eliminated "+phi.getlValue().getAsTypedString(getSymbols())); diff --git a/src/dk/camelot64/kickc/passes/Pass2SsaAssertion.java b/src/dk/camelot64/kickc/passes/Pass2SsaAssertion.java index d98ae639e..a064e1df4 100644 --- a/src/dk/camelot64/kickc/passes/Pass2SsaAssertion.java +++ b/src/dk/camelot64/kickc/passes/Pass2SsaAssertion.java @@ -11,9 +11,9 @@ public abstract class Pass2SsaAssertion { private ControlFlowGraph graph; private ProgramScope programScope; - public Pass2SsaAssertion(ControlFlowGraph graph, ProgramScope programScope) { - this.graph = graph; - this.programScope = programScope; + public Pass2SsaAssertion(Program program) { + this.graph = program.getGraph(); + this.programScope = program.getScope(); } public ControlFlowGraph getGraph() { diff --git a/src/dk/camelot64/kickc/passes/Pass2SsaOptimization.java b/src/dk/camelot64/kickc/passes/Pass2SsaOptimization.java index 059c97192..e694e1e4b 100644 --- a/src/dk/camelot64/kickc/passes/Pass2SsaOptimization.java +++ b/src/dk/camelot64/kickc/passes/Pass2SsaOptimization.java @@ -15,10 +15,10 @@ public abstract class Pass2SsaOptimization { private ControlFlowGraph graph; private ProgramScope scope; - public Pass2SsaOptimization(ControlFlowGraph graph, ProgramScope scope,CompileLog log) { + public Pass2SsaOptimization(Program program,CompileLog log) { this.log = log; - this.graph = graph; - this.scope = scope; + this.graph = program.getGraph(); + this.scope = program.getScope(); } public CompileLog getLog() { @@ -154,12 +154,12 @@ public abstract class Pass2SsaOptimization { } for (Iterator iterator = phi.getPreviousVersions().iterator(); iterator.hasNext(); ) { StatementPhi.PreviousSymbol previousSymbol = iterator.next(); - if (getAlias(aliases, previousSymbol.getRValue()) != null) { - RValue alias = getAlias(aliases, previousSymbol.getRValue()); + if (getAlias(aliases, previousSymbol.getrValue()) != null) { + RValue alias = getAlias(aliases, previousSymbol.getrValue()); if (VOID.equals(alias)) { iterator.remove(); } else { - previousSymbol.setRValue(alias); + previousSymbol.setrValue(alias); } } } @@ -328,7 +328,7 @@ public abstract class Pass2SsaOptimization { @Override public Void visitPhi(StatementPhi phi) { for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) { - addUsage(previousSymbol.getRValue(), phi); + addUsage(previousSymbol.getrValue(), phi); } return null; } @@ -395,7 +395,7 @@ public abstract class Pass2SsaOptimization { @Override public Object visitPhi(StatementPhi phi) { for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) { - addUsage(previousSymbol.getRValue()); + addUsage(previousSymbol.getrValue()); } return null; } diff --git a/src/dk/camelot64/kickc/passes/Pass3BlockSequencePlanner.java b/src/dk/camelot64/kickc/passes/Pass3BlockSequencePlanner.java index 6cfeead82..6e71ef40f 100644 --- a/src/dk/camelot64/kickc/passes/Pass3BlockSequencePlanner.java +++ b/src/dk/camelot64/kickc/passes/Pass3BlockSequencePlanner.java @@ -1,8 +1,6 @@ package dk.camelot64.kickc.passes; -import dk.camelot64.kickc.icl.ControlFlowBlock; -import dk.camelot64.kickc.icl.ControlFlowGraph; -import dk.camelot64.kickc.icl.Scope; +import dk.camelot64.kickc.icl.*; import java.util.ArrayList; import java.util.List; @@ -11,42 +9,42 @@ import java.util.Stack; /** Plan the optimal sequence for the blocks of the control flow graph */ public class Pass3BlockSequencePlanner { - private ControlFlowGraph controlFlowGraph; - private Scope programScope; + private ControlFlowGraph graph; + private ProgramScope scope; - public Pass3BlockSequencePlanner(ControlFlowGraph controlFlowGraph, Scope programScope) { - this.controlFlowGraph = controlFlowGraph; - this.programScope = programScope; + public Pass3BlockSequencePlanner(Program program) { + this.graph = program.getGraph(); + this.scope = program.getScope(); } public void plan() { Stack todo = new Stack<>(); - ControlFlowBlock mainBlock = controlFlowGraph.getMainBlock(); + ControlFlowBlock mainBlock = graph.getMainBlock(); if (mainBlock != null) { todo.push(mainBlock); } - todo.push(controlFlowGraph.getFirstBlock()); - List sequence = new ArrayList<>(); + todo.push(graph.getFirstBlock()); + List sequence = new ArrayList<>(); while(!todo.empty()){ ControlFlowBlock block = todo.pop(); if(block==null) { break; } - if(sequence.contains(block)) { + if(sequence.contains(block.getLabel())) { // already handled - move on continue; } - sequence.add(block); + sequence.add(block.getLabel()); if(block.getCallSuccessor()!=null) { - todo.push(controlFlowGraph.getCallSuccessor(block)); + todo.push(graph.getCallSuccessor(block)); } if(block.getConditionalSuccessor()!=null) { - todo.push(controlFlowGraph.getConditionalSuccessor(block)); + todo.push(graph.getConditionalSuccessor(block)); } - if(controlFlowGraph.getDefaultSuccessor(block)!=null) { - todo.push(controlFlowGraph.getDefaultSuccessor(block)); + if(graph.getDefaultSuccessor(block)!=null) { + todo.push(graph.getDefaultSuccessor(block)); } } - controlFlowGraph.setBlockSequence(sequence); + graph.setSequence(sequence); } } diff --git a/src/dk/camelot64/kickc/passes/Pass3CodeGeneration.java b/src/dk/camelot64/kickc/passes/Pass3CodeGeneration.java index 7292a5506..d35933234 100644 --- a/src/dk/camelot64/kickc/passes/Pass3CodeGeneration.java +++ b/src/dk/camelot64/kickc/passes/Pass3CodeGeneration.java @@ -13,14 +13,15 @@ public class Pass3CodeGeneration { private ControlFlowGraph graph; private ProgramScope symbols; - public Pass3CodeGeneration(ControlFlowGraph graph, ProgramScope symbols) { - this.graph = graph; - this.symbols = symbols; + public Pass3CodeGeneration(Program program) { + this.graph = program.getGraph(); + this.symbols = program.getScope(); } public AsmProgram generate() { AsmProgram asm = new AsmProgram(); - for (ControlFlowBlock block : graph.getBlockSequence()) { + for (LabelRef blockRef : graph.getSequence()) { + ControlFlowBlock block = graph.getBlock(blockRef); // Generate entry points (if needed) genBlockEntryPoints(asm, block); // Generate label @@ -126,7 +127,7 @@ public class Pass3CodeGeneration { }); for (StatementPhi.PreviousSymbol previousSymbol : previousVersions) { if (previousSymbol.getBlock().equals(fromBlock.getLabel())) { - genAsmMove(asm, phi.getlValue(), previousSymbol.getRValue()); + genAsmMove(asm, phi.getlValue(), previousSymbol.getrValue()); break; } } diff --git a/src/dk/camelot64/kickc/passes/Pass3RegisterAllocation.java b/src/dk/camelot64/kickc/passes/Pass3RegisterAllocation.java index a5807e9a8..8e6cb8b15 100644 --- a/src/dk/camelot64/kickc/passes/Pass3RegisterAllocation.java +++ b/src/dk/camelot64/kickc/passes/Pass3RegisterAllocation.java @@ -11,9 +11,9 @@ public class Pass3RegisterAllocation { private ProgramScope symbols; int currentZp = 2; - public Pass3RegisterAllocation(ControlFlowGraph graph, ProgramScope symbols) { - this.graph = graph; - this.symbols = symbols; + public Pass3RegisterAllocation(Program program) { + this.graph = program.getGraph(); + this.symbols = program.getScope(); } public void allocate() { diff --git a/src/dk/camelot64/kickc/test/TestIclJson.java b/src/dk/camelot64/kickc/test/TestIclJson.java index d0f7db3bb..7223ae229 100644 --- a/src/dk/camelot64/kickc/test/TestIclJson.java +++ b/src/dk/camelot64/kickc/test/TestIclJson.java @@ -3,9 +3,13 @@ package dk.camelot64.kickc.test; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.databind.ObjectWriter; +import dk.camelot64.kickc.CompileLog; +import dk.camelot64.kickc.Compiler; import dk.camelot64.kickc.icl.*; import dk.camelot64.kickc.icl.jackson.IclJacksonFactory; +import dk.camelot64.kickc.parser.KickCParser; import junit.framework.TestCase; +import org.antlr.v4.runtime.ANTLRInputStream; import java.io.IOException; import java.util.ArrayList; @@ -44,6 +48,47 @@ public class TestIclJson extends TestCase { assertJsonSerialization(scope, json, Scope.class); } + public void testJsonStmtAssignment() throws IOException { + VariableUnversioned v1 = new VariableUnversioned("v1", null, SymbolTypeBasic.BYTE); + VariableUnversioned v2 = new VariableUnversioned("v2", null, SymbolTypeBasic.BYTE); + VariableUnversioned v3 = new VariableUnversioned("v3", null, SymbolTypeBasic.BYTE); + StatementAssignment statement = new StatementAssignment(v1.getRef(), v2.getRef(), new Operator("+"), v3.getRef()); + String json = "{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"v1\"},\"rValue1\":{\"@type\":\"varref\",\"fullName\":\"v2\"},\"operator\":{\"operator\":\"+\"},\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"v3\"}}"; + assertJsonSerialization(statement, json, Statement.class); + } + + public void testJsonStmtPhi() throws IOException { + VariableUnversioned v1 = new VariableUnversioned("v1", null, SymbolTypeBasic.BYTE); + VariableUnversioned v2 = new VariableUnversioned("v2", null, SymbolTypeBasic.BYTE); + VariableUnversioned v3 = new VariableUnversioned("v3", null, SymbolTypeBasic.BYTE); + Label b1 = new Label("B1", false); + Label b2 = new Label("B2", false); + StatementPhi statement = new StatementPhi(v1.getRef()); + statement.addPreviousVersion(b1.getRef(), v2.getRef()); + statement.addPreviousVersion(b2.getRef(), v3.getRef()); + String json = "{\"@type\":\"phi\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"v1\"},\"previousVersions\":[{\"block\":{\"@type\":\"labelref\",\"fullName\":\"B1\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"v2\"}},{\"block\":{\"@type\":\"labelref\",\"fullName\":\"B2\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"v3\"}}]}"; + assertJsonSerialization(statement, json, Statement.class); + } + + public void testJsonCode() throws IOException { + String minProgram = "byte b=0;byte c=b;"; + Compiler compiler = new Compiler(); + CompileLog log = new CompileLog(); + KickCParser.FileContext file = compiler.pass0ParseInput(new ANTLRInputStream(minProgram), log); + Program program = compiler.pass1GenerateSSA(file, log); + String json = "{\"scope\":{\"@type\":\"program\",\"name\":\"\",\"symbols\":{\"b\":{\"@type\":\"variable_unversioned\",\"name\":\"b\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":1,\"inferredType\":false},\"c\":{\"@type\":\"variable_unversioned\",\"name\":\"c\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":1,\"inferredType\":false},\"@BEGIN\":{\"@type\":\"label\",\"name\":\"@BEGIN\",\"intermediate\":false},\"@END\":{\"@type\":\"label\",\"name\":\"@END\",\"intermediate\":false},\"b#0\":{\"@type\":\"variable_versioned\",\"name\":\"b#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"b\",\"inferredType\":false},\"c#0\":{\"@type\":\"variable_versioned\",\"name\":\"c#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"c\",\"inferredType\":false}},\"intermediateVarCount\":0,\"intermediateLabelCount\":1,\"allocation\":null},\"graph\":{\"blocks\":{\"@BEGIN\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"statements\":[{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"b#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":0}},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"c#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"b#0\"}}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@END\"},\"conditionalSuccessor\":null,\"callSuccessor\":null},\"@END\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@END\"},\"statements\":[],\"defaultSuccessor\":null,\"conditionalSuccessor\":null,\"callSuccessor\":null}},\"firstBlockRef\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"sequence\":null}}"; + assertJsonSerialization(program, json, Program.class); + } + + public void testJsonCodeFib() throws IOException { + String minProgram = "byte n1 = 0; byte n2 = 1; byte i = 12; byte fib = 0; while(i>0) { fib = n1 + n2; n1 = n2; n2 = fib; i = i - 1; }"; + Compiler compiler = new Compiler(); + CompileLog log = new CompileLog(); + KickCParser.FileContext file = compiler.pass0ParseInput(new ANTLRInputStream(minProgram), log); + Program program = compiler.pass1GenerateSSA(file, log); + String json = "{\"scope\":{\"@type\":\"program\",\"name\":\"\",\"symbols\":{\"n1\":{\"@type\":\"variable_unversioned\",\"name\":\"n1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":5,\"inferredType\":false},\"n2\":{\"@type\":\"variable_unversioned\",\"name\":\"n2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":5,\"inferredType\":false},\"i\":{\"@type\":\"variable_unversioned\",\"name\":\"i\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":5,\"inferredType\":false},\"fib\":{\"@type\":\"variable_unversioned\",\"name\":\"fib\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":2,\"inferredType\":false},\"@1\":{\"@type\":\"label\",\"name\":\"@1\",\"intermediate\":true},\"@2\":{\"@type\":\"label\",\"name\":\"@2\",\"intermediate\":true},\"@3\":{\"@type\":\"label\",\"name\":\"@3\",\"intermediate\":true},\"$0\":{\"@type\":\"variable_intermediate\",\"name\":\"$0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"boolean\"},\"inferredType\":true},\"$1\":{\"@type\":\"variable_intermediate\",\"name\":\"$1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"inferredType\":true},\"$2\":{\"@type\":\"variable_intermediate\",\"name\":\"$2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"inferredType\":true},\"@BEGIN\":{\"@type\":\"label\",\"name\":\"@BEGIN\",\"intermediate\":false},\"@END\":{\"@type\":\"label\",\"name\":\"@END\",\"intermediate\":false},\"@4\":{\"@type\":\"label\",\"name\":\"@4\",\"intermediate\":true},\"@5\":{\"@type\":\"label\",\"name\":\"@5\",\"intermediate\":true},\"@6\":{\"@type\":\"label\",\"name\":\"@6\",\"intermediate\":true},\"n1#0\":{\"@type\":\"variable_versioned\",\"name\":\"n1#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n1\",\"inferredType\":false},\"n2#0\":{\"@type\":\"variable_versioned\",\"name\":\"n2#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n2\",\"inferredType\":false},\"i#0\":{\"@type\":\"variable_versioned\",\"name\":\"i#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"i\",\"inferredType\":false},\"fib#0\":{\"@type\":\"variable_versioned\",\"name\":\"fib#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"fib\",\"inferredType\":false},\"fib#1\":{\"@type\":\"variable_versioned\",\"name\":\"fib#1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"fib\",\"inferredType\":false},\"n1#1\":{\"@type\":\"variable_versioned\",\"name\":\"n1#1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n1\",\"inferredType\":false},\"n2#1\":{\"@type\":\"variable_versioned\",\"name\":\"n2#1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n2\",\"inferredType\":false},\"i#1\":{\"@type\":\"variable_versioned\",\"name\":\"i#1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"i\",\"inferredType\":false},\"i#2\":{\"@type\":\"variable_versioned\",\"name\":\"i#2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"i\",\"inferredType\":false},\"n1#2\":{\"@type\":\"variable_versioned\",\"name\":\"n1#2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n1\",\"inferredType\":false},\"n2#2\":{\"@type\":\"variable_versioned\",\"name\":\"n2#2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n2\",\"inferredType\":false},\"i#3\":{\"@type\":\"variable_versioned\",\"name\":\"i#3\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"i\",\"inferredType\":false},\"i#4\":{\"@type\":\"variable_versioned\",\"name\":\"i#4\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"i\",\"inferredType\":false},\"n2#3\":{\"@type\":\"variable_versioned\",\"name\":\"n2#3\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n2\",\"inferredType\":false},\"n2#4\":{\"@type\":\"variable_versioned\",\"name\":\"n2#4\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n2\",\"inferredType\":false},\"n1#3\":{\"@type\":\"variable_versioned\",\"name\":\"n1#3\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n1\",\"inferredType\":false},\"n1#4\":{\"@type\":\"variable_versioned\",\"name\":\"n1#4\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n1\",\"inferredType\":false}},\"intermediateVarCount\":3,\"intermediateLabelCount\":7,\"allocation\":null},\"graph\":{\"blocks\":{\"@BEGIN\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"statements\":[{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"n1#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":0}},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"n2#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":1}},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"i#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":12}},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"fib#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":0}}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@1\"},\"conditionalSuccessor\":null,\"callSuccessor\":null},\"@1\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@1\"},\"statements\":[{\"@type\":\"phi\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"n1#3\"},\"previousVersions\":[{\"block\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"n1#1\"}},{\"block\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"n1#0\"}}]},{\"@type\":\"phi\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"n2#3\"},\"previousVersions\":[{\"block\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"n2#1\"}},{\"block\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"n2#0\"}}]},{\"@type\":\"phi\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"i#2\"},\"previousVersions\":[{\"block\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"i#1\"}},{\"block\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"i#0\"}}]},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"$0\"},\"rValue1\":{\"@type\":\"varref\",\"fullName\":\"i#2\"},\"operator\":{\"operator\":\">\"},\"rValue2\":{\"@type\":\"integer\",\"number\":0}},{\"@type\":\"cond\",\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"$0\"},\"destination\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"rvalue1\":null,\"rvalue2\":{\"@type\":\"varref\",\"fullName\":\"$0\"}}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@4\"},\"conditionalSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"callSuccessor\":null},\"@2\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"statements\":[{\"@type\":\"phi\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"i#3\"},\"previousVersions\":[{\"block\":{\"@type\":\"labelref\",\"fullName\":\"@1\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"i#2\"}},{\"block\":{\"@type\":\"labelref\",\"fullName\":\"@5\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"i#4\"}}]},{\"@type\":\"phi\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"n2#2\"},\"previousVersions\":[{\"block\":{\"@type\":\"labelref\",\"fullName\":\"@1\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"n2#3\"}},{\"block\":{\"@type\":\"labelref\",\"fullName\":\"@5\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"n2#4\"}}]},{\"@type\":\"phi\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"n1#2\"},\"previousVersions\":[{\"block\":{\"@type\":\"labelref\",\"fullName\":\"@1\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"n1#3\"}},{\"block\":{\"@type\":\"labelref\",\"fullName\":\"@5\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"n1#4\"}}]},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"$1\"},\"rValue1\":{\"@type\":\"varref\",\"fullName\":\"n1#2\"},\"operator\":{\"operator\":\"+\"},\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"n2#2\"}},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"fib#1\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"$1\"}},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"n1#1\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"n2#2\"}},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"n2#1\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"fib#1\"}},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"$2\"},\"rValue1\":{\"@type\":\"varref\",\"fullName\":\"i#3\"},\"operator\":{\"operator\":\"-\"},\"rValue2\":{\"@type\":\"integer\",\"number\":1}},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"i#1\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"$2\"}}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@1\"},\"conditionalSuccessor\":null,\"callSuccessor\":null},\"@4\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@4\"},\"statements\":[],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@3\"},\"conditionalSuccessor\":null,\"callSuccessor\":null},\"@3\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@3\"},\"statements\":[],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@END\"},\"conditionalSuccessor\":null,\"callSuccessor\":null},\"@5\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@5\"},\"statements\":[{\"@type\":\"phi\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"n1#4\"},\"previousVersions\":[]},{\"@type\":\"phi\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"n2#4\"},\"previousVersions\":[]},{\"@type\":\"phi\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"i#4\"},\"previousVersions\":[]}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"conditionalSuccessor\":null,\"callSuccessor\":null},\"@6\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@6\"},\"statements\":[],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@3\"},\"conditionalSuccessor\":null,\"callSuccessor\":null},\"@END\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@END\"},\"statements\":[],\"defaultSuccessor\":null,\"conditionalSuccessor\":null,\"callSuccessor\":null}},\"firstBlockRef\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"sequence\":null}}"; + assertJsonSerialization(program, json, Program.class); + } public static void assertJsonSerialization(