diff --git a/src/dk/camelot64/kickc/icl/AsmFragment.java b/src/dk/camelot64/kickc/icl/AsmFragment.java index b317712c7..1795cbe00 100644 --- a/src/dk/camelot64/kickc/icl/AsmFragment.java +++ b/src/dk/camelot64/kickc/icl/AsmFragment.java @@ -26,7 +26,11 @@ public class AsmFragment { this.bindings = new HashMap<>(); this.symbols = symbols; StringBuilder signature = new StringBuilder(); - signature.append(bind(conditionalJump.getCondition())); + if(conditionalJump.getRValue1()!=null) { + signature.append(bind(conditionalJump.getRValue1())); + signature.append(conditionalJump.getOperator().getOperator()); + } + signature.append(bind(conditionalJump.getRValue2())); signature.append("?"); signature.append(bind(conditionalJump.getDestination())); setSignature(signature.toString()); diff --git a/src/dk/camelot64/kickc/icl/Pass2ConditionalJumpSimplification.java b/src/dk/camelot64/kickc/icl/Pass2ConditionalJumpSimplification.java new file mode 100644 index 000000000..578ffe60b --- /dev/null +++ b/src/dk/camelot64/kickc/icl/Pass2ConditionalJumpSimplification.java @@ -0,0 +1,76 @@ +package dk.camelot64.kickc.icl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Compiler Pass simplifying conditional jumps that are simple comparisons + */ +public class Pass2ConditionalJumpSimplification extends Pass2Optimization { + + private Map> allUsages; + + public Pass2ConditionalJumpSimplification(ControlFlowGraph graph, SymbolTable symbolTable) { + super(graph, symbolTable); + } + + /** + * Eliminate alias assignments replacing them with the aliased variable. + */ + @Override + public boolean optimize() { + final Map assignments = getAllAssignments(); + final Map> usages = getAllUsages(); + final List simpleConditionVars = getSimpleConditions(assignments, usages); + removeAssignments(simpleConditionVars); + deleteSymbols(simpleConditionVars); + return (simpleConditionVars.size()>0); + } + + private List getSimpleConditions(final Map assignments, final Map> usages) { + + final List simpleConditionVars = new ArrayList<>(); + + ControlFlowGraphBaseVisitor visitor = new ControlFlowGraphBaseVisitor() { + @Override + public Void visitConditionalJump(StatementConditionalJump conditionalJump) { + if(conditionalJump.getRValue1()==null && conditionalJump.getOperator()==null) { + RValue conditionRValue = conditionalJump.getRValue2(); + if(conditionRValue instanceof Variable && usages.get(conditionRValue).size()==1) { + Variable conditionVar = (Variable) conditionRValue; + StatementAssignment conditionAssignment = assignments.get(conditionVar); + if(conditionAssignment.getOperator()!=null) { + switch (conditionAssignment.getOperator().getOperator()) { + case "==": + case "<>": + case "!=": + case "<": + case ">": + case "<=": + case "=<": + case ">=": + case "=>": + conditionalJump.setRValue1(conditionAssignment.getRValue1()); + conditionalJump.setOperator(conditionAssignment.getOperator()); + conditionalJump.setRValue2(conditionAssignment.getRValue2()); + simpleConditionVars.add(conditionVar); + System.out.println("Simple Condition " + conditionVar + " " + conditionalJump); + break; + default: + } + } + } + } + return null; + } + }; + visitor.visitGraph(getGraph()); + return simpleConditionVars; + + + } + + +} diff --git a/src/dk/camelot64/kickc/icl/Pass2Optimization.java b/src/dk/camelot64/kickc/icl/Pass2Optimization.java index bd4a623b9..8568d7a7f 100644 --- a/src/dk/camelot64/kickc/icl/Pass2Optimization.java +++ b/src/dk/camelot64/kickc/icl/Pass2Optimization.java @@ -1,8 +1,6 @@ package dk.camelot64.kickc.icl; -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; +import java.util.*; /** * Optimization performed during Compiler Pass 2. @@ -66,8 +64,11 @@ public abstract class Pass2Optimization { @Override public Void visitConditionalJump(StatementConditionalJump conditionalJump) { - if(getAlias(aliases, conditionalJump.getCondition())!=null) { - conditionalJump.setCondition(getAlias(aliases, conditionalJump.getCondition())); + if(getAlias(aliases, conditionalJump.getRValue1())!=null) { + conditionalJump.setRValue1(getAlias(aliases, conditionalJump.getRValue1())); + } + if(getAlias(aliases, conditionalJump.getRValue2())!=null) { + conditionalJump.setRValue2(getAlias(aliases, conditionalJump.getRValue2())); } return null; } @@ -196,5 +197,59 @@ public abstract class Pass2Optimization { } } + public Map getAllAssignments() { + final HashMap assignments = new HashMap<>(); + ControlFlowGraphBaseVisitor visitor = new ControlFlowGraphBaseVisitor() { + @Override + public Void visitAssignment(StatementAssignment assignment) { + assignments.put(assignment.getLValue(), assignment); + return null; + } + }; + visitor.visitGraph(getGraph()); + return assignments; + } + public Map> getAllUsages() { + final HashMap> usages = new HashMap<>(); + ControlFlowGraphBaseVisitor visitor = new ControlFlowGraphBaseVisitor() { + @Override + public Void visitAssignment(StatementAssignment assignment) { + addUsage(assignment.getRValue1(), assignment); + addUsage(assignment.getRValue2(), assignment); + return null; + } + + @Override + public Void visitConditionalJump(StatementConditionalJump conditionalJump) { + addUsage(conditionalJump.getRValue1(), conditionalJump); + addUsage(conditionalJump.getRValue2(), conditionalJump); + return null; + } + + @Override + public Void visitPhi(StatementPhi phi) { + for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) { + addUsage(previousSymbol.getRValue(), phi); + } + return null; + } + + private void addUsage(RValue rValue, Statement statement) { + if (rValue == null) { + return; + } + List use = usages.get(rValue); + if (use == null) { + use = new ArrayList<>(); + usages.put(rValue, use); + } + use.add(statement); + } + + }; + visitor.visitGraph(getGraph()); + + return usages; + } } diff --git a/src/dk/camelot64/kickc/icl/Pass3RegisterAllocation.java b/src/dk/camelot64/kickc/icl/Pass3RegisterAllocation.java index 7bb5de57a..513dceebe 100644 --- a/src/dk/camelot64/kickc/icl/Pass3RegisterAllocation.java +++ b/src/dk/camelot64/kickc/icl/Pass3RegisterAllocation.java @@ -25,5 +25,4 @@ public class Pass3RegisterAllocation { symbols.setAllocation(allocation); } - } diff --git a/src/dk/camelot64/kickc/icl/StatementConditionalJump.java b/src/dk/camelot64/kickc/icl/StatementConditionalJump.java index 5e903606b..c0fc9ff60 100644 --- a/src/dk/camelot64/kickc/icl/StatementConditionalJump.java +++ b/src/dk/camelot64/kickc/icl/StatementConditionalJump.java @@ -5,35 +5,75 @@ package dk.camelot64.kickc.icl; * Intermediate form used for compiler optimization. *
* if ( Yj ) goto XX + *
+ * The condition may be a single boolean variable, or a comparison between two variables (==, <>, <, >, <=, >= ) + * */ public class StatementConditionalJump implements Statement { - private RValue condition; + private RValue rValue1; + private Operator operator; + private RValue rValue2; private Label destination; public StatementConditionalJump(RValue condition, Label destination) { - this.condition = condition; + this.rValue1 = null; + this.operator = null; + this.rValue2 = condition; this.destination = destination; } - public RValue getCondition() { - return condition; + public StatementConditionalJump(RValue rValue1, Operator operator, RValue rValue2, Label destination) { + this.rValue1 = rValue1; + this.operator = operator; + this.rValue2 = rValue2; + this.destination = destination; + } + + public RValue getRValue1() { + return rValue1; + } + + public Operator getOperator() { + return operator; + } + + public RValue getRValue2() { + return rValue2; } public Label getDestination() { return destination; } - @Override - public String toString() { - return "if("+condition+") goto "+destination.getName(); + public void setRValue1(RValue rValue1) { + this.rValue1 = rValue1; } - public void setCondition(RValue condition) { - this.condition = condition; + public void setOperator(Operator operator) { + this.operator = operator; + } + + public void setRValue2(RValue rValue2) { + this.rValue2 = rValue2; } public void setDestination(Label destination) { this.destination = destination; } + + @Override + public String toString() { + StringBuilder out = new StringBuilder(); + out.append("if("); + if(rValue1!=null) { + out.append(rValue1); + out.append(operator.getOperator()); + } + out.append(rValue2); + out.append(") goto "); + out.append(destination.getName()); + return out.toString(); + } + } diff --git a/src/dk/camelot64/kickc/icl/asm/zpby1<=coby1?la1.asm b/src/dk/camelot64/kickc/icl/asm/zpby1<=coby1?la1.asm new file mode 100644 index 000000000..2827c1537 --- /dev/null +++ b/src/dk/camelot64/kickc/icl/asm/zpby1<=coby1?la1.asm @@ -0,0 +1,4 @@ +lda {zpby1} +cmp #{coby1} +bcc {la1} +beq {la1} \ No newline at end of file diff --git a/src/dk/camelot64/kickc/test/Main.java b/src/dk/camelot64/kickc/test/Main.java index 058be4b2c..15ad1127e 100644 --- a/src/dk/camelot64/kickc/test/Main.java +++ b/src/dk/camelot64/kickc/test/Main.java @@ -42,6 +42,7 @@ public class Main { optimizations.add(new Pass2AliasElimination(controlFlowGraph, symbolTable)); optimizations.add(new Pass2RedundantPhiElimination(controlFlowGraph, symbolTable)); optimizations.add(new Pass2SelfPhiElimination(controlFlowGraph, symbolTable)); + optimizations.add(new Pass2ConditionalJumpSimplification(controlFlowGraph, symbolTable)); boolean optimized = true; while (optimized) { diff --git a/src/dk/camelot64/kickc/test/fib.kc b/src/dk/camelot64/kickc/test/fib.kc index a3168f6d6..0532b60a7 100644 --- a/src/dk/camelot64/kickc/test/fib.kc +++ b/src/dk/camelot64/kickc/test/fib.kc @@ -2,7 +2,7 @@ byte n1 = 0; byte n2 = 1; byte i = 0; byte fib = 0; -while(i<=10) { +while(i<=11) { fib = n1 + n2; n1 = n2; n2 = fib;