1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-12-28 16:31:36 +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.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;
}
}

View File

@ -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

View File

@ -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

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::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

View File

@ -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 ]