1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-09-08 17:54:40 +00:00

Implemented interval analysis for detecting conditions that are always true/false. Closes #291

This commit is contained in:
Jesper Gravgaard 2019-08-29 20:05:08 +02:00
parent 887b9b08d7
commit 67157f0a70
5 changed files with 168 additions and 192 deletions

View File

@ -2,15 +2,18 @@ package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.ConstantNotLiteral; import dk.camelot64.kickc.model.ConstantNotLiteral;
import dk.camelot64.kickc.model.ControlFlowBlock; import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.InternalError;
import dk.camelot64.kickc.model.Program; import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.operators.Operator; import dk.camelot64.kickc.model.operators.Operator;
import dk.camelot64.kickc.model.operators.OperatorBinary; import dk.camelot64.kickc.model.operators.OperatorBinary;
import dk.camelot64.kickc.model.operators.OperatorUnary; import dk.camelot64.kickc.model.operators.OperatorUnary;
import dk.camelot64.kickc.model.operators.Operators;
import dk.camelot64.kickc.model.statements.Statement; import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.statements.StatementConditionalJump; import dk.camelot64.kickc.model.statements.StatementConditionalJump;
import dk.camelot64.kickc.model.values.ConstantBool; import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.values.ConstantLiteral; import dk.camelot64.kickc.model.types.SymbolTypeInference;
import dk.camelot64.kickc.model.values.ConstantValue; import dk.camelot64.kickc.model.types.SymbolTypeIntegerFixed;
import dk.camelot64.kickc.model.values.*;
import java.util.ListIterator; import java.util.ListIterator;
@ -38,8 +41,11 @@ public class Pass2ConstantIfs extends Pass2SsaOptimization {
Statement statement = stmtIt.next(); Statement statement = stmtIt.next();
if(statement instanceof StatementConditionalJump) { if(statement instanceof StatementConditionalJump) {
StatementConditionalJump conditional = (StatementConditionalJump) statement; StatementConditionalJump conditional = (StatementConditionalJump) statement;
ConstantLiteral literal = getConditionLiteralValue(conditional); ConstantLiteral literal = findConditionLiteral(conditional);
if(literal!=null && literal instanceof ConstantBool) { if(literal == null) {
literal = findConditionLiteralInterval(conditional);
}
if(literal != null && literal instanceof ConstantBool) {
// Condition is a constant boolean // Condition is a constant boolean
if(((ConstantBool) literal).getBool()) { if(((ConstantBool) literal).getBool()) {
// Always true - replace default successor and drop conditional jump // Always true - replace default successor and drop conditional jump
@ -49,7 +55,7 @@ public class Pass2ConstantIfs extends Pass2SsaOptimization {
stmtIt.remove(); stmtIt.remove();
block.setConditionalSuccessor(null); block.setConditionalSuccessor(null);
modified = true; modified = true;
} else { } else {
// Always false - drop the conditional jump // Always false - drop the conditional jump
Pass2EliminateUnusedBlocks.removePhiRValues(block.getLabel(), getGraph().getConditionalSuccessor(block), getLog()); Pass2EliminateUnusedBlocks.removePhiRValues(block.getLabel(), getGraph().getConditionalSuccessor(block), getLog());
getLog().append("if() condition always false - eliminating " + conditional.toString(getProgram(), false)); getLog().append("if() condition always false - eliminating " + conditional.toString(getProgram(), false));
@ -66,17 +72,17 @@ public class Pass2ConstantIfs extends Pass2SsaOptimization {
/** /**
* If the condition always evaluates to constant true or false this finds tha value. * If the condition always evaluates to constant true or false this finds tha value.
*
* @param conditional The conditional * @param conditional The conditional
* @return The literal value of the condition * @return The literal value of the condition
*/ */
private ConstantLiteral getConditionLiteralValue(StatementConditionalJump conditional) { private ConstantLiteral findConditionLiteral(StatementConditionalJump conditional) {
ConstantValue constValue1 = Pass2ConstantIdentification.getConstant(conditional.getrValue1()); ConstantValue constValue1 = Pass2ConstantIdentification.getConstant(conditional.getrValue1());
Operator operator = conditional.getOperator(); Operator operator = conditional.getOperator();
ConstantValue constValue2 = Pass2ConstantIdentification.getConstant(conditional.getrValue2()); ConstantValue constValue2 = Pass2ConstantIdentification.getConstant(conditional.getrValue2());
try { try {
// If all values are constant find the literal condition value // If all values are constant find the literal condition value
if(conditional.getrValue1() == null && operator == null && constValue2 != null) { if(conditional.getrValue1() == null && operator == null && constValue2 != null) {
// Constant condition // Constant condition
return constValue2.calculateLiteral(getScope()); return constValue2.calculateLiteral(getScope());
@ -90,17 +96,113 @@ public class Pass2ConstantIfs extends Pass2SsaOptimization {
return constVal.calculateLiteral(getScope()); return constVal.calculateLiteral(getScope());
} }
// Examine the intervals of the comparison parameters } catch(ConstantNotLiteral e) {
// TODO: Compare intervals based on the operator
} catch (ConstantNotLiteral e) {
// not literal - keep as null // not literal - keep as null
} }
return null; return null;
} }
/**
* Examine the intervals of the conditions to see if they
*
* @param conditional The conditional
* @return The literal value of the condition
*/
private ConstantLiteral findConditionLiteralInterval(StatementConditionalJump conditional) {
if(conditional.getrValue1() != null && conditional.getrValue2() != null) {
IntValueInterval interval1 = getInterval(conditional.getrValue1());
IntValueInterval interval2 = getInterval(conditional.getrValue2());
if(interval1 != null && interval2 != null) {
if(Operators.LT.equals(conditional.getOperator())) {
if(interval1.maxValue < interval2.minValue) {
return new ConstantBool(true);
} else if(interval1.minValue >= interval2.maxValue) {
return new ConstantBool(false);
} else {
return null;
}
} else if(Operators.LE.equals(conditional.getOperator())) {
if(interval1.maxValue <= interval2.minValue) {
return new ConstantBool(true);
} else if(interval1.minValue > interval2.maxValue) {
return new ConstantBool(false);
} else {
return null;
}
} else if(Operators.GT.equals(conditional.getOperator())) {
if(interval1.minValue > interval2.maxValue) {
return new ConstantBool(true);
} else if(interval1.maxValue <= interval2.minValue) {
return new ConstantBool(false);
} else {
return null;
}
} else if(Operators.GE.equals(conditional.getOperator())) {
if(interval1.minValue >= interval2.maxValue) {
return new ConstantBool(true);
} else if(interval1.maxValue < interval2.minValue) {
return new ConstantBool(false);
} else {
return null;
}
} else if(Operators.EQ.equals(conditional.getOperator())) {
if(interval1.minValue > interval2.maxValue) {
return new ConstantBool(false);
} else if(interval1.maxValue < interval2.minValue) {
return new ConstantBool(false);
} else {
return null;
}
} else if(Operators.NEQ.equals(conditional.getOperator())) {
if(interval1.minValue > interval2.maxValue) {
return new ConstantBool(true);
} else if(interval1.maxValue < interval2.minValue) {
return new ConstantBool(true);
} else {
return null;
}
}
}
}
return null;
}
/** Interval of integer types. */
static class IntValueInterval {
long minValue;
long maxValue;
public IntValueInterval(long minValue, long maxValue) {
this.minValue = minValue;
this.maxValue = maxValue;
}
}
private IntValueInterval getInterval(RValue rValue) {
ConstantValue constValue = Pass2ConstantIdentification.getConstant(rValue);
if(constValue != null) {
try {
ConstantLiteral constantLiteral = constValue.calculateLiteral(getScope());
if(constantLiteral instanceof ConstantInteger) {
Long value = ((ConstantInteger) constantLiteral).getInteger();
return new IntValueInterval(value, value);
}
} catch(ConstantNotLiteral e) {
// not literal - keep as null
}
}
// Not constant - find the interval of the type
SymbolType symbolType = SymbolTypeInference.inferType(getScope(), rValue);
if(symbolType instanceof SymbolTypeIntegerFixed) {
SymbolTypeIntegerFixed typeIntegerFixed = (SymbolTypeIntegerFixed) symbolType;
return new IntValueInterval(typeIntegerFixed.getMinValue(), typeIntegerFixed.getMaxValue());
} else if(symbolType.equals(SymbolType.UNUMBER)) {
// Positive number
return new IntValueInterval(0L, Long.MAX_VALUE);
}
// Not a constant integer
return null;
}
} }

View File

@ -4,14 +4,10 @@
:BasicUpstart(main) :BasicUpstart(main)
.pc = $80d "Program" .pc = $80d "Program"
main: { main: {
.label screen = $400
ldx #0 ldx #0
b1: b2:
lda ball_active,x
lda ball_active,x
inx inx
cpx #8 cpx #8
bne b1 bne b2
rts rts
} }
ball_active: .byte 0, 1, 0, 1, 0, 1, 1, 1

View File

@ -12,22 +12,11 @@ main: scope:[main] from @1
to:main::@1 to:main::@1
main::@1: scope:[main] from main main::@2 main::@1: scope:[main] from main main::@2
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 ) [5] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
[6] if(*((const byte[8]) ball_active#0 + (byte) main::i#2)>=(byte) 0) goto main::@2
to:main::@3
main::@3: scope:[main] from main::@1
[7] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '-'
to:main::@2 to:main::@2
main::@2: scope:[main] from main::@1 main::@3 main::@2: scope:[main] from main::@1
[8] (byte) main::temp#1 ← *((const byte[8]) ball_active#0 + (byte) main::i#2) [6] (byte) main::i#1 ← ++ (byte) main::i#2
[9] (byte) main::i#1 ← ++ (byte) main::i#2 [7] if((byte) main::i#1!=(byte) 8) goto main::@1
[10] if((byte) main::i#1!=(byte) 8) goto main::@1
to:main::@4
main::@4: scope:[main] from main::@2
[11] if((byte) main::temp#1>=(byte) 0) goto main::@return
to:main::@5
main::@5: scope:[main] from main::@4
[12] *((const byte*) main::screen#0+(byte) $28) ← (byte) main::temp#1
to:main::@return to:main::@return
main::@return: scope:[main] from main::@4 main::@5 main::@return: scope:[main] from main::@2
[13] return [8] return
to:@return to:@return

View File

@ -123,40 +123,48 @@ Constant (const byte*) main::screen#0 = (byte*) 1024
Constant (const byte) main::temp#0 = 0 Constant (const byte) main::temp#0 = 0
Constant (const byte) main::i#0 = 0 Constant (const byte) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification Successful SSA optimization Pass2ConstantIdentification
if() condition always true - replacing block destination [7] if(*((const byte[8]) ball_active#0 + (byte) main::i#2)>=(byte) 0) goto main::@3
if() condition always true - replacing block destination [18] if((byte) main::temp#1>=(byte) 0) goto main::@return
Successful SSA optimization Pass2ConstantIfs
Resolved ranged next value [10] main::i#1 ← ++ main::i#2 to ++ Resolved ranged next value [10] main::i#1 ← ++ main::i#2 to ++
Resolved ranged comparison value [12] if(main::i#1!=rangelast(0,7)) goto main::@2 to (number) 8 Resolved ranged comparison value [12] if(main::i#1!=rangelast(0,7)) goto main::@2 to (number) 8
Eliminating unused constant (const byte) main::temp#0 Eliminating unused constant (const byte) main::temp#0
Successful SSA optimization PassNEliminateUnusedVars Successful SSA optimization PassNEliminateUnusedVars
Removing unused block main::@4
Removing unused block main::@6
Successful SSA optimization Pass2EliminateUnusedBlocks
Adding number conversion cast (unumber) 8 in if((byte) main::i#1!=(number) 8) goto main::@2 Adding number conversion cast (unumber) 8 in if((byte) main::i#1!=(number) 8) goto main::@2
Successful SSA optimization PassNAddNumberTypeConversions Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant integer cast 8 Simplifying constant integer cast 8
Successful SSA optimization PassNCastSimplification Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 8 Finalized unsigned number type (byte) 8
Successful SSA optimization PassNFinalizeNumberTypeConversions Successful SSA optimization PassNFinalizeNumberTypeConversions
Eliminating unused variable (byte) main::temp#1 and assignment [1] (byte) main::temp#1 ← *((const byte[8]) ball_active#0 + (byte) main::i#2)
Eliminating unused constant (const byte*) main::screen#0
Successful SSA optimization PassNEliminateUnusedVars
Eliminating unused constant (const byte[8]) ball_active#0
Successful SSA optimization PassNEliminateUnusedVars
Inlining constant with var siblings (const byte) main::i#0 Inlining constant with var siblings (const byte) main::i#0
Constant inlined main::i#0 = (byte) 0 Constant inlined main::i#0 = (byte) 0
Successful SSA optimization Pass2ConstantInlining Successful SSA optimization Pass2ConstantInlining
Consolidated array index constant in *(main::screen#0+$28)
Successful SSA optimization Pass2ConstantAdditionElimination
Added new block during phi lifting main::@7(between main::@3 and main::@2) Added new block during phi lifting main::@7(between main::@3 and main::@2)
Adding NOP phi() at start of @begin Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1 Adding NOP phi() at start of @1
Adding NOP phi() at start of @2 Adding NOP phi() at start of @2
Adding NOP phi() at start of @end Adding NOP phi() at start of @end
Adding NOP phi() at start of main Adding NOP phi() at start of main
Adding NOP phi() at start of main::@5
CALL GRAPH CALL GRAPH
Calls in [] to main:2 Calls in [] to main:2
Created 1 initial phi equivalence classes Created 1 initial phi equivalence classes
Coalesced [15] main::i#5 ← main::i#1 Coalesced [11] main::i#5 ← main::i#1
Coalesced down to 1 phi equivalence classes Coalesced down to 1 phi equivalence classes
Culled Empty Block (label) @2 Culled Empty Block (label) @2
Culled Empty Block (label) main::@5
Culled Empty Block (label) main::@7 Culled Empty Block (label) main::@7
Renumbering block main::@2 to main::@1 Renumbering block main::@2 to main::@1
Renumbering block main::@3 to main::@2 Renumbering block main::@3 to main::@2
Renumbering block main::@4 to main::@3
Renumbering block main::@5 to main::@4
Renumbering block main::@6 to main::@5
Adding NOP phi() at start of @begin Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1 Adding NOP phi() at start of @1
Adding NOP phi() at start of @end Adding NOP phi() at start of @end
@ -177,24 +185,13 @@ main: scope:[main] from @1
to:main::@1 to:main::@1
main::@1: scope:[main] from main main::@2 main::@1: scope:[main] from main main::@2
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 ) [5] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
[6] if(*((const byte[8]) ball_active#0 + (byte) main::i#2)>=(byte) 0) goto main::@2
to:main::@3
main::@3: scope:[main] from main::@1
[7] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '-'
to:main::@2 to:main::@2
main::@2: scope:[main] from main::@1 main::@3 main::@2: scope:[main] from main::@1
[8] (byte) main::temp#1 ← *((const byte[8]) ball_active#0 + (byte) main::i#2) [6] (byte) main::i#1 ← ++ (byte) main::i#2
[9] (byte) main::i#1 ← ++ (byte) main::i#2 [7] if((byte) main::i#1!=(byte) 8) goto main::@1
[10] if((byte) main::i#1!=(byte) 8) goto main::@1
to:main::@4
main::@4: scope:[main] from main::@2
[11] if((byte) main::temp#1>=(byte) 0) goto main::@return
to:main::@5
main::@5: scope:[main] from main::@4
[12] *((const byte*) main::screen#0+(byte) $28) ← (byte) main::temp#1
to:main::@return to:main::@return
main::@return: scope:[main] from main::@4 main::@5 main::@return: scope:[main] from main::@2
[13] return [8] return
to:@return to:@return
@ -203,19 +200,15 @@ VARIABLE REGISTER WEIGHTS
(void()) main() (void()) main()
(byte) main::i (byte) main::i
(byte) main::i#1 16.5 (byte) main::i#1 16.5
(byte) main::i#2 13.75 (byte) main::i#2 22.0
(byte*) main::screen (byte*) main::screen
(byte) main::temp (byte) main::temp
(byte) main::temp#1 3.75
Initial phi equivalence classes Initial phi equivalence classes
[ main::i#2 main::i#1 ] [ main::i#2 main::i#1 ]
Added variable main::temp#1 to zero page equivalence class [ main::temp#1 ]
Complete equivalence classes Complete equivalence classes
[ main::i#2 main::i#1 ] [ main::i#2 main::i#1 ]
[ main::temp#1 ]
Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ] Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Allocated zp ZP_BYTE:3 [ main::temp#1 ]
INITIAL ASM INITIAL ASM
Target platform is c64basic Target platform is c64basic
@ -245,8 +238,6 @@ bend_from_b1:
bend: bend:
// main // main
main: { main: {
.label screen = $400
.label temp = 3
.label i = 2 .label i = 2
// [5] phi from main to main::@1 [phi:main->main::@1] // [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main: b1_from_main:
@ -260,66 +251,32 @@ main: {
jmp b1 jmp b1
// main::@1 // main::@1
b1: b1:
// [6] if(*((const byte[8]) ball_active#0 + (byte) main::i#2)>=(byte) 0) goto main::@2 -- pbuc1_derefidx_vbuz1_ge_0_then_la1
ldy.z i
lda ball_active,y
jmp b2
jmp b3
// main::@3
b3:
// [7] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '-' -- pbuc1_derefidx_vbuz1=vbuc2
lda #'-'
ldy.z i
sta screen,y
jmp b2 jmp b2
// main::@2 // main::@2
b2: b2:
// [8] (byte) main::temp#1 ← *((const byte[8]) ball_active#0 + (byte) main::i#2) -- vbuz1=pbuc1_derefidx_vbuz2 // [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
ldy.z i
lda ball_active,y
sta.z temp
// [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc.z i inc.z i
// [10] if((byte) main::i#1!=(byte) 8) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 // [7] if((byte) main::i#1!=(byte) 8) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda #8 lda #8
cmp.z i cmp.z i
bne b1_from_b2 bne b1_from_b2
jmp b4
// main::@4
b4:
// [11] if((byte) main::temp#1>=(byte) 0) goto main::@return -- vbuz1_ge_0_then_la1
lda.z temp
jmp breturn
jmp b5
// main::@5
b5:
// [12] *((const byte*) main::screen#0+(byte) $28) ← (byte) main::temp#1 -- _deref_pbuc1=vbuz1
lda.z temp
sta screen+$28
jmp breturn jmp breturn
// main::@return // main::@return
breturn: breturn:
// [13] return // [8] return
rts rts
} }
// File Data // File Data
ball_active: .byte 0, 1, 0, 1, 0, 1, 1, 1
REGISTER UPLIFT POTENTIAL REGISTERS REGISTER UPLIFT POTENTIAL REGISTERS
Statement [6] if(*((const byte[8]) ball_active#0 + (byte) main::i#2)>=(byte) 0) goto main::@2 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte a , reg byte x , reg byte y ,
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Statement [7] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '-' [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
Statement [6] if(*((const byte[8]) ball_active#0 + (byte) main::i#2)>=(byte) 0) goto main::@2 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
Statement [7] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '-' [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:3 [ main::temp#1 ] : zp ZP_BYTE:3 , reg byte a , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES REGISTER UPLIFT SCOPES
Uplift Scope [main] 30.25: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 3.75: zp ZP_BYTE:3 [ main::temp#1 ] Uplift Scope [main] 38.5: zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Uplift Scope [] Uplift Scope []
Uplifting [main] best 456 combination reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::temp#1 ] Uplifting [main] best 223 combination reg byte x [ main::i#2 main::i#1 ]
Uplifting [] best 456 combination Uplifting [] best 223 combination
ASSEMBLER BEFORE OPTIMIZATION ASSEMBLER BEFORE OPTIMIZATION
// File Comments // File Comments
@ -348,7 +305,6 @@ bend_from_b1:
bend: bend:
// main // main
main: { main: {
.label screen = $400
// [5] phi from main to main::@1 [phi:main->main::@1] // [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main: b1_from_main:
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 // [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
@ -360,113 +316,70 @@ main: {
jmp b1 jmp b1
// main::@1 // main::@1
b1: b1:
// [6] if(*((const byte[8]) ball_active#0 + (byte) main::i#2)>=(byte) 0) goto main::@2 -- pbuc1_derefidx_vbuxx_ge_0_then_la1
lda ball_active,x
jmp b2
jmp b3
// main::@3
b3:
// [7] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '-' -- pbuc1_derefidx_vbuxx=vbuc2
lda #'-'
sta screen,x
jmp b2 jmp b2
// main::@2 // main::@2
b2: b2:
// [8] (byte) main::temp#1 ← *((const byte[8]) ball_active#0 + (byte) main::i#2) -- vbuaa=pbuc1_derefidx_vbuxx // [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
lda ball_active,x
// [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx inx
// [10] if((byte) main::i#1!=(byte) 8) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 // [7] if((byte) main::i#1!=(byte) 8) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #8 cpx #8
bne b1_from_b2 bne b1_from_b2
jmp b4
// main::@4
b4:
// [11] if((byte) main::temp#1>=(byte) 0) goto main::@return -- vbuaa_ge_0_then_la1
jmp breturn
jmp b5
// main::@5
b5:
// [12] *((const byte*) main::screen#0+(byte) $28) ← (byte) main::temp#1 -- _deref_pbuc1=vbuaa
sta screen+$28
jmp breturn jmp breturn
// main::@return // main::@return
breturn: breturn:
// [13] return // [8] return
rts rts
} }
// File Data // File Data
ball_active: .byte 0, 1, 0, 1, 0, 1, 1, 1
ASSEMBLER OPTIMIZATIONS ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1 Removing instruction jmp b1
Removing instruction jmp bend Removing instruction jmp bend
Removing instruction jmp b1 Removing instruction jmp b1
Removing instruction jmp b3
Removing instruction jmp b2 Removing instruction jmp b2
Removing instruction jmp b4
Removing instruction jmp b5
Removing instruction jmp breturn Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination Succesful ASM optimization Pass5NextJumpElimination
Replacing label b1_from_b2 with b1 Replacing label b1 with b2
Replacing label b1_from_b2 with b2
Removing instruction b1_from_bbegin: Removing instruction b1_from_bbegin:
Removing instruction b1: Removing instruction b1:
Removing instruction main_from_b1: Removing instruction main_from_b1:
Removing instruction bend_from_b1: Removing instruction bend_from_b1:
Removing instruction b1_from_b2: Removing instruction b1_from_b2:
Removing instruction b1:
Succesful ASM optimization Pass5RedundantLabelElimination Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend: Removing instruction bend:
Removing instruction b1_from_main: Removing instruction b1_from_main:
Removing instruction b3: Removing instruction breturn:
Removing instruction b4:
Removing instruction b5:
Succesful ASM optimization Pass5UnusedLabelElimination Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly Updating BasicUpstart to call main directly
Removing instruction jsr main Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin Succesful ASM optimization Pass5SkipBegin
Replacing jump to rts with rts in jmp breturn
Succesful ASM optimization Pass5DoubleJumpElimination
Removing unreachable instruction lda #'-'
Removing unreachable instruction sta screen,x
Removing unreachable instruction sta screen+$28
Succesful ASM optimization Pass5UnreachableCodeElimination
Removing instruction jmp b1
Removing instruction jmp b2 Removing instruction jmp b2
Succesful ASM optimization Pass5NextJumpElimination Succesful ASM optimization Pass5NextJumpElimination
Removing instruction bbegin: Removing instruction bbegin:
Removing instruction b2:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination Succesful ASM optimization Pass5UnusedLabelElimination
Removing unreachable instruction rts
Succesful ASM optimization Pass5UnreachableCodeElimination
FINAL SYMBOL TABLE FINAL SYMBOL TABLE
(label) @1 (label) @1
(label) @begin (label) @begin
(label) @end (label) @end
(byte[8]) ball_active (byte[8]) ball_active
(const byte[8]) ball_active#0 ball_active = { (byte) 0, (byte) 1, (byte) 0, (byte) 1, (byte) 0, (byte) 1, (byte) 1, (byte) 1 }
(void()) main() (void()) main()
(label) main::@1 (label) main::@1
(label) main::@2 (label) main::@2
(label) main::@3
(label) main::@4
(label) main::@5
(label) main::@return (label) main::@return
(byte) main::i (byte) main::i
(byte) main::i#1 reg byte x 16.5 (byte) main::i#1 reg byte x 16.5
(byte) main::i#2 reg byte x 13.75 (byte) main::i#2 reg byte x 22.0
(byte*) main::screen (byte*) main::screen
(const byte*) main::screen#0 screen = (byte*) 1024
(byte) main::temp (byte) main::temp
(byte) main::temp#1 reg byte a 3.75
reg byte x [ main::i#2 main::i#1 ] reg byte x [ main::i#2 main::i#1 ]
reg byte a [ main::temp#1 ]
FINAL ASSEMBLER FINAL ASSEMBLER
Score: 181 Score: 91
// File Comments // File Comments
// Examples of unsigned comparisons to values outside the range of unsigned // Examples of unsigned comparisons to values outside the range of unsigned
@ -485,41 +398,24 @@ Score: 181
// @end // @end
// main // main
main: { main: {
.label screen = $400
// [5] phi from main to main::@1 [phi:main->main::@1] // [5] phi from main to main::@1 [phi:main->main::@1]
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 // [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0 ldx #0
// [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1] // [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy // [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
// main::@1 // main::@1
b1:
// if (ball_active[i]<0)
// [6] if(*((const byte[8]) ball_active#0 + (byte) main::i#2)>=(byte) 0) goto main::@2 -- pbuc1_derefidx_vbuxx_ge_0_then_la1
lda ball_active,x
// main::@3
// screen[i] = '-'
// [7] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '-' -- pbuc1_derefidx_vbuxx=vbuc2
// main::@2 // main::@2
// temp = ball_active[i] b2:
// [8] (byte) main::temp#1 ← *((const byte[8]) ball_active#0 + (byte) main::i#2) -- vbuaa=pbuc1_derefidx_vbuxx
lda ball_active,x
// for( char i: 0..7) // for( char i: 0..7)
// [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx // [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx inx
// [10] if((byte) main::i#1!=(byte) 8) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 // [7] if((byte) main::i#1!=(byte) 8) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #8 cpx #8
bne b1 bne b2
// main::@4
// if (temp<0)
// [11] if((byte) main::temp#1>=(byte) 0) goto main::@return -- vbuaa_ge_0_then_la1
rts
// main::@5
// screen[40] = temp
// [12] *((const byte*) main::screen#0+(byte) $28) ← (byte) main::temp#1 -- _deref_pbuc1=vbuaa
// main::@return // main::@return
// } // }
// [13] return // [8] return
rts
} }
// File Data // File Data
ball_active: .byte 0, 1, 0, 1, 0, 1, 1, 1

View File

@ -2,21 +2,14 @@
(label) @begin (label) @begin
(label) @end (label) @end
(byte[8]) ball_active (byte[8]) ball_active
(const byte[8]) ball_active#0 ball_active = { (byte) 0, (byte) 1, (byte) 0, (byte) 1, (byte) 0, (byte) 1, (byte) 1, (byte) 1 }
(void()) main() (void()) main()
(label) main::@1 (label) main::@1
(label) main::@2 (label) main::@2
(label) main::@3
(label) main::@4
(label) main::@5
(label) main::@return (label) main::@return
(byte) main::i (byte) main::i
(byte) main::i#1 reg byte x 16.5 (byte) main::i#1 reg byte x 16.5
(byte) main::i#2 reg byte x 13.75 (byte) main::i#2 reg byte x 22.0
(byte*) main::screen (byte*) main::screen
(const byte*) main::screen#0 screen = (byte*) 1024
(byte) main::temp (byte) main::temp
(byte) main::temp#1 reg byte a 3.75
reg byte x [ main::i#2 main::i#1 ] reg byte x [ main::i#2 main::i#1 ]
reg byte a [ main::temp#1 ]