1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-04-08 14:37:40 +00:00

Implemented comparison rewriting optimization.

This commit is contained in:
Jesper Gravgaard 2019-04-10 11:12:49 +02:00
parent 7ee24766fa
commit 070fb7937d
8 changed files with 122 additions and 16 deletions

View File

@ -1,2 +1,3 @@
cmp #{c1}
bmi {la1}
beq {la1}

View File

@ -0,0 +1,4 @@
cpx #{c1}
beq !+
bcs {la1}
!:

View File

@ -0,0 +1,4 @@
cpy #{c1}
beq !+
bcs {la1}
!:

View File

@ -249,6 +249,7 @@ public class Compiler {
optimizations.add(new Pass2NopCastElimination(program));
optimizations.add(new Pass2EliminateUnusedBlocks(program));
optimizations.add(new Pass2RangeResolving(program));
optimizations.add(new Pass2ComparisonOptimization(program));
pass2Execute(optimizations);
}
@ -306,14 +307,7 @@ public class Compiler {
boolean stepOptimized = true;
while(stepOptimized) {
stepOptimized = optimization.step();
if(stepOptimized) {
getLog().append("Successful SSA optimization " + optimization.getClass().getSimpleName() + "");
ssaOptimized = true;
if(getLog().isVerboseSSAOptimize()) {
getLog().append("CONTROL FLOW GRAPH");
getLog().append(program.getGraph().toString(program));
}
}
ssaOptimized = pass2LogOptimization(ssaOptimized, optimization, stepOptimized);
}
}
}
@ -330,20 +324,24 @@ public class Compiler {
for(Pass2SsaOptimization optimization : optimizations) {
pass2AssertSSA();
boolean stepOptimized = optimization.step();
if(stepOptimized) {
getLog().append("Successful SSA optimization " + optimization.getClass().getSimpleName() + "");
ssaOptimized = true;
if(getLog().isVerboseSSAOptimize()) {
getLog().append("CONTROL FLOW GRAPH");
getLog().append(program.getGraph().toString(program));
}
ssaOptimized = pass2LogOptimization(ssaOptimized, optimization, stepOptimized);
}
return ssaOptimized;
}
private boolean pass2LogOptimization(boolean ssaOptimized, Pass2SsaOptimization optimization, boolean stepOptimized) {
if(stepOptimized) {
getLog().append("Successful SSA optimization " + optimization.getClass().getSimpleName() + "");
ssaOptimized = true;
if(getLog().isVerboseSSAOptimize()) {
getLog().append("CONTROL FLOW GRAPH");
getLog().append(program.getGraph().toString(program));
}
}
return ssaOptimized;
}
private void pass3Analysis() {
new Pass3AssertRValues(program).check();
new Pass3AssertConstants(program).check();
new Pass3AssertArrayLengths(program).check();

View File

@ -23,6 +23,9 @@ public class OperatorCastPtr extends OperatorUnary {
if(value instanceof ConstantInteger) {
return new ConstantPointer(((ConstantInteger) value).getInteger(), elementType);
}
if(value instanceof ConstantPointer) {
return new ConstantPointer(((ConstantPointer) value).getLocation(), elementType);
}
throw new CompileError("Calculation not implemented " + getOperator() + " " + value);
}

View File

@ -0,0 +1,70 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.operators.Operator;
import dk.camelot64.kickc.model.operators.Operators;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.statements.StatementConditionalJump;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeInference;
import dk.camelot64.kickc.model.types.SymbolTypeInteger;
import dk.camelot64.kickc.model.values.ConstantBinary;
import dk.camelot64.kickc.model.values.ConstantInteger;
import dk.camelot64.kickc.model.values.ConstantLiteral;
import dk.camelot64.kickc.model.values.ConstantValue;
/**
* The 6502/6510 handles some comparisons much faster than others.
* This optimization rewrites to faster comparisons when possible.
* Unsigned A > C is rewritten to A >= C+1 if the constant is <max.
* Unsigned A <= C is rewritten to A < C+1 if the constant is <max.
*/
public class Pass2ComparisonOptimization extends Pass2SsaOptimization {
public Pass2ComparisonOptimization(Program program) {
super(program);
}
/**
* Rewrite comparisons to faster ones if possible
*
* @return true optimization was performed. false if no optimization was possible.
*/
@Override
public boolean step() {
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
for(Statement statement : block.getStatements()) {
if(statement instanceof StatementConditionalJump) {
StatementConditionalJump conditionalJump = (StatementConditionalJump) statement;
Operator operator = conditionalJump.getOperator();
if(conditionalJump.getrValue2() instanceof ConstantValue) {
SymbolType valueType = SymbolTypeInference.inferType(getScope(), conditionalJump.getrValue1());
ConstantValue constantValue = (ConstantValue) conditionalJump.getrValue2();
ConstantLiteral constantLiteral = constantValue.calculateLiteral(getScope());
if(Operators.GT.equals(operator) && valueType instanceof SymbolTypeInteger && constantLiteral instanceof ConstantInteger) {
// Found > C - rewrite to >= C+1 if possible
if(((Long) constantLiteral.getValue()) < ((SymbolTypeInteger) valueType).getMaxValue()) {
// Rewrite is possible - do it
getLog().append("Rewriting conditional comparison " + statement.toString(getProgram(), false));
conditionalJump.setOperator(Operators.GE);
conditionalJump.setrValue2(new ConstantBinary(constantValue, Operators.PLUS, new ConstantInteger(1L)));
}
}
if(Operators.LE.equals(operator) && valueType instanceof SymbolTypeInteger && constantLiteral instanceof ConstantInteger) {
// Found <= C - rewrite to < C+1 if possible
if(((Long) constantLiteral.getValue()) < ((SymbolTypeInteger) valueType).getMaxValue()) {
// Rewrite is possible - do it
getLog().append("Rewriting conditional comparison " + statement.toString(getProgram(), false));
conditionalJump.setOperator(Operators.LT);
conditionalJump.setrValue2(new ConstantBinary(constantValue, Operators.PLUS, new ConstantInteger(1L)));
}
}
}
}
}
}
return false;
}
}

View File

@ -32,6 +32,11 @@ public class TestPrograms {
public TestPrograms() {
}
@Test
public void testComparisonRewriting() throws IOException, URISyntaxException {
compileAndCompare("comparison-rewriting", getLogSysout());
}
@Test
public void testLoopBreakContinue() throws IOException, URISyntaxException {
compileAndCompare("loop-break-continue");

View File

@ -0,0 +1,21 @@
// Test rewriting of constant comparisons
void main() {
byte* screen = $0400;
for(byte* sc : screen..screen+1000) *sc=' ';
byte[] header = " < <= == >= >";
for( byte i=0; header[i]!=0; i++)
screen[i] = header[i];
for(byte i=0;i<=9;i++) {
screen +=40;
screen[0] = '0'+i;
if(i<5) screen[2] = '+';
if(i<=5) screen[5] = '+';
if(i==5) screen[8] = '+';
if(i>=5) screen[11] = '+';
if(i>5) screen[14] = '+';
}
}