mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-17 16:31:34 +00:00
Implemented continue statement. Closes #91
This commit is contained in:
parent
4424ffe92c
commit
2d7825a0b9
@ -65,6 +65,10 @@ public class CompileLog {
|
||||
/** Should comments be output as part of the intermediate SSA prints. */
|
||||
private boolean verboseComments = false;
|
||||
|
||||
/**
|
||||
* Should the statement sequence be verbose.
|
||||
*/
|
||||
private boolean verboseStatementSequence = false;
|
||||
|
||||
/**
|
||||
* Should the log be output to System.out while being built
|
||||
@ -87,6 +91,18 @@ public class CompileLog {
|
||||
return log;
|
||||
}
|
||||
|
||||
public boolean isVerboseCreateSsa() {
|
||||
return verboseCreateSsa;
|
||||
}
|
||||
|
||||
public boolean isVerboseStatementSequence() {
|
||||
return verboseStatementSequence;
|
||||
}
|
||||
|
||||
public void setVerboseStatementSequence(boolean verboseStatementSequence) {
|
||||
this.verboseStatementSequence = verboseStatementSequence;
|
||||
}
|
||||
|
||||
public void setVerboseComments(boolean verboseComments) {
|
||||
this.verboseComments = verboseComments;
|
||||
}
|
||||
|
@ -145,8 +145,10 @@ public class Compiler {
|
||||
|
||||
private Program pass1GenerateSSA() {
|
||||
|
||||
//getLog().append("\nSTATEMENTS");
|
||||
//getLog().append(program.getStatementSequence().toString(program));
|
||||
if(getLog().isVerboseStatementSequence()) {
|
||||
getLog().append("\nSTATEMENTS");
|
||||
getLog().append(program.getStatementSequence().toString(program));
|
||||
}
|
||||
|
||||
new Pass1GenerateControlFlowGraph(program).execute();
|
||||
new Pass1ResolveForwardReferences(program).execute();
|
||||
|
@ -637,6 +637,9 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
/** The label after the loop that a break will jump to. Null if no break has been encountered. */
|
||||
Label breakLabel;
|
||||
|
||||
/** The label that a continue will jump to. Null if no continue has been encountered. */
|
||||
Label continueLabel;
|
||||
|
||||
public Loop(Scope loopScope) {
|
||||
this.loopScope = loopScope;
|
||||
}
|
||||
@ -651,6 +654,22 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
}
|
||||
return breakLabel;
|
||||
}
|
||||
|
||||
public Label getContinueLabel() {
|
||||
return continueLabel;
|
||||
}
|
||||
|
||||
public void setContinueLabel(Label continueLabel) {
|
||||
this.continueLabel = continueLabel;
|
||||
}
|
||||
|
||||
public Label getOrCreateContinueLabel() {
|
||||
if(continueLabel==null) {
|
||||
continueLabel = loopScope.addLabelIntermediate();
|
||||
}
|
||||
return continueLabel;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** The loops being generated. */
|
||||
@ -677,6 +696,8 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
sequence.addStatement(endJmpStmt);
|
||||
StatementLabel doJumpTarget = new StatementLabel(doJumpLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS);
|
||||
sequence.addStatement(doJumpTarget);
|
||||
// Reuse the begin jump target for continue.
|
||||
loopStack.peek().setContinueLabel(beginJumpLabel);
|
||||
addLoopBody(ctx.stmt());
|
||||
Statement beginJmpStmt = new StatementJump(beginJumpLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS);
|
||||
sequence.addStatement(beginJmpStmt);
|
||||
@ -700,6 +721,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
StatementLabel beginJumpTarget = new StatementLabel(beginJumpLabel.getRef(), new StatementSource(ctx), comments);
|
||||
sequence.addStatement(beginJumpTarget);
|
||||
addLoopBody(ctx.stmt());
|
||||
addLoopContinueLabel(loopStack.peek(), ctx);
|
||||
PrePostModifierHandler.addPreModifiers(this, ctx.expr());
|
||||
RValue rValue = (RValue) this.visit(ctx.expr());
|
||||
PrePostModifierHandler.addPostModifiers(this, ctx.expr());
|
||||
@ -742,6 +764,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
sequence.addStatement(repeatTarget);
|
||||
// Add body
|
||||
addLoopBody(stmtForCtx.stmt());
|
||||
addLoopContinueLabel(loopStack.peek(), ctx);
|
||||
// Add increment
|
||||
if(ctx.expr(1) != null) {
|
||||
PrePostModifierHandler.addPreModifiers(this, ctx.expr(1));
|
||||
@ -784,6 +807,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
sequence.addStatement(repeatTarget);
|
||||
// Add body
|
||||
addLoopBody(stmtForCtx.stmt());
|
||||
addLoopContinueLabel(loopStack.peek(), ctx);
|
||||
// Add increment
|
||||
Statement stmtNxt = new StatementAssignment(lValue.getRef(), lValue.getRef(), Operators.PLUS, new RangeNext(rangeFirstValue, rangeLastValue), new StatementSource(ctx), Comment.NO_COMMENTS);
|
||||
sequence.addStatement(stmtNxt);
|
||||
@ -809,6 +833,13 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
}
|
||||
}
|
||||
|
||||
private void addLoopContinueLabel(Loop loop, ParserRuleContext ctx) {
|
||||
if(loop.getContinueLabel()!=null) {
|
||||
StatementLabel continueTarget = new StatementLabel(loop.getContinueLabel().getRef(), new StatementSource(ctx), Comment.NO_COMMENTS);
|
||||
sequence.addStatement(continueTarget);
|
||||
}
|
||||
}
|
||||
|
||||
private void addLoopBody(KickCParser.StmtContext stmt) {
|
||||
if(stmt != null) {
|
||||
if(stmt instanceof KickCParser.StmtBlockContext) {
|
||||
@ -864,7 +895,14 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
|
||||
@Override
|
||||
public Object visitStmtContinue(KickCParser.StmtContinueContext ctx) {
|
||||
return super.visitStmtContinue(ctx);
|
||||
if(loopStack.isEmpty()) {
|
||||
throw new CompileError("Continue not inside a loop! ", new StatementSource(ctx));
|
||||
}
|
||||
Loop currentLoop = loopStack.peek();
|
||||
Label continueLabel = currentLoop.getOrCreateContinueLabel();
|
||||
Statement continueJmpStmt = new StatementJump(continueLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS);
|
||||
sequence.addStatement(continueJmpStmt);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -32,6 +32,26 @@ public class TestPrograms {
|
||||
public TestPrograms() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoopWhileContinue() throws IOException, URISyntaxException {
|
||||
compileAndCompare("loop-while-continue");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoopContinue() throws IOException, URISyntaxException {
|
||||
compileAndCompare("loop-continue");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoopBreakNested() throws IOException, URISyntaxException {
|
||||
compileAndCompare("loop-break-nested");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoopBreak() throws IOException, URISyntaxException {
|
||||
compileAndCompare("loop-break");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalScopeLoops() throws IOException, URISyntaxException {
|
||||
compileAndCompare("localscope-loops", getLogSysout());
|
||||
@ -67,17 +87,6 @@ public class TestPrograms {
|
||||
compileAndCompare("examples/music/music");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoopBreakNested() throws IOException, URISyntaxException {
|
||||
compileAndCompare("loop-break-nested");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoopBreak() throws IOException, URISyntaxException {
|
||||
compileAndCompare("loop-break");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testConstEarlyIdentification() throws IOException, URISyntaxException {
|
||||
compileAndCompare("const-early-identification");
|
||||
|
11
src/test/kc/loop-continue.kc
Normal file
11
src/test/kc/loop-continue.kc
Normal file
@ -0,0 +1,11 @@
|
||||
// Tests break statement in a simple loop
|
||||
|
||||
const byte* SCREEN = $400;
|
||||
|
||||
void main() {
|
||||
for( byte i: 0..40*6) {
|
||||
if(SCREEN[i]==' ')
|
||||
continue;
|
||||
SCREEN[i]++;
|
||||
}
|
||||
}
|
12
src/test/kc/loop-while-continue.kc
Normal file
12
src/test/kc/loop-while-continue.kc
Normal file
@ -0,0 +1,12 @@
|
||||
// Tests break statement in a simple loop
|
||||
|
||||
const byte* SCREEN = $400;
|
||||
|
||||
void main() {
|
||||
byte i=0;
|
||||
while(++i<40*6) {
|
||||
if(SCREEN[i]==' ')
|
||||
continue;
|
||||
SCREEN[i]++;
|
||||
}
|
||||
}
|
20
src/test/ref/loop-continue.asm
Normal file
20
src/test/ref/loop-continue.asm
Normal file
@ -0,0 +1,20 @@
|
||||
// Tests break statement in a simple loop
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.label SCREEN = $400
|
||||
main: {
|
||||
ldx #0
|
||||
b1:
|
||||
lda SCREEN,x
|
||||
cmp #' '
|
||||
bne b2
|
||||
b3:
|
||||
inx
|
||||
cpx #$28*6+1
|
||||
bne b1
|
||||
rts
|
||||
b2:
|
||||
inc SCREEN,x
|
||||
jmp b3
|
||||
}
|
26
src/test/ref/loop-continue.cfg
Normal file
26
src/test/ref/loop-continue.cfg
Normal file
@ -0,0 +1,26 @@
|
||||
@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::i#2 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@3/(byte) main::i#1 )
|
||||
[6] if(*((const byte*) SCREEN#0 + (byte) main::i#2)!=(byte) ' ') goto main::@2
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::@2
|
||||
[7] (byte) main::i#1 ← ++ (byte) main::i#2
|
||||
[8] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $28*(byte/signed byte/word/signed word/dword/signed dword) 6+(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
[9] return
|
||||
to:@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
[10] *((const byte*) SCREEN#0 + (byte) main::i#2) ← ++ *((const byte*) SCREEN#0 + (byte) main::i#2)
|
||||
to:main::@3
|
372
src/test/ref/loop-continue.log
Normal file
372
src/test/ref/loop-continue.log
Normal file
@ -0,0 +1,372 @@
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
@begin: scope:[] from
|
||||
(byte*) SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $400
|
||||
to:@1
|
||||
main: scope:[main] from @1
|
||||
(byte/word/signed word/dword/signed dword~) main::$0 ← (byte/signed byte/word/signed word/dword/signed dword) $28 * (byte/signed byte/word/signed word/dword/signed dword) 6
|
||||
(byte) main::i#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@3
|
||||
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@3/(byte) main::i#1 )
|
||||
(bool~) main::$1 ← *((byte*) SCREEN#0 + (byte) main::i#2) == (byte) ' '
|
||||
(bool~) main::$2 ← ! (bool~) main::$1
|
||||
if((bool~) main::$2) goto main::@2
|
||||
to:main::@3
|
||||
main::@2: scope:[main] from main::@1
|
||||
(byte) main::i#3 ← phi( main::@1/(byte) main::i#2 )
|
||||
*((byte*) SCREEN#0 + (byte) main::i#3) ← ++ *((byte*) SCREEN#0 + (byte) main::i#3)
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::@2
|
||||
(byte) main::i#4 ← phi( main::@1/(byte) main::i#2 main::@2/(byte) main::i#3 )
|
||||
(byte) main::i#1 ← (byte) main::i#4 + rangenext(0,main::$0)
|
||||
(bool~) main::$3 ← (byte) main::i#1 != rangelast(0,main::$0)
|
||||
if((bool~) main::$3) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
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
|
||||
(byte*) SCREEN
|
||||
(byte*) SCREEN#0
|
||||
(void()) main()
|
||||
(byte/word/signed word/dword/signed dword~) main::$0
|
||||
(bool~) main::$1
|
||||
(bool~) main::$2
|
||||
(bool~) main::$3
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@3
|
||||
(label) main::@return
|
||||
(byte) main::i
|
||||
(byte) main::i#0
|
||||
(byte) main::i#1
|
||||
(byte) main::i#2
|
||||
(byte) main::i#3
|
||||
(byte) main::i#4
|
||||
|
||||
Culled Empty Block (label) @2
|
||||
Successful SSA optimization Pass2CullEmptyBlocks
|
||||
Inversing boolean not [5] (bool~) main::$2 ← *((byte*) SCREEN#0 + (byte) main::i#2) != (byte) ' ' from [4] (bool~) main::$1 ← *((byte*) SCREEN#0 + (byte) main::i#2) == (byte) ' '
|
||||
Successful SSA optimization Pass2UnaryNotSimplification
|
||||
Alias (byte) main::i#2 = (byte) main::i#3
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Alias (byte) main::i#2 = (byte) main::i#4
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Simple Condition (bool~) main::$2 [6] if(*((byte*) SCREEN#0 + (byte) main::i#2)!=(byte) ' ') goto main::@2
|
||||
Simple Condition (bool~) main::$3 [12] if((byte) main::i#1!=rangelast(0,main::$0)) goto main::@1
|
||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||
Constant (const byte*) SCREEN#0 = ((byte*))$400
|
||||
Constant (const byte/word/signed word/dword/signed dword) main::$0 = $28*6
|
||||
Constant (const byte) main::i#0 = 0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Resolved ranged next value main::i#1 ← ++ main::i#2 to ++
|
||||
Resolved ranged comparison value if(main::i#1!=rangelast(0,main::$0)) goto main::@1 to (const byte/word/signed word/dword/signed dword) main::$0+(byte/signed byte/word/signed word/dword/signed dword) 1
|
||||
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/signed byte/word/signed word/dword/signed dword) $28*(byte/signed byte/word/signed word/dword/signed dword) 6
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Added new block during phi lifting main::@7(between main::@3 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 [10] main::i#5 ← main::i#1
|
||||
Coalesced down to 1 phi equivalence classes
|
||||
Culled Empty Block (label) main::@7
|
||||
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::@3
|
||||
[5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@3/(byte) main::i#1 )
|
||||
[6] if(*((const byte*) SCREEN#0 + (byte) main::i#2)!=(byte) ' ') goto main::@2
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::@2
|
||||
[7] (byte) main::i#1 ← ++ (byte) main::i#2
|
||||
[8] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $28*(byte/signed byte/word/signed word/dword/signed dword) 6+(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
[9] return
|
||||
to:@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
[10] *((const byte*) SCREEN#0 + (byte) main::i#2) ← ++ *((const byte*) SCREEN#0 + (byte) main::i#2)
|
||||
to:main::@3
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(byte*) SCREEN
|
||||
(void()) main()
|
||||
(byte) main::i
|
||||
(byte) main::i#1 16.5
|
||||
(byte) main::i#2 18.333333333333332
|
||||
|
||||
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
|
||||
// Tests break statement in a simple loop
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
//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 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::@3 to main::@1 [phi:main::@3->main::@1]
|
||||
b1_from_b3:
|
||||
//SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@3->main::@1#0] -- register_copy
|
||||
jmp b1
|
||||
//SEG15 main::@1
|
||||
b1:
|
||||
//SEG16 [6] if(*((const byte*) SCREEN#0 + (byte) main::i#2)!=(byte) ' ') goto main::@2 -- pbuc1_derefidx_vbuz1_neq_vbuc2_then_la1
|
||||
lda #' '
|
||||
ldy i
|
||||
cmp SCREEN,y
|
||||
bne b2
|
||||
jmp b3
|
||||
//SEG17 main::@3
|
||||
b3:
|
||||
//SEG18 [7] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
|
||||
inc i
|
||||
//SEG19 [8] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $28*(byte/signed byte/word/signed word/dword/signed dword) 6+(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
|
||||
lda #$28*6+1
|
||||
cmp i
|
||||
bne b1_from_b3
|
||||
jmp breturn
|
||||
//SEG20 main::@return
|
||||
breturn:
|
||||
//SEG21 [9] return
|
||||
rts
|
||||
//SEG22 main::@2
|
||||
b2:
|
||||
//SEG23 [10] *((const byte*) SCREEN#0 + (byte) main::i#2) ← ++ *((const byte*) SCREEN#0 + (byte) main::i#2) -- pbuc1_derefidx_vbuz1=_inc_pbuc1_derefidx_vbuz1
|
||||
ldx i
|
||||
inc SCREEN,x
|
||||
jmp b3
|
||||
}
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [6] if(*((const byte*) SCREEN#0 + (byte) main::i#2)!=(byte) ' ') 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 [6] if(*((const byte*) SCREEN#0 + (byte) main::i#2)!=(byte) ' ') goto main::@2 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
|
||||
Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main] 34.83: zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 413 combination reg byte x [ main::i#2 main::i#1 ]
|
||||
Uplifting [] best 413 combination
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
//SEG0 File Comments
|
||||
// Tests break statement in a simple loop
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
//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: {
|
||||
//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::@3 to main::@1 [phi:main::@3->main::@1]
|
||||
b1_from_b3:
|
||||
//SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@3->main::@1#0] -- register_copy
|
||||
jmp b1
|
||||
//SEG15 main::@1
|
||||
b1:
|
||||
//SEG16 [6] if(*((const byte*) SCREEN#0 + (byte) main::i#2)!=(byte) ' ') goto main::@2 -- pbuc1_derefidx_vbuxx_neq_vbuc2_then_la1
|
||||
lda SCREEN,x
|
||||
cmp #' '
|
||||
bne b2
|
||||
jmp b3
|
||||
//SEG17 main::@3
|
||||
b3:
|
||||
//SEG18 [7] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
//SEG19 [8] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $28*(byte/signed byte/word/signed word/dword/signed dword) 6+(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
|
||||
cpx #$28*6+1
|
||||
bne b1_from_b3
|
||||
jmp breturn
|
||||
//SEG20 main::@return
|
||||
breturn:
|
||||
//SEG21 [9] return
|
||||
rts
|
||||
//SEG22 main::@2
|
||||
b2:
|
||||
//SEG23 [10] *((const byte*) SCREEN#0 + (byte) main::i#2) ← ++ *((const byte*) SCREEN#0 + (byte) main::i#2) -- pbuc1_derefidx_vbuxx=_inc_pbuc1_derefidx_vbuxx
|
||||
inc SCREEN,x
|
||||
jmp b3
|
||||
}
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp b1
|
||||
Removing instruction jmp bend
|
||||
Removing instruction jmp b1
|
||||
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:
|
||||
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
|
||||
(byte*) SCREEN
|
||||
(const byte*) SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@3
|
||||
(label) main::@return
|
||||
(byte) main::i
|
||||
(byte) main::i#1 reg byte x 16.5
|
||||
(byte) main::i#2 reg byte x 18.333333333333332
|
||||
|
||||
reg byte x [ main::i#2 main::i#1 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 281
|
||||
|
||||
//SEG0 File Comments
|
||||
// Tests break statement in a simple loop
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
//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: {
|
||||
//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::@3 to main::@1 [phi:main::@3->main::@1]
|
||||
//SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@3->main::@1#0] -- register_copy
|
||||
//SEG15 main::@1
|
||||
b1:
|
||||
//SEG16 [6] if(*((const byte*) SCREEN#0 + (byte) main::i#2)!=(byte) ' ') goto main::@2 -- pbuc1_derefidx_vbuxx_neq_vbuc2_then_la1
|
||||
lda SCREEN,x
|
||||
cmp #' '
|
||||
bne b2
|
||||
//SEG17 main::@3
|
||||
b3:
|
||||
//SEG18 [7] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
//SEG19 [8] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $28*(byte/signed byte/word/signed word/dword/signed dword) 6+(byte/signed byte/word/signed word/dword/signed dword) 1) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
|
||||
cpx #$28*6+1
|
||||
bne b1
|
||||
//SEG20 main::@return
|
||||
//SEG21 [9] return
|
||||
rts
|
||||
//SEG22 main::@2
|
||||
b2:
|
||||
//SEG23 [10] *((const byte*) SCREEN#0 + (byte) main::i#2) ← ++ *((const byte*) SCREEN#0 + (byte) main::i#2) -- pbuc1_derefidx_vbuxx=_inc_pbuc1_derefidx_vbuxx
|
||||
inc SCREEN,x
|
||||
jmp b3
|
||||
}
|
||||
|
15
src/test/ref/loop-continue.sym
Normal file
15
src/test/ref/loop-continue.sym
Normal file
@ -0,0 +1,15 @@
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(byte*) SCREEN
|
||||
(const byte*) SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@3
|
||||
(label) main::@return
|
||||
(byte) main::i
|
||||
(byte) main::i#1 reg byte x 16.5
|
||||
(byte) main::i#2 reg byte x 18.333333333333332
|
||||
|
||||
reg byte x [ main::i#2 main::i#1 ]
|
21
src/test/ref/loop-while-continue.asm
Normal file
21
src/test/ref/loop-while-continue.asm
Normal file
@ -0,0 +1,21 @@
|
||||
// Tests break statement in a simple loop
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.label SCREEN = $400
|
||||
main: {
|
||||
ldx #0
|
||||
b1:
|
||||
inx
|
||||
cpx #$28*6
|
||||
bcc b2
|
||||
rts
|
||||
b2:
|
||||
lda SCREEN,x
|
||||
cmp #' '
|
||||
bne b3
|
||||
jmp b1
|
||||
b3:
|
||||
inc SCREEN,x
|
||||
jmp b1
|
||||
}
|
26
src/test/ref/loop-while-continue.cfg
Normal file
26
src/test/ref/loop-while-continue.cfg
Normal file
@ -0,0 +1,26 @@
|
||||
@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::@2 main::@3
|
||||
[5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@2/(byte) main::i#1 main::@3/(byte) main::i#1 )
|
||||
[6] (byte) main::i#1 ← ++ (byte) main::i#2
|
||||
[7] if((byte) main::i#1<(byte/signed byte/word/signed word/dword/signed dword) $28*(byte/signed byte/word/signed word/dword/signed dword) 6) goto main::@2
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[8] return
|
||||
to:@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
[9] if(*((const byte*) SCREEN#0 + (byte) main::i#1)!=(byte) ' ') goto main::@3
|
||||
to:main::@1
|
||||
main::@3: scope:[main] from main::@2
|
||||
[10] *((const byte*) SCREEN#0 + (byte) main::i#1) ← ++ *((const byte*) SCREEN#0 + (byte) main::i#1)
|
||||
to:main::@1
|
372
src/test/ref/loop-while-continue.log
Normal file
372
src/test/ref/loop-while-continue.log
Normal file
@ -0,0 +1,372 @@
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
@begin: scope:[] from
|
||||
(byte*) SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $400
|
||||
to:@1
|
||||
main: scope:[main] from @1
|
||||
(byte) main::i#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@2 main::@4
|
||||
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#3 main::@4/(byte) main::i#4 )
|
||||
(byte) main::i#1 ← ++ (byte) main::i#2
|
||||
(byte/word/signed word/dword/signed dword~) main::$0 ← (byte/signed byte/word/signed word/dword/signed dword) $28 * (byte/signed byte/word/signed word/dword/signed dword) 6
|
||||
(bool~) main::$1 ← (byte) main::i#1 < (byte/word/signed word/dword/signed dword~) main::$0
|
||||
if((bool~) main::$1) goto main::@2
|
||||
to:main::@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
(byte) main::i#3 ← phi( main::@1/(byte) main::i#1 )
|
||||
(bool~) main::$2 ← *((byte*) SCREEN#0 + (byte) main::i#3) == (byte) ' '
|
||||
(bool~) main::$3 ← ! (bool~) main::$2
|
||||
if((bool~) main::$3) goto main::@4
|
||||
to:main::@1
|
||||
main::@4: scope:[main] from main::@2
|
||||
(byte) main::i#4 ← phi( main::@2/(byte) main::i#3 )
|
||||
*((byte*) SCREEN#0 + (byte) main::i#4) ← ++ *((byte*) SCREEN#0 + (byte) main::i#4)
|
||||
to:main::@1
|
||||
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
|
||||
(byte*) SCREEN
|
||||
(byte*) SCREEN#0
|
||||
(void()) main()
|
||||
(byte/word/signed word/dword/signed dword~) main::$0
|
||||
(bool~) main::$1
|
||||
(bool~) main::$2
|
||||
(bool~) main::$3
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@4
|
||||
(label) main::@return
|
||||
(byte) main::i
|
||||
(byte) main::i#0
|
||||
(byte) main::i#1
|
||||
(byte) main::i#2
|
||||
(byte) main::i#3
|
||||
(byte) main::i#4
|
||||
|
||||
Culled Empty Block (label) @2
|
||||
Successful SSA optimization Pass2CullEmptyBlocks
|
||||
Inversing boolean not [9] (bool~) main::$3 ← *((byte*) SCREEN#0 + (byte) main::i#3) != (byte) ' ' from [8] (bool~) main::$2 ← *((byte*) SCREEN#0 + (byte) main::i#3) == (byte) ' '
|
||||
Successful SSA optimization Pass2UnaryNotSimplification
|
||||
Alias (byte) main::i#1 = (byte) main::i#3 (byte) main::i#4
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Simple Condition (bool~) main::$1 [6] if((byte) main::i#1<(byte/word/signed word/dword/signed dword~) main::$0) goto main::@2
|
||||
Simple Condition (bool~) main::$3 [10] if(*((byte*) SCREEN#0 + (byte) main::i#1)!=(byte) ' ') goto main::@4
|
||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||
Constant (const byte*) SCREEN#0 = ((byte*))$400
|
||||
Constant (const byte) main::i#0 = 0
|
||||
Constant (const byte/word/signed word/dword/signed dword) main::$0 = $28*6
|
||||
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/signed byte/word/signed word/dword/signed dword) $28*(byte/signed byte/word/signed word/dword/signed dword) 6
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Added new block during phi lifting main::@10(between main::@2 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 [10] main::i#5 ← main::i#1
|
||||
Coalesced (already) [12] main::i#6 ← main::i#1
|
||||
Coalesced down to 1 phi equivalence classes
|
||||
Culled Empty Block (label) main::@10
|
||||
Renumbering block main::@4 to 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::@2 main::@3
|
||||
[5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@2/(byte) main::i#1 main::@3/(byte) main::i#1 )
|
||||
[6] (byte) main::i#1 ← ++ (byte) main::i#2
|
||||
[7] if((byte) main::i#1<(byte/signed byte/word/signed word/dword/signed dword) $28*(byte/signed byte/word/signed word/dword/signed dword) 6) goto main::@2
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[8] return
|
||||
to:@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
[9] if(*((const byte*) SCREEN#0 + (byte) main::i#1)!=(byte) ' ') goto main::@3
|
||||
to:main::@1
|
||||
main::@3: scope:[main] from main::@2
|
||||
[10] *((const byte*) SCREEN#0 + (byte) main::i#1) ← ++ *((const byte*) SCREEN#0 + (byte) main::i#1)
|
||||
to:main::@1
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(byte*) SCREEN
|
||||
(void()) main()
|
||||
(byte) main::i
|
||||
(byte) main::i#1 109.25
|
||||
(byte) main::i#2 213.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
|
||||
// Tests break statement in a simple loop
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
//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 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 main::@1
|
||||
b1:
|
||||
//SEG14 [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
|
||||
inc i
|
||||
//SEG15 [7] if((byte) main::i#1<(byte/signed byte/word/signed word/dword/signed dword) $28*(byte/signed byte/word/signed word/dword/signed dword) 6) goto main::@2 -- vbuz1_lt_vbuc1_then_la1
|
||||
lda i
|
||||
cmp #$28*6
|
||||
bcc b2
|
||||
jmp breturn
|
||||
//SEG16 main::@return
|
||||
breturn:
|
||||
//SEG17 [8] return
|
||||
rts
|
||||
//SEG18 main::@2
|
||||
b2:
|
||||
//SEG19 [9] if(*((const byte*) SCREEN#0 + (byte) main::i#1)!=(byte) ' ') goto main::@3 -- pbuc1_derefidx_vbuz1_neq_vbuc2_then_la1
|
||||
lda #' '
|
||||
ldy i
|
||||
cmp SCREEN,y
|
||||
bne b3
|
||||
//SEG20 [5] phi from main::@2 main::@3 to main::@1 [phi:main::@2/main::@3->main::@1]
|
||||
b1_from_b2:
|
||||
b1_from_b3:
|
||||
//SEG21 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2/main::@3->main::@1#0] -- register_copy
|
||||
jmp b1
|
||||
//SEG22 main::@3
|
||||
b3:
|
||||
//SEG23 [10] *((const byte*) SCREEN#0 + (byte) main::i#1) ← ++ *((const byte*) SCREEN#0 + (byte) main::i#1) -- pbuc1_derefidx_vbuz1=_inc_pbuc1_derefidx_vbuz1
|
||||
ldx i
|
||||
inc SCREEN,x
|
||||
jmp b1_from_b3
|
||||
}
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [9] if(*((const byte*) SCREEN#0 + (byte) main::i#1)!=(byte) ' ') goto main::@3 [ main::i#1 ] ( main:2 [ main::i#1 ] ) 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 [9] if(*((const byte*) SCREEN#0 + (byte) main::i#1)!=(byte) ' ') goto main::@3 [ main::i#1 ] ( main:2 [ main::i#1 ] ) 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] 322.25: zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 2768 combination reg byte x [ main::i#2 main::i#1 ]
|
||||
Uplifting [] best 2768 combination
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
//SEG0 File Comments
|
||||
// Tests break statement in a simple loop
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
//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: {
|
||||
//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 main::@1
|
||||
b1:
|
||||
//SEG14 [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
//SEG15 [7] if((byte) main::i#1<(byte/signed byte/word/signed word/dword/signed dword) $28*(byte/signed byte/word/signed word/dword/signed dword) 6) goto main::@2 -- vbuxx_lt_vbuc1_then_la1
|
||||
cpx #$28*6
|
||||
bcc b2
|
||||
jmp breturn
|
||||
//SEG16 main::@return
|
||||
breturn:
|
||||
//SEG17 [8] return
|
||||
rts
|
||||
//SEG18 main::@2
|
||||
b2:
|
||||
//SEG19 [9] if(*((const byte*) SCREEN#0 + (byte) main::i#1)!=(byte) ' ') goto main::@3 -- pbuc1_derefidx_vbuxx_neq_vbuc2_then_la1
|
||||
lda SCREEN,x
|
||||
cmp #' '
|
||||
bne b3
|
||||
//SEG20 [5] phi from main::@2 main::@3 to main::@1 [phi:main::@2/main::@3->main::@1]
|
||||
b1_from_b2:
|
||||
b1_from_b3:
|
||||
//SEG21 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2/main::@3->main::@1#0] -- register_copy
|
||||
jmp b1
|
||||
//SEG22 main::@3
|
||||
b3:
|
||||
//SEG23 [10] *((const byte*) SCREEN#0 + (byte) main::i#1) ← ++ *((const byte*) SCREEN#0 + (byte) main::i#1) -- pbuc1_derefidx_vbuxx=_inc_pbuc1_derefidx_vbuxx
|
||||
inc SCREEN,x
|
||||
jmp b1_from_b3
|
||||
}
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp b1
|
||||
Removing instruction jmp bend
|
||||
Removing instruction jmp b1
|
||||
Removing instruction jmp breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction b1_from_bbegin:
|
||||
Removing instruction b1:
|
||||
Removing instruction main_from_b1:
|
||||
Removing instruction bend_from_b1:
|
||||
Removing instruction b1_from_b2:
|
||||
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
|
||||
Skipping double jump to b1 in jmp b1_from_b3
|
||||
Succesful ASM optimization Pass5DoubleJumpElimination
|
||||
Relabelling long label b1_from_b3 to b4
|
||||
Succesful ASM optimization Pass5RelabelLongLabels
|
||||
Removing instruction bbegin:
|
||||
Removing instruction b4:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(byte*) SCREEN
|
||||
(const byte*) SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@3
|
||||
(label) main::@return
|
||||
(byte) main::i
|
||||
(byte) main::i#1 reg byte x 109.25
|
||||
(byte) main::i#2 reg byte x 213.0
|
||||
|
||||
reg byte x [ main::i#2 main::i#1 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 2156
|
||||
|
||||
//SEG0 File Comments
|
||||
// Tests break statement in a simple loop
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
//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: {
|
||||
//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 main::@1
|
||||
b1:
|
||||
//SEG14 [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
//SEG15 [7] if((byte) main::i#1<(byte/signed byte/word/signed word/dword/signed dword) $28*(byte/signed byte/word/signed word/dword/signed dword) 6) goto main::@2 -- vbuxx_lt_vbuc1_then_la1
|
||||
cpx #$28*6
|
||||
bcc b2
|
||||
//SEG16 main::@return
|
||||
//SEG17 [8] return
|
||||
rts
|
||||
//SEG18 main::@2
|
||||
b2:
|
||||
//SEG19 [9] if(*((const byte*) SCREEN#0 + (byte) main::i#1)!=(byte) ' ') goto main::@3 -- pbuc1_derefidx_vbuxx_neq_vbuc2_then_la1
|
||||
lda SCREEN,x
|
||||
cmp #' '
|
||||
bne b3
|
||||
//SEG20 [5] phi from main::@2 main::@3 to main::@1 [phi:main::@2/main::@3->main::@1]
|
||||
//SEG21 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2/main::@3->main::@1#0] -- register_copy
|
||||
jmp b1
|
||||
//SEG22 main::@3
|
||||
b3:
|
||||
//SEG23 [10] *((const byte*) SCREEN#0 + (byte) main::i#1) ← ++ *((const byte*) SCREEN#0 + (byte) main::i#1) -- pbuc1_derefidx_vbuxx=_inc_pbuc1_derefidx_vbuxx
|
||||
inc SCREEN,x
|
||||
jmp b1
|
||||
}
|
||||
|
15
src/test/ref/loop-while-continue.sym
Normal file
15
src/test/ref/loop-while-continue.sym
Normal file
@ -0,0 +1,15 @@
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(byte*) SCREEN
|
||||
(const byte*) SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@3
|
||||
(label) main::@return
|
||||
(byte) main::i
|
||||
(byte) main::i#1 reg byte x 109.25
|
||||
(byte) main::i#2 reg byte x 213.0
|
||||
|
||||
reg byte x [ main::i#2 main::i#1 ]
|
Loading…
Reference in New Issue
Block a user