diff --git a/src/main/java/dk/camelot64/kickc/Compiler.java b/src/main/java/dk/camelot64/kickc/Compiler.java index c0e8b3084..23310454f 100644 --- a/src/main/java/dk/camelot64/kickc/Compiler.java +++ b/src/main/java/dk/camelot64/kickc/Compiler.java @@ -222,6 +222,7 @@ public class Compiler { assertions.add(new Pass2AssertNoLabels(program)); assertions.add(new Pass2AssertSingleAssignment(program)); assertions.add(new Pass2AssertRValues(program)); + //assertions.add(new Pass2AssertPhiPredecessors(program)); for(Pass2SsaAssertion assertion : assertions) { assertion.check(); } diff --git a/src/main/java/dk/camelot64/kickc/model/StatementSequence.java b/src/main/java/dk/camelot64/kickc/model/StatementSequence.java index 8f1461c83..754286877 100644 --- a/src/main/java/dk/camelot64/kickc/model/StatementSequence.java +++ b/src/main/java/dk/camelot64/kickc/model/StatementSequence.java @@ -4,6 +4,7 @@ import dk.camelot64.kickc.model.statements.Statement; import dk.camelot64.kickc.model.statements.StatementLabel; import dk.camelot64.kickc.model.statements.StatementProcedureBegin; import dk.camelot64.kickc.model.statements.StatementProcedureEnd; +import dk.camelot64.kickc.model.values.LabelRef; import java.util.ArrayList; import java.util.List; @@ -11,7 +12,7 @@ import java.util.List; /** A sequence of Statements */ public class StatementSequence { - private List statements; + private ArrayList statements; public StatementSequence() { this.statements = new ArrayList<>(); @@ -43,4 +44,17 @@ public class StatementSequence { return out.toString(); } + /** + * Look backwar from the end of the sequence and find the last label + * @return The label of the block, currently being build + */ + public LabelRef getCurrentBlockLabel() { + for(int i = statements.size()-1; i >= 0; i--) { + Statement statement = statements.get(i); + if(statement instanceof StatementLabel) { + return ((StatementLabel) statement).getLabel(); + } + } + return null; + } } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java index d060c9682..6889b48b4 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java @@ -1371,18 +1371,20 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor { RValue falseValue = (RValue) this.visit(ctx.expr(2)); VariableRef falseVar = getCurrentScope().addVariableIntermediate().getRef(); sequence.addStatement(new StatementAssignment(falseVar, null, null, falseValue, new StatementSource(ctx), Comment.NO_COMMENTS)); + LabelRef falseExitLabel = sequence.getCurrentBlockLabel(); sequence.addStatement(new StatementJump(endJumpLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS)); sequence.addStatement(new StatementLabel(trueLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS)); RValue trueValue = (RValue) this.visit(ctx.expr(1)); VariableRef trueVar = getCurrentScope().addVariableIntermediate().getRef(); sequence.addStatement(new StatementAssignment(trueVar, null, null, trueValue, new StatementSource(ctx), Comment.NO_COMMENTS)); + LabelRef trueExitLabel = sequence.getCurrentBlockLabel(); sequence.addStatement(new StatementLabel(endJumpLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS)); StatementPhiBlock phiBlock = new StatementPhiBlock(Comment.NO_COMMENTS); phiBlock.setSource(new StatementSource(ctx)); VariableRef finalVar = getCurrentScope().addVariableIntermediate().getRef(); StatementPhiBlock.PhiVariable phiVariable = phiBlock.addPhiVariable(finalVar); - phiVariable.setrValue(trueLabel.getRef(), trueVar); - phiVariable.setrValue(falseLabel.getRef(), falseVar); + phiVariable.setrValue(trueExitLabel, trueVar); + phiVariable.setrValue(falseExitLabel, falseVar); sequence.addStatement(phiBlock); return finalVar; } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2AssertPhiPredecessors.java b/src/main/java/dk/camelot64/kickc/passes/Pass2AssertPhiPredecessors.java new file mode 100644 index 000000000..781346e6b --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2AssertPhiPredecessors.java @@ -0,0 +1,38 @@ +package dk.camelot64.kickc.passes; + +import dk.camelot64.kickc.model.CompileError; +import dk.camelot64.kickc.model.ControlFlowBlock; +import dk.camelot64.kickc.model.Program; +import dk.camelot64.kickc.model.statements.StatementPhiBlock; +import dk.camelot64.kickc.model.values.LabelRef; + +import java.util.List; +import java.util.stream.Collectors; + +/** Asserts that the program does not contain any predecessors in Phi-blocks that are not true predecessors */ +public class Pass2AssertPhiPredecessors extends Pass2SsaAssertion { + + public Pass2AssertPhiPredecessors(Program program) { + super(program); + } + + @Override + public void check() throws AssertionFailed { + for(ControlFlowBlock block : getGraph().getAllBlocks()) { + if(block.hasPhiBlock()) { + StatementPhiBlock phiBlock = block.getPhiBlock(); + List predecessors = + getGraph().getPredecessors(block).stream().map(ControlFlowBlock::getLabel).collect(Collectors.toList()); + for(StatementPhiBlock.PhiVariable phiVariable : phiBlock.getPhiVariables()) { + for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) { + if(!predecessors.contains(phiRValue.getPredecessor())) { + throw new CompileError("INTERNAL ERROR! Block "+block.getLabel()+" phi references non-predecessor block "+phiRValue.getPredecessor()+ + "\n "+phiBlock.toString(getProgram(), false)); + } + } + } + } + } + } + +} diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index e89ac0f61..c9ac8c94e 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -32,15 +32,20 @@ public class TestPrograms { public TestPrograms() { } + @Test + public void testSimpleLoop() throws IOException, URISyntaxException { + compileAndCompare("simple-loop"); + } + @Test public void testLiteralCharMinusNumber() throws IOException, URISyntaxException { compileAndCompare("literal-char-minus-number"); } - //@Test - //public void testPaulNelsenSandboxTernaryError() throws IOException, URISyntaxException { - // compileAndCompare("sandbox-ternary-error", log().verboseParse().verboseCreateSsa().setVerboseSSAOptimize().verboseStatementSequence()); - //} + @Test + public void testPaulNelsenSandboxTernaryError() throws IOException, URISyntaxException { + compileAndCompare("sandbox-ternary-error", log().verboseParse().verboseCreateSsa().setVerboseSSAOptimize().verboseStatementSequence()); + } @Test public void testPaulNelsenSandbox() throws IOException, URISyntaxException { diff --git a/src/test/kc/simple-loop.kc b/src/test/kc/simple-loop.kc new file mode 100644 index 000000000..44546a147 --- /dev/null +++ b/src/test/kc/simple-loop.kc @@ -0,0 +1,8 @@ +void main() { + const unsigned char* SCREEN = 0x0400; + for( unsigned char i = 0; i<128; i+=2) { + SCREEN[i] = 'a'; + (*(unsigned char*)0xD020)=0; + } +} + diff --git a/src/test/ref/literal-char-minus-number.asm b/src/test/ref/literal-char-minus-number.asm new file mode 100644 index 000000000..5330c67fc --- /dev/null +++ b/src/test/ref/literal-char-minus-number.asm @@ -0,0 +1,10 @@ +// Tests subtracting a number from a literal char +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +main: { + .label SCREEN = $400 + lda #'a'-1 + sta SCREEN + rts +} diff --git a/src/test/ref/literal-char-minus-number.cfg b/src/test/ref/literal-char-minus-number.cfg new file mode 100644 index 000000000..35582016d --- /dev/null +++ b/src/test/ref/literal-char-minus-number.cfg @@ -0,0 +1,15 @@ +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] *((const byte*) main::SCREEN#0) ← (byte) 'a'-(byte/signed byte/word/signed word/dword/signed dword) 1 + to:main::@return +main::@return: scope:[main] from main + [5] return + to:@return diff --git a/src/test/ref/literal-char-minus-number.log b/src/test/ref/literal-char-minus-number.log new file mode 100644 index 000000000..57666570a --- /dev/null +++ b/src/test/ref/literal-char-minus-number.log @@ -0,0 +1,210 @@ + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (byte*) main::SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $400 + (byte/signed byte/word/signed word/dword/signed dword~) main::$0 ← (byte) 'a' - (byte/signed byte/word/signed word/dword/signed dword) 1 + *((byte*) main::SCREEN#0) ← (byte/signed byte/word/signed word/dword/signed dword~) main::$0 + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + call main + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @begin +(label) @end +(void()) main() +(byte/signed byte/word/signed word/dword/signed dword~) main::$0 +(label) main::@return +(byte*) main::SCREEN +(byte*) main::SCREEN#0 + +Culled Empty Block (label) @2 +Successful SSA optimization Pass2CullEmptyBlocks +Constant (const byte*) main::SCREEN#0 = ((byte*))$400 +Constant (const byte/signed byte/word/signed word/dword/signed dword) main::$0 = 'a'-1 +Successful SSA optimization Pass2ConstantIdentification +Constant inlined main::$0 = (byte) 'a'-(byte/signed byte/word/signed word/dword/signed dword) 1 +Successful SSA optimization Pass2ConstantInlining +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +CALL GRAPH +Calls in [] to main:2 + +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] *((const byte*) main::SCREEN#0) ← (byte) 'a'-(byte/signed byte/word/signed word/dword/signed dword) 1 + to:main::@return +main::@return: scope:[main] from main + [5] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(byte*) main::SCREEN + +Initial phi equivalence classes +Complete equivalence classes + +INITIAL ASM +//SEG0 File Comments +// Tests subtracting a number from a literal char +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .label SCREEN = $400 + //SEG10 [4] *((const byte*) main::SCREEN#0) ← (byte) 'a'-(byte/signed byte/word/signed word/dword/signed dword) 1 -- _deref_pbuc1=vbuc2 + lda #'a'-1 + sta SCREEN + jmp breturn + //SEG11 main::@return + breturn: + //SEG12 [5] return + rts +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] *((const byte*) main::SCREEN#0) ← (byte) 'a'-(byte/signed byte/word/signed word/dword/signed dword) 1 [ ] ( main:2 [ ] ) always clobbers reg byte a + +REGISTER UPLIFT SCOPES +Uplift Scope [main] +Uplift Scope [] + +Uplifting [main] best 27 combination +Uplifting [] best 27 combination + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +// Tests subtracting a number from a literal char +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .label SCREEN = $400 + //SEG10 [4] *((const byte*) main::SCREEN#0) ← (byte) 'a'-(byte/signed byte/word/signed word/dword/signed dword) 1 -- _deref_pbuc1=vbuc2 + lda #'a'-1 + sta SCREEN + jmp breturn + //SEG11 main::@return + breturn: + //SEG12 [5] return + rts +} + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction bend_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400 + + + +FINAL ASSEMBLER +Score: 12 + +//SEG0 File Comments +// Tests subtracting a number from a literal char +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG5 @1 +//SEG6 [2] call main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +//SEG8 @end +//SEG9 main +main: { + .label SCREEN = $400 + //SEG10 [4] *((const byte*) main::SCREEN#0) ← (byte) 'a'-(byte/signed byte/word/signed word/dword/signed dword) 1 -- _deref_pbuc1=vbuc2 + lda #'a'-1 + sta SCREEN + //SEG11 main::@return + //SEG12 [5] return + rts +} + diff --git a/src/test/ref/literal-char-minus-number.sym b/src/test/ref/literal-char-minus-number.sym new file mode 100644 index 000000000..6a928d5b4 --- /dev/null +++ b/src/test/ref/literal-char-minus-number.sym @@ -0,0 +1,8 @@ +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400 + diff --git a/src/test/ref/sandbox-ternary-error.asm b/src/test/ref/sandbox-ternary-error.asm new file mode 100644 index 000000000..cf9c393e2 --- /dev/null +++ b/src/test/ref/sandbox-ternary-error.asm @@ -0,0 +1,26 @@ +// Demonstrates error with nested ternary operator +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +main: { + .label SCREEN = $400 + ldx #0 + b1: + cpx #0 + beq b4 + cpx #1 + beq b2 + lda #'c' + jmp b3 + b2: + lda #'b' + jmp b3 + b4: + lda #'a' + b3: + sta SCREEN + inx + cpx #3 + bne b1 + rts +} diff --git a/src/test/ref/sandbox-ternary-error.cfg b/src/test/ref/sandbox-ternary-error.cfg new file mode 100644 index 000000000..c2d0d8d36 --- /dev/null +++ b/src/test/ref/sandbox-ternary-error.cfg @@ -0,0 +1,34 @@ +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] phi() + to:main::@1 +main::@1: scope:[main] from main main::@3 + [5] (byte) main::b#2 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@3/(byte) main::b#1 ) + [6] if((byte) main::b#2==(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@3 + to:main::@2 +main::@2: scope:[main] from main::@1 + [7] if((byte) main::b#2==(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@5 + to:main::@4 +main::@4: scope:[main] from main::@2 + [8] phi() + to:main::@5 +main::@5: scope:[main] from main::@2 main::@4 + [9] (byte~) main::$5 ← phi( main::@2/(byte) 'b' main::@4/(byte) 'c' ) + to:main::@3 +main::@3: scope:[main] from main::@1 main::@5 + [10] (byte~) main::$7 ← phi( main::@1/(byte) 'a' main::@5/(byte~) main::$5 ) + [11] *((const byte*) main::SCREEN#0) ← (byte~) main::$7 + [12] (byte) main::b#1 ← ++ (byte) main::b#2 + [13] if((byte) main::b#1!=(byte/signed byte/word/signed word/dword/signed dword) 3) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@3 + [14] return + to:@return diff --git a/src/test/ref/sandbox-ternary-error.log b/src/test/ref/sandbox-ternary-error.log new file mode 100644 index 000000000..fad815c7e --- /dev/null +++ b/src/test/ref/sandbox-ternary-error.log @@ -0,0 +1,988 @@ +PARSING src/test/kc/sandbox-ternary-error.kc +// Demonstrates error with nested ternary operator + +void main(void) { + const byte* SCREEN = 0x0400; + for ( byte b: 0..2 ) { + *SCREEN = (b == 0) ? 'a' : ((b == 1) ? 'b' : 'c'); + } +} + + + + + + + +STATEMENTS +proc (void()) main() + (byte*) main::SCREEN ← (word/signed word/dword/signed dword) $400 + (byte) main:::1::b ← (byte/signed byte/word/signed word/dword/signed dword) 0 +main:::1::@1: + (var) main:::1::$0 ← (byte) main:::1::b == (byte/signed byte/word/signed word/dword/signed dword) 0 + if((var) main:::1::$0) goto main:::1::@2 +main:::1::@3: + (var) main:::1::$1 ← (byte) main:::1::b == (byte/signed byte/word/signed word/dword/signed dword) 1 + if((var) main:::1::$1) goto main:::1::@5 +main:::1::@6: + (var) main:::1::$2 ← (byte) 'c' + goto main:::1::@7 +main:::1::@5: + (var) main:::1::$3 ← (byte) 'b' +main:::1::@7: + (var) main:::1::$4 ← phi( main:::1::@5/(var) main:::1::$3 main:::1::@6/(var) main:::1::$2 ) + (var) main:::1::$5 ← (var) main:::1::$4 + goto main:::1::@4 +main:::1::@2: + (var) main:::1::$6 ← (byte) 'a' +main:::1::@4: + (var) main:::1::$7 ← phi( main:::1::@2/(var) main:::1::$6 main:::1::@7/(var) main:::1::$5 ) + *((byte*) main::SCREEN) ← (var) main:::1::$7 + (byte) main:::1::b ← (byte) main:::1::b + rangenext(0,2) + (var) main:::1::$8 ← (byte) main:::1::b != rangelast(0,2) + if((var) main:::1::$8) goto main:::1::@1 +main::@return: + return +endproc // main() + call main + +SYMBOLS +(label) @1 +(label) @begin +(label) @end +(void()) main() +(bool~) main::$0 +(bool~) main::$1 +(byte~) main::$2 +(byte~) main::$3 +(byte~) main::$4 +(byte~) main::$5 +(byte~) main::$6 +(byte~) main::$7 +(bool~) main::$8 +(label) main::@1 +(label) main::@10 +(label) main::@11 +(label) main::@12 +(label) main::@2 +(label) main::@3 +(label) main::@4 +(label) main::@5 +(label) main::@6 +(label) main::@7 +(label) main::@8 +(label) main::@9 +(label) main::@return +(byte*) main::SCREEN +(byte) main::b + +Promoting word/signed word/dword/signed dword to byte* in main::SCREEN ← ((byte*)) $400 +INITIAL CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from + [0] (byte*) main::SCREEN ← ((byte*)) (word/signed word/dword/signed dword) $400 + [1] (byte) main::b ← (byte/signed byte/word/signed word/dword/signed dword) 0 + to:main::@1 +main::@1: scope:[main] from main main::@4 + [2] (bool~) main::$0 ← (byte) main::b == (byte/signed byte/word/signed word/dword/signed dword) 0 + [3] if((bool~) main::$0) goto main::@2 + to:main::@8 +main::@2: scope:[main] from main::@1 main::@11 + [4] (byte~) main::$6 ← (byte) 'a' + to:main::@4 +main::@8: scope:[main] from main::@1 + to:main::@3 +main::@3: scope:[main] from main::@8 + [5] (bool~) main::$1 ← (byte) main::b == (byte/signed byte/word/signed word/dword/signed dword) 1 + [6] if((bool~) main::$1) goto main::@5 + to:main::@9 +main::@5: scope:[main] from main::@10 main::@3 + [7] (byte~) main::$3 ← (byte) 'b' + to:main::@7 +main::@9: scope:[main] from main::@3 + to:main::@6 +main::@6: scope:[main] from main::@9 + [8] (byte~) main::$2 ← (byte) 'c' + to:main::@7 +main::@7: scope:[main] from main::@5 main::@6 + [9] (byte~) main::$4 ← phi( main::@5/(byte~) main::$3 main::@6/(byte~) main::$2 ) + [10] (byte~) main::$5 ← (byte~) main::$4 + to:main::@4 +main::@10: scope:[main] from + to:main::@5 +main::@4: scope:[main] from main::@2 main::@7 + [11] (byte~) main::$7 ← phi( main::@2/(byte~) main::$6 main::@7/(byte~) main::$5 ) + [12] *((byte*) main::SCREEN) ← (byte~) main::$7 + [13] (byte) main::b ← (byte) main::b + rangenext(0,2) + [14] (bool~) main::$8 ← (byte) main::b != rangelast(0,2) + [15] if((bool~) main::$8) goto main::@1 + to:main::@12 +main::@11: scope:[main] from + to:main::@2 +main::@12: scope:[main] from main::@4 + to:main::@return +main::@return: scope:[main] from main::@12 + [16] return + to:@return +@1: scope:[] from @begin + [17] call main + to:@end +@end: scope:[] from @1 + +Removing empty block main::@8 +Removing empty block main::@9 +Removing empty block main::@10 +Removing empty block main::@11 +Removing empty block main::@12 +PROCEDURE MODIFY VARIABLE ANALYSIS + +Completing Phi functions... +Completing Phi functions... +Completing Phi functions... + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (byte*) main::SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $400 + (byte) main::b#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 + to:main::@1 +main::@1: scope:[main] from main main::@4 + (byte) main::b#2 ← phi( main/(byte) main::b#0 main::@4/(byte) main::b#1 ) + (bool~) main::$0 ← (byte) main::b#2 == (byte/signed byte/word/signed word/dword/signed dword) 0 + if((bool~) main::$0) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 + (byte) main::b#5 ← phi( main::@1/(byte) main::b#2 ) + (byte~) main::$6 ← (byte) 'a' + to:main::@4 +main::@3: scope:[main] from main::@1 + (byte) main::b#3 ← phi( main::@1/(byte) main::b#2 ) + (bool~) main::$1 ← (byte) main::b#3 == (byte/signed byte/word/signed word/dword/signed dword) 1 + if((bool~) main::$1) goto main::@5 + to:main::@6 +main::@5: scope:[main] from main::@3 + (byte) main::b#7 ← phi( main::@3/(byte) main::b#3 ) + (byte~) main::$3 ← (byte) 'b' + to:main::@7 +main::@6: scope:[main] from main::@3 + (byte) main::b#8 ← phi( main::@3/(byte) main::b#3 ) + (byte~) main::$2 ← (byte) 'c' + to:main::@7 +main::@7: scope:[main] from main::@5 main::@6 + (byte) main::b#6 ← phi( main::@5/(byte) main::b#7 main::@6/(byte) main::b#8 ) + (byte~) main::$4 ← phi( main::@5/(byte~) main::$3 main::@6/(byte~) main::$2 ) + (byte~) main::$5 ← (byte~) main::$4 + to:main::@4 +main::@4: scope:[main] from main::@2 main::@7 + (byte) main::b#4 ← phi( main::@2/(byte) main::b#5 main::@7/(byte) main::b#6 ) + (byte~) main::$7 ← phi( main::@2/(byte~) main::$6 main::@7/(byte~) main::$5 ) + *((byte*) main::SCREEN#0) ← (byte~) main::$7 + (byte) main::b#1 ← (byte) main::b#4 + rangenext(0,2) + (bool~) main::$8 ← (byte) main::b#1 != rangelast(0,2) + if((bool~) main::$8) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@4 + return + to:@return +@1: scope:[] from @begin + call main + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @begin +(label) @end +(void()) main() +(bool~) main::$0 +(bool~) main::$1 +(byte~) main::$2 +(byte~) main::$3 +(byte~) main::$4 +(byte~) main::$5 +(byte~) main::$6 +(byte~) main::$7 +(bool~) main::$8 +(label) main::@1 +(label) main::@2 +(label) main::@3 +(label) main::@4 +(label) main::@5 +(label) main::@6 +(label) main::@7 +(label) main::@return +(byte*) main::SCREEN +(byte*) main::SCREEN#0 +(byte) main::b +(byte) main::b#0 +(byte) main::b#1 +(byte) main::b#2 +(byte) main::b#3 +(byte) main::b#4 +(byte) main::b#5 +(byte) main::b#6 +(byte) main::b#7 +(byte) main::b#8 + +Culled Empty Block (label) @2 +Successful SSA optimization Pass2CullEmptyBlocks +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (byte*) main::SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $400 + (byte) main::b#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 + to:main::@1 +main::@1: scope:[main] from main main::@4 + (byte) main::b#2 ← phi( main/(byte) main::b#0 main::@4/(byte) main::b#1 ) + (bool~) main::$0 ← (byte) main::b#2 == (byte/signed byte/word/signed word/dword/signed dword) 0 + if((bool~) main::$0) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 + (byte) main::b#5 ← phi( main::@1/(byte) main::b#2 ) + (byte~) main::$6 ← (byte) 'a' + to:main::@4 +main::@3: scope:[main] from main::@1 + (byte) main::b#3 ← phi( main::@1/(byte) main::b#2 ) + (bool~) main::$1 ← (byte) main::b#3 == (byte/signed byte/word/signed word/dword/signed dword) 1 + if((bool~) main::$1) goto main::@5 + to:main::@6 +main::@5: scope:[main] from main::@3 + (byte) main::b#7 ← phi( main::@3/(byte) main::b#3 ) + (byte~) main::$3 ← (byte) 'b' + to:main::@7 +main::@6: scope:[main] from main::@3 + (byte) main::b#8 ← phi( main::@3/(byte) main::b#3 ) + (byte~) main::$2 ← (byte) 'c' + to:main::@7 +main::@7: scope:[main] from main::@5 main::@6 + (byte) main::b#6 ← phi( main::@5/(byte) main::b#7 main::@6/(byte) main::b#8 ) + (byte~) main::$4 ← phi( main::@5/(byte~) main::$3 main::@6/(byte~) main::$2 ) + (byte~) main::$5 ← (byte~) main::$4 + to:main::@4 +main::@4: scope:[main] from main::@2 main::@7 + (byte) main::b#4 ← phi( main::@2/(byte) main::b#5 main::@7/(byte) main::b#6 ) + (byte~) main::$7 ← phi( main::@2/(byte~) main::$6 main::@7/(byte~) main::$5 ) + *((byte*) main::SCREEN#0) ← (byte~) main::$7 + (byte) main::b#1 ← (byte) main::b#4 + rangenext(0,2) + (bool~) main::$8 ← (byte) main::b#1 != rangelast(0,2) + if((bool~) main::$8) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@4 + return + to:@return +@1: scope:[] from @begin + call main + to:@end +@end: scope:[] from @1 + +Alias (byte) main::b#2 = (byte) main::b#5 (byte) main::b#3 (byte) main::b#7 (byte) main::b#8 +Alias (byte~) main::$5 = (byte~) main::$4 +Successful SSA optimization Pass2AliasElimination +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + [0] (byte*) main::SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $400 + [1] (byte) main::b#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 + to:main::@1 +main::@1: scope:[main] from main main::@4 + [2] (byte) main::b#2 ← phi( main/(byte) main::b#0 main::@4/(byte) main::b#1 ) + [3] (bool~) main::$0 ← (byte) main::b#2 == (byte/signed byte/word/signed word/dword/signed dword) 0 + [4] if((bool~) main::$0) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 + [6] (byte~) main::$6 ← (byte) 'a' + to:main::@4 +main::@3: scope:[main] from main::@1 + [8] (bool~) main::$1 ← (byte) main::b#2 == (byte/signed byte/word/signed word/dword/signed dword) 1 + [9] if((bool~) main::$1) goto main::@5 + to:main::@6 +main::@5: scope:[main] from main::@3 + [11] (byte~) main::$3 ← (byte) 'b' + to:main::@7 +main::@6: scope:[main] from main::@3 + [13] (byte~) main::$2 ← (byte) 'c' + to:main::@7 +main::@7: scope:[main] from main::@5 main::@6 + [14] (byte) main::b#6 ← phi( main::@5/(byte) main::b#2 main::@6/(byte) main::b#2 ) + [14] (byte~) main::$5 ← phi( main::@5/(byte~) main::$3 main::@6/(byte~) main::$2 ) + to:main::@4 +main::@4: scope:[main] from main::@2 main::@7 + [16] (byte) main::b#4 ← phi( main::@2/(byte) main::b#2 main::@7/(byte) main::b#6 ) + [16] (byte~) main::$7 ← phi( main::@2/(byte~) main::$6 main::@7/(byte~) main::$5 ) + [17] *((byte*) main::SCREEN#0) ← (byte~) main::$7 + [18] (byte) main::b#1 ← (byte) main::b#4 + rangenext(0,2) + [19] (bool~) main::$8 ← (byte) main::b#1 != rangelast(0,2) + [20] if((bool~) main::$8) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@4 + [21] return + to:@return +@1: scope:[] from @begin + [22] call main + to:@end +@end: scope:[] from @1 + +Alias (byte) main::b#2 = (byte) main::b#6 +Successful SSA optimization Pass2AliasElimination +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + [0] (byte*) main::SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $400 + [1] (byte) main::b#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 + to:main::@1 +main::@1: scope:[main] from main main::@4 + [2] (byte) main::b#2 ← phi( main/(byte) main::b#0 main::@4/(byte) main::b#1 ) + [3] (bool~) main::$0 ← (byte) main::b#2 == (byte/signed byte/word/signed word/dword/signed dword) 0 + [4] if((bool~) main::$0) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 + [6] (byte~) main::$6 ← (byte) 'a' + to:main::@4 +main::@3: scope:[main] from main::@1 + [8] (bool~) main::$1 ← (byte) main::b#2 == (byte/signed byte/word/signed word/dword/signed dword) 1 + [9] if((bool~) main::$1) goto main::@5 + to:main::@6 +main::@5: scope:[main] from main::@3 + [11] (byte~) main::$3 ← (byte) 'b' + to:main::@7 +main::@6: scope:[main] from main::@3 + [13] (byte~) main::$2 ← (byte) 'c' + to:main::@7 +main::@7: scope:[main] from main::@5 main::@6 + [14] (byte~) main::$5 ← phi( main::@5/(byte~) main::$3 main::@6/(byte~) main::$2 ) + to:main::@4 +main::@4: scope:[main] from main::@2 main::@7 + [16] (byte) main::b#4 ← phi( main::@2/(byte) main::b#2 main::@7/(byte) main::b#2 ) + [16] (byte~) main::$7 ← phi( main::@2/(byte~) main::$6 main::@7/(byte~) main::$5 ) + [17] *((byte*) main::SCREEN#0) ← (byte~) main::$7 + [18] (byte) main::b#1 ← (byte) main::b#4 + rangenext(0,2) + [19] (bool~) main::$8 ← (byte) main::b#1 != rangelast(0,2) + [20] if((bool~) main::$8) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@4 + [21] return + to:@return +@1: scope:[] from @begin + [22] call main + to:@end +@end: scope:[] from @1 + +Alias (byte) main::b#2 = (byte) main::b#4 +Successful SSA optimization Pass2AliasElimination +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + [0] (byte*) main::SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $400 + [1] (byte) main::b#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 + to:main::@1 +main::@1: scope:[main] from main main::@4 + [2] (byte) main::b#2 ← phi( main/(byte) main::b#0 main::@4/(byte) main::b#1 ) + [3] (bool~) main::$0 ← (byte) main::b#2 == (byte/signed byte/word/signed word/dword/signed dword) 0 + [4] if((bool~) main::$0) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 + [6] (byte~) main::$6 ← (byte) 'a' + to:main::@4 +main::@3: scope:[main] from main::@1 + [8] (bool~) main::$1 ← (byte) main::b#2 == (byte/signed byte/word/signed word/dword/signed dword) 1 + [9] if((bool~) main::$1) goto main::@5 + to:main::@6 +main::@5: scope:[main] from main::@3 + [11] (byte~) main::$3 ← (byte) 'b' + to:main::@7 +main::@6: scope:[main] from main::@3 + [13] (byte~) main::$2 ← (byte) 'c' + to:main::@7 +main::@7: scope:[main] from main::@5 main::@6 + [14] (byte~) main::$5 ← phi( main::@5/(byte~) main::$3 main::@6/(byte~) main::$2 ) + to:main::@4 +main::@4: scope:[main] from main::@2 main::@7 + [16] (byte~) main::$7 ← phi( main::@2/(byte~) main::$6 main::@7/(byte~) main::$5 ) + [17] *((byte*) main::SCREEN#0) ← (byte~) main::$7 + [18] (byte) main::b#1 ← (byte) main::b#2 + rangenext(0,2) + [19] (bool~) main::$8 ← (byte) main::b#1 != rangelast(0,2) + [20] if((bool~) main::$8) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@4 + [21] return + to:@return +@1: scope:[] from @begin + [22] call main + to:@end +@end: scope:[] from @1 + +Simple Condition (bool~) main::$0 [4] if((byte) main::b#2==(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@2 +Simple Condition (bool~) main::$1 [9] if((byte) main::b#2==(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@5 +Simple Condition (bool~) main::$8 [20] if((byte) main::b#1!=rangelast(0,2)) goto main::@1 +Successful SSA optimization Pass2ConditionalJumpSimplification +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + [0] (byte*) main::SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $400 + [1] (byte) main::b#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 + to:main::@1 +main::@1: scope:[main] from main main::@4 + [2] (byte) main::b#2 ← phi( main/(byte) main::b#0 main::@4/(byte) main::b#1 ) + [4] if((byte) main::b#2==(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 + [6] (byte~) main::$6 ← (byte) 'a' + to:main::@4 +main::@3: scope:[main] from main::@1 + [9] if((byte) main::b#2==(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@5 + to:main::@6 +main::@5: scope:[main] from main::@3 + [11] (byte~) main::$3 ← (byte) 'b' + to:main::@7 +main::@6: scope:[main] from main::@3 + [13] (byte~) main::$2 ← (byte) 'c' + to:main::@7 +main::@7: scope:[main] from main::@5 main::@6 + [14] (byte~) main::$5 ← phi( main::@5/(byte~) main::$3 main::@6/(byte~) main::$2 ) + to:main::@4 +main::@4: scope:[main] from main::@2 main::@7 + [16] (byte~) main::$7 ← phi( main::@2/(byte~) main::$6 main::@7/(byte~) main::$5 ) + [17] *((byte*) main::SCREEN#0) ← (byte~) main::$7 + [18] (byte) main::b#1 ← (byte) main::b#2 + rangenext(0,2) + [20] if((byte) main::b#1!=rangelast(0,2)) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@4 + [21] return + to:@return +@1: scope:[] from @begin + [22] call main + to:@end +@end: scope:[] from @1 + +Constant (const byte*) main::SCREEN#0 = ((byte*))$400 +Constant (const byte) main::b#0 = 0 +Constant (const byte) main::$6 = 'a' +Constant (const byte) main::$3 = 'b' +Constant (const byte) main::$2 = 'c' +Successful SSA optimization Pass2ConstantIdentification +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + to:main::@1 +main::@1: scope:[main] from main main::@4 + [2] (byte) main::b#2 ← phi( main/(const byte) main::b#0 main::@4/(byte) main::b#1 ) + [4] if((byte) main::b#2==(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 + to:main::@4 +main::@3: scope:[main] from main::@1 + [9] if((byte) main::b#2==(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@5 + to:main::@6 +main::@5: scope:[main] from main::@3 + to:main::@7 +main::@6: scope:[main] from main::@3 + to:main::@7 +main::@7: scope:[main] from main::@5 main::@6 + [14] (byte~) main::$5 ← phi( main::@5/(const byte) main::$3 main::@6/(const byte) main::$2 ) + to:main::@4 +main::@4: scope:[main] from main::@2 main::@7 + [16] (byte~) main::$7 ← phi( main::@2/(const byte) main::$6 main::@7/(byte~) main::$5 ) + [17] *((const byte*) main::SCREEN#0) ← (byte~) main::$7 + [18] (byte) main::b#1 ← (byte) main::b#2 + rangenext(0,2) + [20] if((byte) main::b#1!=rangelast(0,2)) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@4 + [21] return + to:@return +@1: scope:[] from @begin + [22] call main + to:@end +@end: scope:[] from @1 + +Resolved ranged next value main::b#1 ← ++ main::b#2 to ++ +Resolved ranged comparison value if(main::b#1!=rangelast(0,2)) goto main::@1 to (byte/signed byte/word/signed word/dword/signed dword) 3 +Culled Empty Block (label) main::@2 +Culled Empty Block (label) main::@5 +Successful SSA optimization Pass2CullEmptyBlocks +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + to:main::@1 +main::@1: scope:[main] from main main::@4 + (byte) main::b#2 ← phi( main/(const byte) main::b#0 main::@4/(byte) main::b#1 ) + if((byte) main::b#2==(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@4 + to:main::@3 +main::@3: scope:[main] from main::@1 + if((byte) main::b#2==(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@7 + to:main::@6 +main::@6: scope:[main] from main::@3 + to:main::@7 +main::@7: scope:[main] from main::@3 main::@6 + (byte~) main::$5 ← phi( main::@3/(const byte) main::$3 main::@6/(const byte) main::$2 ) + to:main::@4 +main::@4: scope:[main] from main::@1 main::@7 + (byte~) main::$7 ← phi( main::@1/(const byte) main::$6 main::@7/(byte~) main::$5 ) + *((const byte*) main::SCREEN#0) ← (byte~) main::$7 + (byte) main::b#1 ← ++ (byte) main::b#2 + if((byte) main::b#1!=(byte/signed byte/word/signed word/dword/signed dword) 3) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@4 + return + to:@return +@1: scope:[] from @begin + call main + to:@end +@end: scope:[] from @1 + +Inlining constant with var siblings (const byte) main::b#0 +Constant inlined main::$6 = (byte) 'a' +Constant inlined main::$3 = (byte) 'b' +Constant inlined main::b#0 = (byte/signed byte/word/signed word/dword/signed dword) 0 +Constant inlined main::$2 = (byte) 'c' +Successful SSA optimization Pass2ConstantInlining +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + to:main::@1 +main::@1: scope:[main] from main main::@4 + [0] (byte) main::b#2 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@4/(byte) main::b#1 ) + [1] if((byte) main::b#2==(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@4 + to:main::@3 +main::@3: scope:[main] from main::@1 + [2] if((byte) main::b#2==(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@7 + to:main::@6 +main::@6: scope:[main] from main::@3 + to:main::@7 +main::@7: scope:[main] from main::@3 main::@6 + [3] (byte~) main::$5 ← phi( main::@3/(byte) 'b' main::@6/(byte) 'c' ) + to:main::@4 +main::@4: scope:[main] from main::@1 main::@7 + [4] (byte~) main::$7 ← phi( main::@1/(byte) 'a' main::@7/(byte~) main::$5 ) + [5] *((const byte*) main::SCREEN#0) ← (byte~) main::$7 + [6] (byte) main::b#1 ← ++ (byte) main::b#2 + [7] if((byte) main::b#1!=(byte/signed byte/word/signed word/dword/signed dword) 3) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@4 + [8] return + to:@return +@1: scope:[] from @begin + [9] call main + to:@end +@end: scope:[] from @1 + +Added new block during phi lifting main::@13(between main::@4 and main::@1) +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +Adding NOP phi() at start of main::@6 +CALL GRAPH +Calls in [] to main:2 + +Created 3 initial phi equivalence classes +Coalesced [10] main::$9 ← main::$5 +Coalesced [16] main::b#9 ← main::b#1 +Coalesced down to 2 phi equivalence classes +Culled Empty Block (label) main::@13 +Renumbering block main::@3 to main::@2 +Renumbering block main::@4 to main::@3 +Renumbering block main::@6 to main::@4 +Renumbering block main::@7 to main::@5 +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +Adding NOP phi() at start of main::@4 + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] phi() + to:main::@1 +main::@1: scope:[main] from main main::@3 + [5] (byte) main::b#2 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@3/(byte) main::b#1 ) + [6] if((byte) main::b#2==(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@3 + to:main::@2 +main::@2: scope:[main] from main::@1 + [7] if((byte) main::b#2==(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@5 + to:main::@4 +main::@4: scope:[main] from main::@2 + [8] phi() + to:main::@5 +main::@5: scope:[main] from main::@2 main::@4 + [9] (byte~) main::$5 ← phi( main::@2/(byte) 'b' main::@4/(byte) 'c' ) + to:main::@3 +main::@3: scope:[main] from main::@1 main::@5 + [10] (byte~) main::$7 ← phi( main::@1/(byte) 'a' main::@5/(byte~) main::$5 ) + [11] *((const byte*) main::SCREEN#0) ← (byte~) main::$7 + [12] (byte) main::b#1 ← ++ (byte) main::b#2 + [13] if((byte) main::b#1!=(byte/signed byte/word/signed word/dword/signed dword) 3) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@3 + [14] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(byte~) main::$5 11.0 +(byte~) main::$7 22.0 +(byte*) main::SCREEN +(byte) main::b +(byte) main::b#1 16.5 +(byte) main::b#2 6.285714285714286 + +Initial phi equivalence classes +[ main::b#2 main::b#1 ] +[ main::$7 main::$5 ] +Complete equivalence classes +[ main::b#2 main::b#1 ] +[ main::$7 main::$5 ] +Allocated zp ZP_BYTE:2 [ main::b#2 main::b#1 ] +Allocated zp ZP_BYTE:3 [ main::$7 main::$5 ] + +INITIAL ASM +//SEG0 File Comments +// Demonstrates error with nested ternary operator +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main +//SEG7 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG9 @end +bend: +//SEG10 main +main: { + .label SCREEN = $400 + .label _5 = 3 + .label _7 = 3 + .label b = 2 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG12 [5] phi (byte) main::b#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 + lda #0 + sta b + jmp b1 + //SEG13 [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1] + b1_from_b3: + //SEG14 [5] phi (byte) main::b#2 = (byte) main::b#1 [phi:main::@3->main::@1#0] -- register_copy + jmp b1 + //SEG15 main::@1 + b1: + //SEG16 [6] if((byte) main::b#2==(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@3 -- vbuz1_eq_0_then_la1 + lda b + cmp #0 + beq b3_from_b1 + jmp b2 + //SEG17 main::@2 + b2: + //SEG18 [7] if((byte) main::b#2==(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@5 -- vbuz1_eq_vbuc1_then_la1 + lda #1 + cmp b + beq b5_from_b2 + //SEG19 [8] phi from main::@2 to main::@4 [phi:main::@2->main::@4] + b4_from_b2: + jmp b4 + //SEG20 main::@4 + b4: + //SEG21 [9] phi from main::@4 to main::@5 [phi:main::@4->main::@5] + b5_from_b4: + //SEG22 [9] phi (byte~) main::$5 = (byte) 'c' [phi:main::@4->main::@5#0] -- vbuz1=vbuc1 + lda #'c' + sta _5 + jmp b5 + //SEG23 [9] phi from main::@2 to main::@5 [phi:main::@2->main::@5] + b5_from_b2: + //SEG24 [9] phi (byte~) main::$5 = (byte) 'b' [phi:main::@2->main::@5#0] -- vbuz1=vbuc1 + lda #'b' + sta _5 + jmp b5 + //SEG25 main::@5 + b5: + //SEG26 [10] phi from main::@5 to main::@3 [phi:main::@5->main::@3] + b3_from_b5: + //SEG27 [10] phi (byte~) main::$7 = (byte~) main::$5 [phi:main::@5->main::@3#0] -- register_copy + jmp b3 + //SEG28 [10] phi from main::@1 to main::@3 [phi:main::@1->main::@3] + b3_from_b1: + //SEG29 [10] phi (byte~) main::$7 = (byte) 'a' [phi:main::@1->main::@3#0] -- vbuz1=vbuc1 + lda #'a' + sta _7 + jmp b3 + //SEG30 main::@3 + b3: + //SEG31 [11] *((const byte*) main::SCREEN#0) ← (byte~) main::$7 -- _deref_pbuc1=vbuz1 + lda _7 + sta SCREEN + //SEG32 [12] (byte) main::b#1 ← ++ (byte) main::b#2 -- vbuz1=_inc_vbuz1 + inc b + //SEG33 [13] if((byte) main::b#1!=(byte/signed byte/word/signed word/dword/signed dword) 3) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 + lda #3 + cmp b + bne b1_from_b3 + jmp breturn + //SEG34 main::@return + breturn: + //SEG35 [14] return + rts +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Potential registers zp ZP_BYTE:2 [ main::b#2 main::b#1 ] : zp ZP_BYTE:2 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:3 [ main::$7 main::$5 ] : zp ZP_BYTE:3 , reg byte a , reg byte x , reg byte y , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 33: zp ZP_BYTE:3 [ main::$7 main::$5 ] 22.79: zp ZP_BYTE:2 [ main::b#2 main::b#1 ] +Uplift Scope [] + +Uplifting [main] best 563 combination reg byte a [ main::$7 main::$5 ] reg byte x [ main::b#2 main::b#1 ] +Uplifting [] best 563 combination + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +// Demonstrates error with nested ternary operator +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main +//SEG7 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG9 @end +bend: +//SEG10 main +main: { + .label SCREEN = $400 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG12 [5] phi (byte) main::b#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + ldx #0 + jmp b1 + //SEG13 [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1] + b1_from_b3: + //SEG14 [5] phi (byte) main::b#2 = (byte) main::b#1 [phi:main::@3->main::@1#0] -- register_copy + jmp b1 + //SEG15 main::@1 + b1: + //SEG16 [6] if((byte) main::b#2==(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@3 -- vbuxx_eq_0_then_la1 + cpx #0 + beq b3_from_b1 + jmp b2 + //SEG17 main::@2 + b2: + //SEG18 [7] if((byte) main::b#2==(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@5 -- vbuxx_eq_vbuc1_then_la1 + cpx #1 + beq b5_from_b2 + //SEG19 [8] phi from main::@2 to main::@4 [phi:main::@2->main::@4] + b4_from_b2: + jmp b4 + //SEG20 main::@4 + b4: + //SEG21 [9] phi from main::@4 to main::@5 [phi:main::@4->main::@5] + b5_from_b4: + //SEG22 [9] phi (byte~) main::$5 = (byte) 'c' [phi:main::@4->main::@5#0] -- vbuaa=vbuc1 + lda #'c' + jmp b5 + //SEG23 [9] phi from main::@2 to main::@5 [phi:main::@2->main::@5] + b5_from_b2: + //SEG24 [9] phi (byte~) main::$5 = (byte) 'b' [phi:main::@2->main::@5#0] -- vbuaa=vbuc1 + lda #'b' + jmp b5 + //SEG25 main::@5 + b5: + //SEG26 [10] phi from main::@5 to main::@3 [phi:main::@5->main::@3] + b3_from_b5: + //SEG27 [10] phi (byte~) main::$7 = (byte~) main::$5 [phi:main::@5->main::@3#0] -- register_copy + jmp b3 + //SEG28 [10] phi from main::@1 to main::@3 [phi:main::@1->main::@3] + b3_from_b1: + //SEG29 [10] phi (byte~) main::$7 = (byte) 'a' [phi:main::@1->main::@3#0] -- vbuaa=vbuc1 + lda #'a' + jmp b3 + //SEG30 main::@3 + b3: + //SEG31 [11] *((const byte*) main::SCREEN#0) ← (byte~) main::$7 -- _deref_pbuc1=vbuaa + sta SCREEN + //SEG32 [12] (byte) main::b#1 ← ++ (byte) main::b#2 -- vbuxx=_inc_vbuxx + inx + //SEG33 [13] if((byte) main::b#1!=(byte/signed byte/word/signed word/dword/signed dword) 3) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 + cpx #3 + bne b1_from_b3 + jmp breturn + //SEG34 main::@return + breturn: + //SEG35 [14] return + rts +} + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp b1 +Removing instruction jmp b2 +Removing instruction jmp b4 +Removing instruction jmp b5 +Removing instruction jmp b3 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Replacing label b1_from_b3 with b1 +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction main_from_b1: +Removing instruction bend_from_b1: +Removing instruction b1_from_b3: +Removing instruction b4_from_b2: +Removing instruction b5_from_b4: +Removing instruction b3_from_b5: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction b1_from_main: +Removing instruction b2: +Removing instruction b4: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Skipping double jump to b3 in jmp b5 +Succesful ASM optimization Pass5DoubleJumpElimination +Relabelling long label b5_from_b2 to b2 +Relabelling long label b3_from_b1 to b4 +Succesful ASM optimization Pass5RelabelLongLabels +Removing instruction jmp b1 +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction bbegin: +Removing instruction b5: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(void()) main() +(byte~) main::$5 reg byte a 11.0 +(byte~) main::$7 reg byte a 22.0 +(label) main::@1 +(label) main::@2 +(label) main::@3 +(label) main::@4 +(label) main::@5 +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400 +(byte) main::b +(byte) main::b#1 reg byte x 16.5 +(byte) main::b#2 reg byte x 6.285714285714286 + +reg byte x [ main::b#2 main::b#1 ] +reg byte a [ main::$7 main::$5 ] + + +FINAL ASSEMBLER +Score: 341 + +//SEG0 File Comments +// Demonstrates error with nested ternary operator +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG5 @1 +//SEG6 [2] call main +//SEG7 [4] phi from @1 to main [phi:@1->main] +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +//SEG9 @end +//SEG10 main +main: { + .label SCREEN = $400 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + //SEG12 [5] phi (byte) main::b#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + ldx #0 + //SEG13 [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1] + //SEG14 [5] phi (byte) main::b#2 = (byte) main::b#1 [phi:main::@3->main::@1#0] -- register_copy + //SEG15 main::@1 + b1: + //SEG16 [6] if((byte) main::b#2==(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@3 -- vbuxx_eq_0_then_la1 + cpx #0 + beq b4 + //SEG17 main::@2 + //SEG18 [7] if((byte) main::b#2==(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@5 -- vbuxx_eq_vbuc1_then_la1 + cpx #1 + beq b2 + //SEG19 [8] phi from main::@2 to main::@4 [phi:main::@2->main::@4] + //SEG20 main::@4 + //SEG21 [9] phi from main::@4 to main::@5 [phi:main::@4->main::@5] + //SEG22 [9] phi (byte~) main::$5 = (byte) 'c' [phi:main::@4->main::@5#0] -- vbuaa=vbuc1 + lda #'c' + jmp b3 + //SEG23 [9] phi from main::@2 to main::@5 [phi:main::@2->main::@5] + b2: + //SEG24 [9] phi (byte~) main::$5 = (byte) 'b' [phi:main::@2->main::@5#0] -- vbuaa=vbuc1 + lda #'b' + //SEG25 main::@5 + //SEG26 [10] phi from main::@5 to main::@3 [phi:main::@5->main::@3] + //SEG27 [10] phi (byte~) main::$7 = (byte~) main::$5 [phi:main::@5->main::@3#0] -- register_copy + jmp b3 + //SEG28 [10] phi from main::@1 to main::@3 [phi:main::@1->main::@3] + b4: + //SEG29 [10] phi (byte~) main::$7 = (byte) 'a' [phi:main::@1->main::@3#0] -- vbuaa=vbuc1 + lda #'a' + //SEG30 main::@3 + b3: + //SEG31 [11] *((const byte*) main::SCREEN#0) ← (byte~) main::$7 -- _deref_pbuc1=vbuaa + sta SCREEN + //SEG32 [12] (byte) main::b#1 ← ++ (byte) main::b#2 -- vbuxx=_inc_vbuxx + inx + //SEG33 [13] if((byte) main::b#1!=(byte/signed byte/word/signed word/dword/signed dword) 3) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 + cpx #3 + bne b1 + //SEG34 main::@return + //SEG35 [14] return + rts +} + diff --git a/src/test/ref/sandbox-ternary-error.sym b/src/test/ref/sandbox-ternary-error.sym new file mode 100644 index 000000000..9f605b4b9 --- /dev/null +++ b/src/test/ref/sandbox-ternary-error.sym @@ -0,0 +1,20 @@ +(label) @1 +(label) @begin +(label) @end +(void()) main() +(byte~) main::$5 reg byte a 11.0 +(byte~) main::$7 reg byte a 22.0 +(label) main::@1 +(label) main::@2 +(label) main::@3 +(label) main::@4 +(label) main::@5 +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400 +(byte) main::b +(byte) main::b#1 reg byte x 16.5 +(byte) main::b#2 reg byte x 6.285714285714286 + +reg byte x [ main::b#2 main::b#1 ] +reg byte a [ main::$7 main::$5 ] diff --git a/src/test/ref/simple-loop.asm b/src/test/ref/simple-loop.asm new file mode 100644 index 000000000..2319dc851 --- /dev/null +++ b/src/test/ref/simple-loop.asm @@ -0,0 +1,17 @@ +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +main: { + .label SCREEN = $400 + ldx #0 + b1: + lda #'a' + sta SCREEN,x + lda #0 + sta $d020 + inx + inx + cpx #$80 + bcc b1 + rts +} diff --git a/src/test/ref/simple-loop.cfg b/src/test/ref/simple-loop.cfg new file mode 100644 index 000000000..c681c2659 --- /dev/null +++ b/src/test/ref/simple-loop.cfg @@ -0,0 +1,22 @@ +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] phi() + to:main::@1 +main::@1: scope:[main] from main main::@1 + [5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@1/(byte) main::i#1 ) + [6] *((const byte*) main::SCREEN#0 + (byte) main::i#2) ← (byte) 'a' + [7] *(((byte*))(word/dword/signed dword) $d020) ← (byte/signed byte/word/signed word/dword/signed dword) 0 + [8] (byte) main::i#1 ← (byte) main::i#2 + (byte/signed byte/word/signed word/dword/signed dword) 2 + [9] if((byte) main::i#1<(byte/word/signed word/dword/signed dword) $80) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@1 + [10] return + to:@return diff --git a/src/test/ref/simple-loop.log b/src/test/ref/simple-loop.log new file mode 100644 index 000000000..a8f80bd4e --- /dev/null +++ b/src/test/ref/simple-loop.log @@ -0,0 +1,328 @@ + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (byte*) main::SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $400 + (byte) main::i#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 + to:main::@1 +main::@1: scope:[main] from main main::@1 + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 ) + *((byte*) main::SCREEN#0 + (byte) main::i#2) ← (byte) 'a' + (byte*~) main::$0 ← ((byte*)) (word/dword/signed dword) $d020 + *((byte*~) main::$0) ← (byte/signed byte/word/signed word/dword/signed dword) 0 + (byte) main::i#1 ← (byte) main::i#2 + (byte/signed byte/word/signed word/dword/signed dword) 2 + (bool~) main::$1 ← (byte) main::i#1 < (byte/word/signed word/dword/signed dword) $80 + if((bool~) main::$1) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@1 + return + to:@return +@1: scope:[] from @begin + call main + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @begin +(label) @end +(void()) main() +(byte*~) main::$0 +(bool~) main::$1 +(label) main::@1 +(label) main::@return +(byte*) main::SCREEN +(byte*) main::SCREEN#0 +(byte) main::i +(byte) main::i#0 +(byte) main::i#1 +(byte) main::i#2 + +Culled Empty Block (label) @2 +Successful SSA optimization Pass2CullEmptyBlocks +Simple Condition (bool~) main::$1 [8] if((byte) main::i#1<(byte/word/signed word/dword/signed dword) $80) goto main::@1 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant (const byte*) main::SCREEN#0 = ((byte*))$400 +Constant (const byte) main::i#0 = 0 +Constant (const byte*) main::$0 = ((byte*))$d020 +Successful SSA optimization Pass2ConstantIdentification +Inlining constant with var siblings (const byte) main::i#0 +Constant inlined main::i#0 = (byte/signed byte/word/signed word/dword/signed dword) 0 +Constant inlined main::$0 = ((byte*))(word/dword/signed dword) $d020 +Successful SSA optimization Pass2ConstantInlining +Added new block during phi lifting main::@3(between main::@1 and main::@1) +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +CALL GRAPH +Calls in [] to main:2 + +Created 1 initial phi equivalence classes +Coalesced [11] main::i#3 ← main::i#1 +Coalesced down to 1 phi equivalence classes +Culled Empty Block (label) main::@3 +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] phi() + to:main::@1 +main::@1: scope:[main] from main main::@1 + [5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@1/(byte) main::i#1 ) + [6] *((const byte*) main::SCREEN#0 + (byte) main::i#2) ← (byte) 'a' + [7] *(((byte*))(word/dword/signed dword) $d020) ← (byte/signed byte/word/signed word/dword/signed dword) 0 + [8] (byte) main::i#1 ← (byte) main::i#2 + (byte/signed byte/word/signed word/dword/signed dword) 2 + [9] if((byte) main::i#1<(byte/word/signed word/dword/signed dword) $80) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@1 + [10] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(byte*) main::SCREEN +(byte) main::i +(byte) main::i#1 16.5 +(byte) main::i#2 11.0 + +Initial phi equivalence classes +[ main::i#2 main::i#1 ] +Complete equivalence classes +[ main::i#2 main::i#1 ] +Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ] + +INITIAL ASM +//SEG0 File Comments +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main +//SEG7 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG9 @end +bend: +//SEG10 main +main: { + .label SCREEN = $400 + .label i = 2 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 + lda #0 + sta i + jmp b1 + //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + b1_from_b1: + //SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + jmp b1 + //SEG15 main::@1 + b1: + //SEG16 [6] *((const byte*) main::SCREEN#0 + (byte) main::i#2) ← (byte) 'a' -- pbuc1_derefidx_vbuz1=vbuc2 + lda #'a' + ldy i + sta SCREEN,y + //SEG17 [7] *(((byte*))(word/dword/signed dword) $d020) ← (byte/signed byte/word/signed word/dword/signed dword) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta $d020 + //SEG18 [8] (byte) main::i#1 ← (byte) main::i#2 + (byte/signed byte/word/signed word/dword/signed dword) 2 -- vbuz1=vbuz1_plus_2 + lda i + clc + adc #2 + sta i + //SEG19 [9] if((byte) main::i#1<(byte/word/signed word/dword/signed dword) $80) goto main::@1 -- vbuz1_lt_vbuc1_then_la1 + lda i + cmp #$80 + bcc b1_from_b1 + jmp breturn + //SEG20 main::@return + breturn: + //SEG21 [10] return + rts +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [6] *((const byte*) main::SCREEN#0 + (byte) main::i#2) ← (byte) 'a' [ 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] *(((byte*))(word/dword/signed dword) $d020) ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a +Statement [6] *((const byte*) main::SCREEN#0 + (byte) main::i#2) ← (byte) 'a' [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a +Statement [7] *(((byte*))(word/dword/signed dword) $d020) ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ 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 , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 27.5: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] +Uplift Scope [] + +Uplifting [main] best 343 combination reg byte x [ main::i#2 main::i#1 ] +Uplifting [] best 343 combination + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main +//SEG7 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG9 @end +bend: +//SEG10 main +main: { + .label SCREEN = $400 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + ldx #0 + jmp b1 + //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + b1_from_b1: + //SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + jmp b1 + //SEG15 main::@1 + b1: + //SEG16 [6] *((const byte*) main::SCREEN#0 + (byte) main::i#2) ← (byte) 'a' -- pbuc1_derefidx_vbuxx=vbuc2 + lda #'a' + sta SCREEN,x + //SEG17 [7] *(((byte*))(word/dword/signed dword) $d020) ← (byte/signed byte/word/signed word/dword/signed dword) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta $d020 + //SEG18 [8] (byte) main::i#1 ← (byte) main::i#2 + (byte/signed byte/word/signed word/dword/signed dword) 2 -- vbuxx=vbuxx_plus_2 + inx + inx + //SEG19 [9] if((byte) main::i#1<(byte/word/signed word/dword/signed dword) $80) goto main::@1 -- vbuxx_lt_vbuc1_then_la1 + cpx #$80 + bcc b1_from_b1 + jmp breturn + //SEG20 main::@return + breturn: + //SEG21 [10] return + rts +} + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp b1 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Replacing label b1_from_b1 with b1 +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction main_from_b1: +Removing instruction bend_from_b1: +Removing instruction b1_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction b1_from_main: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction jmp b1 +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@1 +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400 +(byte) main::i +(byte) main::i#1 reg byte x 16.5 +(byte) main::i#2 reg byte x 11.0 + +reg byte x [ main::i#2 main::i#1 ] + + +FINAL ASSEMBLER +Score: 241 + +//SEG0 File Comments +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG5 @1 +//SEG6 [2] call main +//SEG7 [4] phi from @1 to main [phi:@1->main] +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +//SEG9 @end +//SEG10 main +main: { + .label SCREEN = $400 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + //SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + ldx #0 + //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + //SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + //SEG15 main::@1 + b1: + //SEG16 [6] *((const byte*) main::SCREEN#0 + (byte) main::i#2) ← (byte) 'a' -- pbuc1_derefidx_vbuxx=vbuc2 + lda #'a' + sta SCREEN,x + //SEG17 [7] *(((byte*))(word/dword/signed dword) $d020) ← (byte/signed byte/word/signed word/dword/signed dword) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta $d020 + //SEG18 [8] (byte) main::i#1 ← (byte) main::i#2 + (byte/signed byte/word/signed word/dword/signed dword) 2 -- vbuxx=vbuxx_plus_2 + inx + inx + //SEG19 [9] if((byte) main::i#1<(byte/word/signed word/dword/signed dword) $80) goto main::@1 -- vbuxx_lt_vbuc1_then_la1 + cpx #$80 + bcc b1 + //SEG20 main::@return + //SEG21 [10] return + rts +} + diff --git a/src/test/ref/simple-loop.sym b/src/test/ref/simple-loop.sym new file mode 100644 index 000000000..272fe7f04 --- /dev/null +++ b/src/test/ref/simple-loop.sym @@ -0,0 +1,13 @@ +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@1 +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400 +(byte) main::i +(byte) main::i#1 reg byte x 16.5 +(byte) main::i#2 reg byte x 11.0 + +reg byte x [ main::i#2 main::i#1 ]