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:
parent
7ee24766fa
commit
070fb7937d
@ -1,2 +1,3 @@
|
||||
cmp #{c1}
|
||||
bmi {la1}
|
||||
beq {la1}
|
||||
|
4
src/main/fragment/vbuxx_gt_vbuc1_then_la1.asm
Normal file
4
src/main/fragment/vbuxx_gt_vbuc1_then_la1.asm
Normal file
@ -0,0 +1,4 @@
|
||||
cpx #{c1}
|
||||
beq !+
|
||||
bcs {la1}
|
||||
!:
|
4
src/main/fragment/vbuyy_gt_vbuc1_then_la1.asm
Normal file
4
src/main/fragment/vbuyy_gt_vbuc1_then_la1.asm
Normal file
@ -0,0 +1,4 @@
|
||||
cpy #{c1}
|
||||
beq !+
|
||||
bcs {la1}
|
||||
!:
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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");
|
||||
|
21
src/test/kc/comparison-rewriting.kc
Normal file
21
src/test/kc/comparison-rewriting.kc
Normal 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] = '+';
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user