diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2ConditionalAndOrRewriting.java b/src/main/java/dk/camelot64/kickc/passes/Pass2ConditionalAndOrRewriting.java index 1d1006cfd..68226e824 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2ConditionalAndOrRewriting.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2ConditionalAndOrRewriting.java @@ -3,6 +3,7 @@ package dk.camelot64.kickc.passes; import dk.camelot64.kickc.model.Comment; import dk.camelot64.kickc.model.ControlFlowBlock; import dk.camelot64.kickc.model.Program; +import dk.camelot64.kickc.model.VariableReferenceInfos; import dk.camelot64.kickc.model.operators.Operators; import dk.camelot64.kickc.model.statements.Statement; import dk.camelot64.kickc.model.statements.StatementAssignment; @@ -10,9 +11,14 @@ import dk.camelot64.kickc.model.statements.StatementConditionalJump; import dk.camelot64.kickc.model.statements.StatementPhiBlock; import dk.camelot64.kickc.model.symbols.Label; import dk.camelot64.kickc.model.symbols.Scope; -import dk.camelot64.kickc.model.values.*; +import dk.camelot64.kickc.model.values.LabelRef; +import dk.camelot64.kickc.model.values.RValue; +import dk.camelot64.kickc.model.values.ScopeRef; +import dk.camelot64.kickc.model.values.VariableRef; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; /** * Compiler Pass rewriting conditional jumps that use && or || operators @@ -25,12 +31,10 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization { @Override public boolean step() { - Map assignments = getAllAssignments(); - Map> usages = getAllUsages(); boolean done = false; boolean modified = false; while(!done) { - VariableRef obsoleteConditionVar = findAndRewriteBooleanCondition(assignments, usages); + VariableRef obsoleteConditionVar = findAndRewriteBooleanCondition(); if(obsoleteConditionVar != null) { Collection obsoleteVars = new ArrayList<>(); obsoleteVars.add(obsoleteConditionVar); @@ -47,31 +51,40 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization { /** * Look through the entire program looking for an if() condition that uses &&, || or !. * When found rewrite it (adding blocks) + * * @return Null if no condition was found to rewrite. The now obsolete variable containing the && / || / ! to be removed. */ - private VariableRef findAndRewriteBooleanCondition(Map assignments, Map> usages) { + private VariableRef findAndRewriteBooleanCondition() { + final VariableReferenceInfos variableReferenceInfos = getProgram().getVariableReferenceInfos(); for(ControlFlowBlock block : getGraph().getAllBlocks()) { for(Statement statement : block.getStatements()) { if(statement instanceof StatementConditionalJump) { StatementConditionalJump conditional = (StatementConditionalJump) statement; - if(conditional.getrValue1()==null && conditional.getOperator()==null) { + if(conditional.getrValue1() == null && conditional.getOperator() == null) { RValue conditionRValue = conditional.getrValue2(); - if(conditionRValue instanceof VariableRef && usages.get(conditionRValue).size() == 1) { - VariableRef conditionVar = (VariableRef) conditionRValue; - StatementAssignment conditionAssignment = assignments.get(conditionVar); - if(conditionAssignment!=null) { - if(Operators.LOGIC_AND.equals(conditionAssignment.getOperator())) { - // Found if() with logical && condition - rewrite to if(c1) if(c2) { xx } - rewriteLogicAnd(block, conditional, conditionAssignment); - return conditionVar; - } else if(Operators.LOGIC_OR.equals(conditionAssignment.getOperator())) { - // Found if() with logical || condition - rewrite to if(c1) goto x else if(c2) goto x else goto end, x:{ xx } end: - rewriteLogicOr(block, conditional, conditionAssignment); - return conditionVar; - } else if(Operators.LOGIC_NOT.equals(conditionAssignment.getOperator())) { - // Found if() with logical ! condition - rewrite to if(!c1) goto x else goto end, x:{ xx } end: - rewriteLogicNot(block, conditional, conditionAssignment); - return conditionVar; + if(conditionRValue instanceof VariableRef) { + final int conditionRValueUsages = variableReferenceInfos.getVarUseStatements((VariableRef) conditionRValue).size(); + if(conditionRValueUsages == 1) { + VariableRef conditionVar = (VariableRef) conditionRValue; + final Integer conditionDefineStatementIdx = variableReferenceInfos.getVarDefineStatement(conditionVar); + if(conditionDefineStatementIdx != null) { + final Statement conditionDefineStatement = getGraph().getStatementByIndex(conditionDefineStatementIdx); + if(conditionDefineStatement instanceof StatementAssignment) { + StatementAssignment conditionAssignment = (StatementAssignment) conditionDefineStatement; + if(Operators.LOGIC_AND.equals(conditionAssignment.getOperator())) { + // Found if() with logical && condition - rewrite to if(c1) if(c2) { xx } + rewriteLogicAnd(block, conditional, conditionAssignment); + return conditionVar; + } else if(Operators.LOGIC_OR.equals(conditionAssignment.getOperator())) { + // Found if() with logical || condition - rewrite to if(c1) goto x else if(c2) goto x else goto end, x:{ xx } end: + rewriteLogicOr(block, conditional, conditionAssignment); + return conditionVar; + } else if(Operators.LOGIC_NOT.equals(conditionAssignment.getOperator())) { + // Found if() with logical ! condition - rewrite to if(!c1) goto x else goto end, x:{ xx } end: + rewriteLogicNot(block, conditional, conditionAssignment); + return conditionVar; + } + } } } } @@ -84,13 +97,14 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization { /** * Rewrite logical && condition if(c1&&c2) { xx } to if(c1) if(c2) { xx } + * * @param block The block containing the current if() * @param conditional The if()-statement * @param conditionAssignment The assignment defining the condition variable. */ private void rewriteLogicAnd(ControlFlowBlock block, StatementConditionalJump conditional, StatementAssignment conditionAssignment) { // Found an if with a logical && condition - rewrite to if(c1) if(c2) { xx } - getLog().append("Rewriting && if()-condition to two if()s "+conditionAssignment.toString(getProgram(), false)); + getLog().append("Rewriting && if()-condition to two if()s " + conditionAssignment.toString(getProgram(), false)); ScopeRef currentScopeRef = block.getScope(); Scope currentScope = getScope().getScope(currentScopeRef); // Add a new block containing the second part of the && condition expression @@ -118,12 +132,13 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization { /** * Rewrite logical || condition if(c1||c2) { xx } to if(c1) goto x else if(c2) goto x else goto end, x:{ xx } end: + * * @param block The block containing the current if() * @param conditional The if()-statement * @param conditionAssignment The assignment defining the condition variable. */ private void rewriteLogicOr(ControlFlowBlock block, StatementConditionalJump conditional, StatementAssignment conditionAssignment) { - getLog().append("Rewriting || if()-condition to two if()s "+conditionAssignment.toString(getProgram(), false)); + getLog().append("Rewriting || if()-condition to two if()s " + conditionAssignment.toString(getProgram(), false)); ScopeRef currentScopeRef = block.getScope(); Scope currentScope = getScope().getScope(currentScopeRef); // Add a new block containing the second part of the && condition expression @@ -174,12 +189,13 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization { /** * Rewrite logical ! condition if(!c1) { xx } to if(c1) goto end else goto x, x:{ xx } end: + * * @param block The block containing the current if() * @param conditional The if()-statement * @param conditionAssignment The assignment defining the condition variable. */ private void rewriteLogicNot(ControlFlowBlock block, StatementConditionalJump conditional, StatementAssignment conditionAssignment) { - getLog().append("Rewriting ! if()-condition to reversed if() "+conditionAssignment.toString(getProgram(), false)); + getLog().append("Rewriting ! if()-condition to reversed if() " + conditionAssignment.toString(getProgram(), false)); // Rewrite the conditional to use only the first part of the && condition expression LabelRef defaultSuccessor = block.getDefaultSuccessor(); LabelRef conditionalSuccessor = block.getConditionalSuccessor(); diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2ConditionalJumpSimplification.java b/src/main/java/dk/camelot64/kickc/passes/Pass2ConditionalJumpSimplification.java index cb1c030d2..28ebbfca3 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2ConditionalJumpSimplification.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2ConditionalJumpSimplification.java @@ -7,13 +7,14 @@ import dk.camelot64.kickc.model.statements.Statement; import dk.camelot64.kickc.model.statements.StatementAssignment; import dk.camelot64.kickc.model.statements.StatementConditionalJump; import dk.camelot64.kickc.model.statements.StatementInfos; +import dk.camelot64.kickc.model.symbols.Variable; import dk.camelot64.kickc.model.values.RValue; import dk.camelot64.kickc.model.values.VariableRef; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Map; +import java.util.stream.Collectors; /** * Compiler Pass simplifying conditional jumps that are simple comparisons @@ -26,14 +27,13 @@ public class Pass2ConditionalJumpSimplification extends Pass2SsaOptimization { @Override public boolean step() { - final Map> usages = getAllUsages(); - final List simpleConditionVars = getSimpleConditions(usages); + final List simpleConditionVars = getSimpleConditions(); removeAssignments(getGraph(), simpleConditionVars); deleteSymbols(getScope(), simpleConditionVars); return (simpleConditionVars.size() > 0); } - private List getSimpleConditions(final Map> usages) { + private List getSimpleConditions() { final VariableReferenceInfos variableReferenceInfos = getProgram().getVariableReferenceInfos(); final List simpleConditionVars = new ArrayList<>(); for(ControlFlowBlock block : getGraph().getAllBlocks()) { @@ -42,10 +42,11 @@ public class Pass2ConditionalJumpSimplification extends Pass2SsaOptimization { StatementConditionalJump conditionalJump = (StatementConditionalJump) statement; if(conditionalJump.getrValue1() == null && conditionalJump.getOperator() == null) { RValue conditionRValue = conditionalJump.getrValue2(); - if(conditionRValue instanceof VariableRef && usages.get(conditionRValue).size() == 1) { + if(conditionRValue instanceof VariableRef) { VariableRef conditionVar = (VariableRef) conditionRValue; + final Collection conditionRvalueUsages = variableReferenceInfos.getVarUseStatements(conditionVar); final Integer conditionDefineStmtIdx = variableReferenceInfos.getVarDefineStatement(conditionVar); - if(conditionDefineStmtIdx != null) { + if(conditionRvalueUsages.size() == 1 && conditionDefineStmtIdx != null) { final Statement conditionDefineStmt = getGraph().getStatementByIndex(conditionDefineStmtIdx); if(conditionDefineStmt instanceof StatementAssignment && ((StatementAssignment) conditionDefineStmt).getOperator() != null) { StatementAssignment conditionAssignment = (StatementAssignment) conditionDefineStmt; @@ -59,7 +60,7 @@ public class Pass2ConditionalJumpSimplification extends Pass2SsaOptimization { case "=<": case ">=": case "=>": - final Collection referencedLoadStoreVariables = getReferencedLoadStoreVariables(conditionAssignment.getrValue1()); + final Collection referencedLoadStoreVariables = getReferencedLoadStoreVariables(conditionAssignment.getrValue1()); referencedLoadStoreVariables.addAll(getReferencedLoadStoreVariables(conditionAssignment.getrValue2())); boolean isSimple = true; if(referencedLoadStoreVariables.size() > 0) { @@ -68,8 +69,8 @@ public class Pass2ConditionalJumpSimplification extends Pass2SsaOptimization { final StatementInfos statementInfos = getProgram().getStatementInfos(); Collection statementsBetween = getGraph().getStatementsBetween(conditionAssignment, conditionalJump, statementInfos); for(Statement statementBetween : statementsBetween) { - for(VariableRef referencedLoadStoreVariable : referencedLoadStoreVariables) { - if(variableReferenceInfos.getDefinedVars(statementBetween).contains(referencedLoadStoreVariable)) { + for(Variable referencedLoadStoreVariable : referencedLoadStoreVariables) { + if(variableReferenceInfos.getDefinedVars(statementBetween).contains(referencedLoadStoreVariable.getVariableRef())) { // A referenced load/store-variable is modified in a statement between the assignment and the condition! isSimple = false; getLog().append("Condition not simple " + conditionVar.toString(getProgram()) + " " + conditionalJump.toString(getProgram(), false)); @@ -106,14 +107,12 @@ public class Pass2ConditionalJumpSimplification extends Pass2SsaOptimization { * @param rValue The RValue * @return All referenced load/store variables */ - private Collection getReferencedLoadStoreVariables(RValue rValue) { - List referencedLoadStoreVariables = new ArrayList<>(); - final Collection vars1 = VariableReferenceInfos.getReferencedVars(rValue); - for(VariableRef variableRef : vars1) { - if(getScope().getVariable(variableRef).isKindLoadStore()) - referencedLoadStoreVariables.add(variableRef); - } - return referencedLoadStoreVariables; + private Collection getReferencedLoadStoreVariables(RValue rValue) { + return VariableReferenceInfos.getReferencedVars(rValue) + .stream() + .map(variableRef -> getScope().getVariable(variableRef)) + .filter(Variable::isKindLoadStore) + .collect(Collectors.toList()); } } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2SsaOptimization.java b/src/main/java/dk/camelot64/kickc/passes/Pass2SsaOptimization.java index c244c4d15..849d6119b 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2SsaOptimization.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2SsaOptimization.java @@ -127,62 +127,5 @@ public abstract class Pass2SsaOptimization extends Pass1Base implements PassStep } } - public Map getAllAssignments() { - final HashMap assignments = new LinkedHashMap<>(); - 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 LinkedHashMap<>(); - 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 visitPhiBlock(StatementPhiBlock phi) { - for(StatementPhiBlock.PhiVariable phiVariable : phi.getPhiVariables()) { - for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) { - addUsage(phiRValue.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/main/java/dk/camelot64/kickc/passes/Pass2UnaryNotSimplification.java b/src/main/java/dk/camelot64/kickc/passes/Pass2UnaryNotSimplification.java index 9134f0a23..4acee5d09 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2UnaryNotSimplification.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2UnaryNotSimplification.java @@ -1,14 +1,15 @@ package dk.camelot64.kickc.passes; -import dk.camelot64.kickc.model.*; +import dk.camelot64.kickc.model.ControlFlowBlock; +import dk.camelot64.kickc.model.Program; +import dk.camelot64.kickc.model.VariableReferenceInfos; import dk.camelot64.kickc.model.operators.Operators; -import dk.camelot64.kickc.model.values.LValue; -import dk.camelot64.kickc.model.values.VariableRef; +import dk.camelot64.kickc.model.statements.Statement; import dk.camelot64.kickc.model.statements.StatementAssignment; +import dk.camelot64.kickc.model.values.VariableRef; import java.util.ArrayList; import java.util.List; -import java.util.Map; /** * Compiler Pass simplifying unary not variables if they reference a comparison that can be inverted @@ -20,71 +21,80 @@ public class Pass2UnaryNotSimplification extends Pass2SsaOptimization { } /** - * Eliminate unary nots if they are the only usage of a reversable comparison + * Eliminate unary nots if they are the only usage of a reversible comparison */ @Override public boolean step() { - final VariableReferenceInfos usages = getProgram().getVariableReferenceInfos(); - final Map assignments = getAllAssignments(); - final List unusedComparisons = optimizeUnaryNots(assignments, usages); + final List unusedComparisons = optimizeUnaryNots(); removeAssignments(getGraph(), unusedComparisons); deleteSymbols(getScope(), unusedComparisons); return (unusedComparisons.size() > 0); } /** - * Examine all unary nots. If they are the only usage of a reversable unary not replace the unary not with the reversed comparison - and eliminate the riginal variable. + * Examine all unary nots. If they are the only usage of a reversible unary not replace the unary not with the reversed comparison - and eliminate the original variable. * * @param assignments Assignments to examine * @param usages All variable usages - * @return Unused comparisons (because they have been replaced with reversed comparisions) + * @return Unused comparisons (because they have been replaced with reversed comparisons) */ - private List optimizeUnaryNots(final Map assignments, VariableReferenceInfos usages) { - + private List optimizeUnaryNots() { + final VariableReferenceInfos variableReferenceInfos = getProgram().getVariableReferenceInfos(); final List unused = new ArrayList<>(); - for(StatementAssignment assignment : assignments.values()) { - if(assignment.getrValue1() == null - && assignment.getOperator() != null - && ("!".equals(assignment.getOperator().getOperator()) || "not".equals(assignment.getOperator().getOperator())) - && assignment.getrValue2() instanceof VariableRef + for(ControlFlowBlock block : getGraph().getAllBlocks()) { + for(Statement statement : block.getStatements()) { + if(statement instanceof StatementAssignment) { + StatementAssignment assignment = (StatementAssignment) statement; + if(assignment.getrValue1() == null + && assignment.getOperator() != null + && ("!".equals(assignment.getOperator().getOperator()) || "not".equals(assignment.getOperator().getOperator())) + && assignment.getrValue2() instanceof VariableRef ) { - VariableRef tempVar = (VariableRef) assignment.getrValue2(); - StatementAssignment tempAssignment = assignments.get(tempVar); - int tempVarUsages = usages.getVarUseStatements(tempVar).size(); - if(tempVarUsages == 1 && tempAssignment!=null && tempAssignment.getOperator() != null) { - switch(tempAssignment.getOperator().getOperator()) { - case "<": - createInverse(">=", assignment, tempAssignment); - unused.add(tempVar); - break; - case ">": - createInverse("<=", assignment, tempAssignment); - unused.add(tempVar); - break; - case "<=": - case "=<": - createInverse(">", assignment, tempAssignment); - unused.add(tempVar); - break; - case ">=": - case "=>": - createInverse("<", assignment, tempAssignment); - unused.add(tempVar); - break; - case "==": - createInverse("!=", assignment, tempAssignment); - unused.add(tempVar); - break; - case "!=": - case "<>": - createInverse("==", assignment, tempAssignment); - unused.add(tempVar); - break; - case "!": - case "not": - createInverse(null, assignment, tempAssignment); - unused.add(tempVar); - break; + VariableRef tempVar = (VariableRef) assignment.getrValue2(); + final Integer tempVarDefineStmtIdx = variableReferenceInfos.getVarDefineStatement(tempVar); + if(tempVarDefineStmtIdx != null) { + final Statement tempVarDefineStmt = getGraph().getStatementByIndex(tempVarDefineStmtIdx); + if(tempVarDefineStmt instanceof StatementAssignment) { + StatementAssignment tempAssignment = (StatementAssignment) tempVarDefineStmt; + int tempVarUsages = variableReferenceInfos.getVarUseStatements(tempVar).size(); + if(tempVarUsages == 1 && tempAssignment.getOperator() != null) { + switch(tempAssignment.getOperator().getOperator()) { + case "<": + createInverse(">=", assignment, tempAssignment); + unused.add(tempVar); + break; + case ">": + createInverse("<=", assignment, tempAssignment); + unused.add(tempVar); + break; + case "<=": + case "=<": + createInverse(">", assignment, tempAssignment); + unused.add(tempVar); + break; + case ">=": + case "=>": + createInverse("<", assignment, tempAssignment); + unused.add(tempVar); + break; + case "==": + createInverse("!=", assignment, tempAssignment); + unused.add(tempVar); + break; + case "!=": + case "<>": + createInverse("==", assignment, tempAssignment); + unused.add(tempVar); + break; + case "!": + case "not": + createInverse(null, assignment, tempAssignment); + unused.add(tempVar); + break; + } + } + } + } } } }