From 67157f0a7079778b3e040ca6e0014d6e3f6d161c Mon Sep 17 00:00:00 2001 From: Jesper Gravgaard Date: Thu, 29 Aug 2019 20:05:08 +0200 Subject: [PATCH] Implemented interval analysis for detecting conditions that are always true/false. Closes #291 --- .../kickc/passes/Pass2ConstantIfs.java | 134 +++++++++++-- .../ref/optimize-unsigned-comparisons.asm | 8 +- .../ref/optimize-unsigned-comparisons.cfg | 21 +- .../ref/optimize-unsigned-comparisons.log | 188 ++++-------------- .../ref/optimize-unsigned-comparisons.sym | 9 +- 5 files changed, 168 insertions(+), 192 deletions(-) diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIfs.java b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIfs.java index 651d7ed8b..30362dac9 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIfs.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIfs.java @@ -2,15 +2,18 @@ package dk.camelot64.kickc.passes; import dk.camelot64.kickc.model.ConstantNotLiteral; import dk.camelot64.kickc.model.ControlFlowBlock; +import dk.camelot64.kickc.model.InternalError; import dk.camelot64.kickc.model.Program; import dk.camelot64.kickc.model.operators.Operator; import dk.camelot64.kickc.model.operators.OperatorBinary; 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.StatementConditionalJump; -import dk.camelot64.kickc.model.values.ConstantBool; -import dk.camelot64.kickc.model.values.ConstantLiteral; -import dk.camelot64.kickc.model.values.ConstantValue; +import dk.camelot64.kickc.model.types.SymbolType; +import dk.camelot64.kickc.model.types.SymbolTypeInference; +import dk.camelot64.kickc.model.types.SymbolTypeIntegerFixed; +import dk.camelot64.kickc.model.values.*; import java.util.ListIterator; @@ -38,8 +41,11 @@ public class Pass2ConstantIfs extends Pass2SsaOptimization { Statement statement = stmtIt.next(); if(statement instanceof StatementConditionalJump) { StatementConditionalJump conditional = (StatementConditionalJump) statement; - ConstantLiteral literal = getConditionLiteralValue(conditional); - if(literal!=null && literal instanceof ConstantBool) { + ConstantLiteral literal = findConditionLiteral(conditional); + if(literal == null) { + literal = findConditionLiteralInterval(conditional); + } + if(literal != null && literal instanceof ConstantBool) { // Condition is a constant boolean if(((ConstantBool) literal).getBool()) { // Always true - replace default successor and drop conditional jump @@ -49,7 +55,7 @@ public class Pass2ConstantIfs extends Pass2SsaOptimization { stmtIt.remove(); block.setConditionalSuccessor(null); modified = true; - } else { + } else { // Always false - drop the conditional jump Pass2EliminateUnusedBlocks.removePhiRValues(block.getLabel(), getGraph().getConditionalSuccessor(block), getLog()); 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. + * * @param conditional The conditional * @return The literal value of the condition */ - private ConstantLiteral getConditionLiteralValue(StatementConditionalJump conditional) { + private ConstantLiteral findConditionLiteral(StatementConditionalJump conditional) { ConstantValue constValue1 = Pass2ConstantIdentification.getConstant(conditional.getrValue1()); Operator operator = conditional.getOperator(); ConstantValue constValue2 = Pass2ConstantIdentification.getConstant(conditional.getrValue2()); try { // If all values are constant find the literal condition value - if(conditional.getrValue1() == null && operator == null && constValue2 != null) { // Constant condition return constValue2.calculateLiteral(getScope()); @@ -90,17 +96,113 @@ public class Pass2ConstantIfs extends Pass2SsaOptimization { return constVal.calculateLiteral(getScope()); } - // Examine the intervals of the comparison parameters - - // TODO: Compare intervals based on the operator - - - - - } catch (ConstantNotLiteral e) { + } catch(ConstantNotLiteral e) { // not literal - keep as 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; + } + } diff --git a/src/test/ref/optimize-unsigned-comparisons.asm b/src/test/ref/optimize-unsigned-comparisons.asm index d888f7f44..9f77ba449 100644 --- a/src/test/ref/optimize-unsigned-comparisons.asm +++ b/src/test/ref/optimize-unsigned-comparisons.asm @@ -4,14 +4,10 @@ :BasicUpstart(main) .pc = $80d "Program" main: { - .label screen = $400 ldx #0 - b1: - lda ball_active,x - lda ball_active,x + b2: inx cpx #8 - bne b1 + bne b2 rts } - ball_active: .byte 0, 1, 0, 1, 0, 1, 1, 1 diff --git a/src/test/ref/optimize-unsigned-comparisons.cfg b/src/test/ref/optimize-unsigned-comparisons.cfg index 334a41565..8e8f08fa8 100644 --- a/src/test/ref/optimize-unsigned-comparisons.cfg +++ b/src/test/ref/optimize-unsigned-comparisons.cfg @@ -12,22 +12,11 @@ main: scope:[main] from @1 to:main::@1 main::@1: scope:[main] from main main::@2 [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 -main::@2: scope:[main] from main::@1 main::@3 - [8] (byte) main::temp#1 ← *((const byte[8]) ball_active#0 + (byte) main::i#2) - [9] (byte) main::i#1 ← ++ (byte) main::i#2 - [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 +main::@2: scope:[main] from main::@1 + [6] (byte) main::i#1 ← ++ (byte) main::i#2 + [7] if((byte) main::i#1!=(byte) 8) goto main::@1 to:main::@return -main::@return: scope:[main] from main::@4 main::@5 - [13] return +main::@return: scope:[main] from main::@2 + [8] return to:@return diff --git a/src/test/ref/optimize-unsigned-comparisons.log b/src/test/ref/optimize-unsigned-comparisons.log index 052fc5e74..9806b9473 100644 --- a/src/test/ref/optimize-unsigned-comparisons.log +++ b/src/test/ref/optimize-unsigned-comparisons.log @@ -123,40 +123,48 @@ Constant (const byte*) main::screen#0 = (byte*) 1024 Constant (const byte) main::temp#0 = 0 Constant (const byte) main::i#0 = 0 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 comparison value [12] if(main::i#1!=rangelast(0,7)) goto main::@2 to (number) 8 Eliminating unused constant (const byte) main::temp#0 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 Successful SSA optimization PassNAddNumberTypeConversions Simplifying constant integer cast 8 Successful SSA optimization PassNCastSimplification Finalized unsigned number type (byte) 8 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 Constant inlined main::i#0 = (byte) 0 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) Adding NOP phi() at start of @begin Adding NOP phi() at start of @1 Adding NOP phi() at start of @2 Adding NOP phi() at start of @end Adding NOP phi() at start of main +Adding NOP phi() at start of main::@5 CALL GRAPH Calls in [] to main:2 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 Culled Empty Block (label) @2 +Culled Empty Block (label) main::@5 Culled Empty Block (label) main::@7 Renumbering block main::@2 to main::@1 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 @1 Adding NOP phi() at start of @end @@ -177,24 +185,13 @@ main: scope:[main] from @1 to:main::@1 main::@1: scope:[main] from main main::@2 [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 -main::@2: scope:[main] from main::@1 main::@3 - [8] (byte) main::temp#1 ← *((const byte[8]) ball_active#0 + (byte) main::i#2) - [9] (byte) main::i#1 ← ++ (byte) main::i#2 - [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 +main::@2: scope:[main] from main::@1 + [6] (byte) main::i#1 ← ++ (byte) main::i#2 + [7] if((byte) main::i#1!=(byte) 8) goto main::@1 to:main::@return -main::@return: scope:[main] from main::@4 main::@5 - [13] return +main::@return: scope:[main] from main::@2 + [8] return to:@return @@ -203,19 +200,15 @@ VARIABLE REGISTER WEIGHTS (void()) main() (byte) main::i (byte) main::i#1 16.5 -(byte) main::i#2 13.75 +(byte) main::i#2 22.0 (byte*) main::screen (byte) main::temp -(byte) main::temp#1 3.75 Initial phi equivalence classes [ main::i#2 main::i#1 ] -Added variable main::temp#1 to zero page equivalence class [ main::temp#1 ] Complete equivalence classes [ main::i#2 main::i#1 ] -[ main::temp#1 ] Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ] -Allocated zp ZP_BYTE:3 [ main::temp#1 ] INITIAL ASM Target platform is c64basic @@ -245,8 +238,6 @@ bend_from_b1: bend: // main main: { - .label screen = $400 - .label temp = 3 .label i = 2 // [5] phi from main to main::@1 [phi:main->main::@1] b1_from_main: @@ -260,66 +251,32 @@ main: { jmp b1 // main::@1 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 // main::@2 b2: - // [8] (byte) main::temp#1 ← *((const byte[8]) ball_active#0 + (byte) main::i#2) -- vbuz1=pbuc1_derefidx_vbuz2 - ldy.z i - lda ball_active,y - sta.z temp - // [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 + // [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 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 cmp.z i 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 // main::@return breturn: - // [13] return + // [8] return rts } // File Data - ball_active: .byte 0, 1, 0, 1, 0, 1, 1, 1 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 -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 , +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 , 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 [] -Uplifting [main] best 456 combination reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::temp#1 ] -Uplifting [] best 456 combination +Uplifting [main] best 223 combination reg byte x [ main::i#2 main::i#1 ] +Uplifting [] best 223 combination ASSEMBLER BEFORE OPTIMIZATION // File Comments @@ -348,7 +305,6 @@ bend_from_b1: bend: // main main: { - .label screen = $400 // [5] phi from main to main::@1 [phi:main->main::@1] b1_from_main: // [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 @@ -360,113 +316,70 @@ main: { jmp b1 // main::@1 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 // main::@2 b2: - // [8] (byte) main::temp#1 ← *((const byte[8]) ball_active#0 + (byte) main::i#2) -- vbuaa=pbuc1_derefidx_vbuxx - lda ball_active,x - // [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 - // [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 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 // main::@return breturn: - // [13] return + // [8] return rts } // File Data - ball_active: .byte 0, 1, 0, 1, 0, 1, 1, 1 ASSEMBLER OPTIMIZATIONS Removing instruction jmp b1 Removing instruction jmp bend Removing instruction jmp b1 -Removing instruction jmp b3 Removing instruction jmp b2 -Removing instruction jmp b4 -Removing instruction jmp b5 Removing instruction jmp breturn 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: Removing instruction main_from_b1: Removing instruction bend_from_b1: Removing instruction b1_from_b2: +Removing instruction b1: Succesful ASM optimization Pass5RedundantLabelElimination Removing instruction bend: Removing instruction b1_from_main: -Removing instruction b3: -Removing instruction b4: -Removing instruction b5: +Removing instruction breturn: Succesful ASM optimization Pass5UnusedLabelElimination Updating BasicUpstart to call main directly Removing instruction jsr main 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 Succesful ASM optimization Pass5NextJumpElimination Removing instruction bbegin: -Removing instruction b2: -Removing instruction breturn: Succesful ASM optimization Pass5UnusedLabelElimination -Removing unreachable instruction rts -Succesful ASM optimization Pass5UnreachableCodeElimination FINAL SYMBOL TABLE (label) @1 (label) @begin (label) @end (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() (label) main::@1 (label) main::@2 -(label) main::@3 -(label) main::@4 -(label) main::@5 (label) main::@return (byte) main::i (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 -(const byte*) main::screen#0 screen = (byte*) 1024 (byte) main::temp -(byte) main::temp#1 reg byte a 3.75 reg byte x [ main::i#2 main::i#1 ] -reg byte a [ main::temp#1 ] FINAL ASSEMBLER -Score: 181 +Score: 91 // File Comments // Examples of unsigned comparisons to values outside the range of unsigned @@ -485,41 +398,24 @@ Score: 181 // @end // main main: { - .label screen = $400 // [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 ldx #0 // [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 // 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 - // temp = ball_active[i] - // [8] (byte) main::temp#1 ← *((const byte[8]) ball_active#0 + (byte) main::i#2) -- vbuaa=pbuc1_derefidx_vbuxx - lda ball_active,x + b2: // 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 - // [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 - bne b1 - // 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 + bne b2 // main::@return // } - // [13] return + // [8] return + rts } // File Data - ball_active: .byte 0, 1, 0, 1, 0, 1, 1, 1 diff --git a/src/test/ref/optimize-unsigned-comparisons.sym b/src/test/ref/optimize-unsigned-comparisons.sym index 59af6a4b5..48fdf20df 100644 --- a/src/test/ref/optimize-unsigned-comparisons.sym +++ b/src/test/ref/optimize-unsigned-comparisons.sym @@ -2,21 +2,14 @@ (label) @begin (label) @end (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() (label) main::@1 (label) main::@2 -(label) main::@3 -(label) main::@4 -(label) main::@5 (label) main::@return (byte) main::i (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 -(const byte*) main::screen#0 screen = (byte*) 1024 (byte) main::temp -(byte) main::temp#1 reg byte a 3.75 reg byte x [ main::i#2 main::i#1 ] -reg byte a [ main::temp#1 ]