diff --git a/src/main/assembly/assembly.xml b/src/main/assembly/assembly.xml
index 26a71ba4c..0c1a6209d 100644
--- a/src/main/assembly/assembly.xml
+++ b/src/main/assembly/assembly.xml
@@ -31,6 +31,7 @@
*/*.kc
*/*.png
+ */*.sid
diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java
index d69a4c141..04dc2d3b0 100644
--- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java
+++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java
@@ -32,6 +32,11 @@ public class TestPrograms {
public TestPrograms() {
}
+ @Test
+ public void testLoopBreakContinue() throws IOException, URISyntaxException {
+ compileAndCompare("loop-break-continue");
+ }
+
@Test
public void testLoopWhileContinue() throws IOException, URISyntaxException {
compileAndCompare("loop-while-continue");
diff --git a/src/test/kc/loop-break-continue.kc b/src/test/kc/loop-break-continue.kc
new file mode 100644
index 000000000..4405f2c72
--- /dev/null
+++ b/src/test/kc/loop-break-continue.kc
@@ -0,0 +1,11 @@
+// Illustrates both break & continue statements in a loop
+// Prints a message ending at '@' skipping all spaces
+void main() {
+ byte* screen = $400;
+ byte[] str = "hello brave new world@";
+ for( byte i: 0..255) {
+ if(str[i]=='@') break;
+ if(str[i]==' ') continue;
+ *screen++ = str[i];
+ }
+}
diff --git a/src/test/ref/loop-break-continue.asm b/src/test/ref/loop-break-continue.asm
new file mode 100644
index 000000000..497bb9879
--- /dev/null
+++ b/src/test/ref/loop-break-continue.asm
@@ -0,0 +1,38 @@
+// Illustrates both break & continue statements in a loop
+// Prints a message ending at '@' skipping all spaces
+.pc = $801 "Basic"
+:BasicUpstart(main)
+.pc = $80d "Program"
+main: {
+ .label screen = 2
+ lda #<$400
+ sta screen
+ lda #>$400
+ sta screen+1
+ ldx #0
+ b1:
+ lda str,x
+ cmp #'@'
+ bne b2
+ breturn:
+ rts
+ b2:
+ lda str,x
+ cmp #' '
+ bne b3
+ b4:
+ inx
+ cpx #0
+ bne b1
+ jmp breturn
+ b3:
+ lda str,x
+ ldy #0
+ sta (screen),y
+ inc screen
+ bne !+
+ inc screen+1
+ !:
+ jmp b4
+ str: .text "hello brave new world@"
+}
diff --git a/src/test/ref/loop-break-continue.cfg b/src/test/ref/loop-break-continue.cfg
new file mode 100644
index 000000000..eedba7931
--- /dev/null
+++ b/src/test/ref/loop-break-continue.cfg
@@ -0,0 +1,32 @@
+@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::@4
+ [5] (byte*) main::screen#2 ← phi( main/((byte*))(word/signed word/dword/signed dword) $400 main::@4/(byte*) main::screen#5 )
+ [5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@4/(byte) main::i#1 )
+ [6] if(*((const byte[]) main::str#0 + (byte) main::i#2)!=(byte) '@') goto main::@2
+ to:main::@return
+main::@return: scope:[main] from main::@1 main::@4
+ [7] return
+ to:@return
+main::@2: scope:[main] from main::@1
+ [8] if(*((const byte[]) main::str#0 + (byte) main::i#2)!=(byte) ' ') goto main::@3
+ to:main::@4
+main::@4: scope:[main] from main::@2 main::@3
+ [9] (byte*) main::screen#5 ← phi( main::@2/(byte*) main::screen#2 main::@3/(byte*) main::screen#1 )
+ [10] (byte) main::i#1 ← ++ (byte) main::i#2
+ [11] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@1
+ to:main::@return
+main::@3: scope:[main] from main::@2
+ [12] *((byte*) main::screen#2) ← *((const byte[]) main::str#0 + (byte) main::i#2)
+ [13] (byte*) main::screen#1 ← ++ (byte*) main::screen#2
+ to:main::@4
diff --git a/src/test/ref/loop-break-continue.log b/src/test/ref/loop-break-continue.log
new file mode 100644
index 000000000..9c84fa171
--- /dev/null
+++ b/src/test/ref/loop-break-continue.log
@@ -0,0 +1,512 @@
+
+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::str#0 ← (const string) main::$5
+ (byte) main::i#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
+ to:main::@1
+main::@1: scope:[main] from main main::@5
+ (byte*) main::screen#4 ← phi( main/(byte*) main::screen#0 main::@5/(byte*) main::screen#5 )
+ (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@5/(byte) main::i#1 )
+ (bool~) main::$0 ← *((byte[]) main::str#0 + (byte) main::i#2) == (byte) '@'
+ (bool~) main::$1 ← ! (bool~) main::$0
+ if((bool~) main::$1) goto main::@2
+ to:main::@return
+main::@2: scope:[main] from main::@1
+ (byte*) main::screen#3 ← phi( main::@1/(byte*) main::screen#4 )
+ (byte) main::i#3 ← phi( main::@1/(byte) main::i#2 )
+ (bool~) main::$2 ← *((byte[]) main::str#0 + (byte) main::i#3) == (byte) ' '
+ (bool~) main::$3 ← ! (bool~) main::$2
+ if((bool~) main::$3) goto main::@4
+ to:main::@5
+main::@4: scope:[main] from main::@2
+ (byte*) main::screen#2 ← phi( main::@2/(byte*) main::screen#3 )
+ (byte) main::i#4 ← phi( main::@2/(byte) main::i#3 )
+ *((byte*) main::screen#2) ← *((byte[]) main::str#0 + (byte) main::i#4)
+ (byte*) main::screen#1 ← ++ (byte*) main::screen#2
+ to:main::@5
+main::@5: scope:[main] from main::@2 main::@4
+ (byte*) main::screen#5 ← phi( main::@2/(byte*) main::screen#3 main::@4/(byte*) main::screen#1 )
+ (byte) main::i#5 ← phi( main::@2/(byte) main::i#3 main::@4/(byte) main::i#4 )
+ (byte) main::i#1 ← (byte) main::i#5 + rangenext(0,$ff)
+ (bool~) main::$4 ← (byte) main::i#1 != rangelast(0,$ff)
+ if((bool~) main::$4) goto main::@1
+ to:main::@return
+main::@return: scope:[main] from main::@1 main::@5
+ 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
+(bool~) main::$2
+(bool~) main::$3
+(bool~) main::$4
+(const string) main::$5 = (string) "hello brave new world@"
+(label) main::@1
+(label) main::@2
+(label) main::@4
+(label) main::@5
+(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
+(byte) main::i#5
+(byte*) main::screen
+(byte*) main::screen#0
+(byte*) main::screen#1
+(byte*) main::screen#2
+(byte*) main::screen#3
+(byte*) main::screen#4
+(byte*) main::screen#5
+(byte[]) main::str
+(byte[]) main::str#0
+
+Culled Empty Block (label) @2
+Successful SSA optimization Pass2CullEmptyBlocks
+Inversing boolean not [5] (bool~) main::$1 ← *((byte[]) main::str#0 + (byte) main::i#2) != (byte) '@' from [4] (bool~) main::$0 ← *((byte[]) main::str#0 + (byte) main::i#2) == (byte) '@'
+Inversing boolean not [9] (bool~) main::$3 ← *((byte[]) main::str#0 + (byte) main::i#3) != (byte) ' ' from [8] (bool~) main::$2 ← *((byte[]) main::str#0 + (byte) main::i#3) == (byte) ' '
+Successful SSA optimization Pass2UnaryNotSimplification
+Alias (byte) main::i#2 = (byte) main::i#3 (byte) main::i#4
+Alias (byte*) main::screen#2 = (byte*) main::screen#3 (byte*) main::screen#4
+Successful SSA optimization Pass2AliasElimination
+Alias (byte) main::i#2 = (byte) main::i#5
+Successful SSA optimization Pass2AliasElimination
+Simple Condition (bool~) main::$1 [6] if(*((byte[]) main::str#0 + (byte) main::i#2)!=(byte) '@') goto main::@2
+Simple Condition (bool~) main::$3 [10] if(*((byte[]) main::str#0 + (byte) main::i#2)!=(byte) ' ') goto main::@4
+Simple Condition (bool~) main::$4 [17] if((byte) main::i#1!=rangelast(0,$ff)) goto main::@1
+Successful SSA optimization Pass2ConditionalJumpSimplification
+Constant (const byte*) main::screen#0 = ((byte*))$400
+Constant (const byte[]) main::str#0 = main::$5
+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,$ff)) goto main::@1 to (byte/signed byte/word/signed word/dword/signed dword) 0
+Inlining constant with var siblings (const byte*) main::screen#0
+Inlining constant with var siblings (const byte) main::i#0
+Constant inlined main::$5 = (const byte[]) main::str#0
+Constant inlined main::screen#0 = ((byte*))(word/signed word/dword/signed dword) $400
+Constant inlined main::i#0 = (byte/signed byte/word/signed word/dword/signed dword) 0
+Successful SSA optimization Pass2ConstantInlining
+Added new block during phi lifting main::@11(between main::@5 and main::@1)
+Added new block during phi lifting main::@12(between main::@2 and 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
+CALL GRAPH
+Calls in [] to main:2
+
+Created 3 initial phi equivalence classes
+Coalesced [9] main::screen#7 ← main::screen#2
+Coalesced [13] main::i#6 ← main::i#1
+Coalesced (already) [14] main::screen#6 ← main::screen#5
+Coalesced [17] main::screen#8 ← main::screen#1
+Coalesced down to 2 phi equivalence classes
+Culled Empty Block (label) main::@12
+Culled Empty Block (label) main::@11
+Renumbering block main::@4 to main::@3
+Renumbering block main::@5 to main::@4
+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::@4
+ [5] (byte*) main::screen#2 ← phi( main/((byte*))(word/signed word/dword/signed dword) $400 main::@4/(byte*) main::screen#5 )
+ [5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@4/(byte) main::i#1 )
+ [6] if(*((const byte[]) main::str#0 + (byte) main::i#2)!=(byte) '@') goto main::@2
+ to:main::@return
+main::@return: scope:[main] from main::@1 main::@4
+ [7] return
+ to:@return
+main::@2: scope:[main] from main::@1
+ [8] if(*((const byte[]) main::str#0 + (byte) main::i#2)!=(byte) ' ') goto main::@3
+ to:main::@4
+main::@4: scope:[main] from main::@2 main::@3
+ [9] (byte*) main::screen#5 ← phi( main::@2/(byte*) main::screen#2 main::@3/(byte*) main::screen#1 )
+ [10] (byte) main::i#1 ← ++ (byte) main::i#2
+ [11] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@1
+ to:main::@return
+main::@3: scope:[main] from main::@2
+ [12] *((byte*) main::screen#2) ← *((const byte[]) main::str#0 + (byte) main::i#2)
+ [13] (byte*) main::screen#1 ← ++ (byte*) main::screen#2
+ to:main::@4
+
+
+VARIABLE REGISTER WEIGHTS
+(void()) main()
+(byte) main::i
+(byte) main::i#1 16.5
+(byte) main::i#2 9.166666666666666
+(byte*) main::screen
+(byte*) main::screen#1 22.0
+(byte*) main::screen#2 11.0
+(byte*) main::screen#5 11.0
+(byte[]) main::str
+
+Initial phi equivalence classes
+[ main::i#2 main::i#1 ]
+[ main::screen#2 main::screen#5 main::screen#1 ]
+Complete equivalence classes
+[ main::i#2 main::i#1 ]
+[ main::screen#2 main::screen#5 main::screen#1 ]
+Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
+Allocated zp ZP_WORD:3 [ main::screen#2 main::screen#5 main::screen#1 ]
+
+INITIAL ASM
+//SEG0 File Comments
+// Illustrates both break & continue statements in a loop
+// Prints a message ending at '@' skipping all spaces
+//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 = 3
+ .label i = 2
+ //SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
+ b1_from_main:
+ //SEG12 [5] phi (byte*) main::screen#2 = ((byte*))(word/signed word/dword/signed dword) $400 [phi:main->main::@1#0] -- pbuz1=pbuc1
+ lda #<$400
+ sta screen
+ lda #>$400
+ sta screen+1
+ //SEG13 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#1] -- vbuz1=vbuc1
+ lda #0
+ sta i
+ jmp b1
+ //SEG14 [5] phi from main::@4 to main::@1 [phi:main::@4->main::@1]
+ b1_from_b4:
+ //SEG15 [5] phi (byte*) main::screen#2 = (byte*) main::screen#5 [phi:main::@4->main::@1#0] -- register_copy
+ //SEG16 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@4->main::@1#1] -- register_copy
+ jmp b1
+ //SEG17 main::@1
+ b1:
+ //SEG18 [6] if(*((const byte[]) main::str#0 + (byte) main::i#2)!=(byte) '@') goto main::@2 -- pbuc1_derefidx_vbuz1_neq_vbuc2_then_la1
+ lda #'@'
+ ldy i
+ cmp str,y
+ bne b2
+ jmp breturn
+ //SEG19 main::@return
+ breturn:
+ //SEG20 [7] return
+ rts
+ //SEG21 main::@2
+ b2:
+ //SEG22 [8] if(*((const byte[]) main::str#0 + (byte) main::i#2)!=(byte) ' ') goto main::@3 -- pbuc1_derefidx_vbuz1_neq_vbuc2_then_la1
+ lda #' '
+ ldy i
+ cmp str,y
+ bne b3
+ //SEG23 [9] phi from main::@2 main::@3 to main::@4 [phi:main::@2/main::@3->main::@4]
+ b4_from_b2:
+ b4_from_b3:
+ //SEG24 [9] phi (byte*) main::screen#5 = (byte*) main::screen#2 [phi:main::@2/main::@3->main::@4#0] -- register_copy
+ jmp b4
+ //SEG25 main::@4
+ b4:
+ //SEG26 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
+ inc i
+ //SEG27 [11] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@1 -- vbuz1_neq_0_then_la1
+ lda i
+ cmp #0
+ bne b1_from_b4
+ jmp breturn
+ //SEG28 main::@3
+ b3:
+ //SEG29 [12] *((byte*) main::screen#2) ← *((const byte[]) main::str#0 + (byte) main::i#2) -- _deref_pbuz1=pbuc1_derefidx_vbuz2
+ ldy i
+ lda str,y
+ ldy #0
+ sta (screen),y
+ //SEG30 [13] (byte*) main::screen#1 ← ++ (byte*) main::screen#2 -- pbuz1=_inc_pbuz1
+ inc screen
+ bne !+
+ inc screen+1
+ !:
+ jmp b4_from_b3
+ str: .text "hello brave new world@"
+}
+
+REGISTER UPLIFT POTENTIAL REGISTERS
+Statement [6] if(*((const byte[]) main::str#0 + (byte) main::i#2)!=(byte) '@') goto main::@2 [ main::i#2 main::screen#2 ] ( main:2 [ main::i#2 main::screen#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 [8] if(*((const byte[]) main::str#0 + (byte) main::i#2)!=(byte) ' ') goto main::@3 [ main::i#2 main::screen#2 ] ( main:2 [ main::i#2 main::screen#2 ] ) always clobbers reg byte a
+Statement [12] *((byte*) main::screen#2) ← *((const byte[]) main::str#0 + (byte) main::i#2) [ main::i#2 main::screen#2 ] ( main:2 [ main::i#2 main::screen#2 ] ) always clobbers reg byte a reg byte y
+Removing always clobbered register reg byte y as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
+Statement [6] if(*((const byte[]) main::str#0 + (byte) main::i#2)!=(byte) '@') goto main::@2 [ main::i#2 main::screen#2 ] ( main:2 [ main::i#2 main::screen#2 ] ) always clobbers reg byte a
+Statement [8] if(*((const byte[]) main::str#0 + (byte) main::i#2)!=(byte) ' ') goto main::@3 [ main::i#2 main::screen#2 ] ( main:2 [ main::i#2 main::screen#2 ] ) always clobbers reg byte a
+Statement [12] *((byte*) main::screen#2) ← *((const byte[]) main::str#0 + (byte) main::i#2) [ main::i#2 main::screen#2 ] ( main:2 [ main::i#2 main::screen#2 ] ) always clobbers reg byte a reg byte y
+Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte x ,
+Potential registers zp ZP_WORD:3 [ main::screen#2 main::screen#5 main::screen#1 ] : zp ZP_WORD:3 ,
+
+REGISTER UPLIFT SCOPES
+Uplift Scope [main] 44: zp ZP_WORD:3 [ main::screen#2 main::screen#5 main::screen#1 ] 25.67: zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
+Uplift Scope []
+
+Uplifting [main] best 813 combination zp ZP_WORD:3 [ main::screen#2 main::screen#5 main::screen#1 ] reg byte x [ main::i#2 main::i#1 ]
+Uplifting [] best 813 combination
+Allocated (was zp ZP_WORD:3) zp ZP_WORD:2 [ main::screen#2 main::screen#5 main::screen#1 ]
+
+ASSEMBLER BEFORE OPTIMIZATION
+//SEG0 File Comments
+// Illustrates both break & continue statements in a loop
+// Prints a message ending at '@' skipping all spaces
+//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 = 2
+ //SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
+ b1_from_main:
+ //SEG12 [5] phi (byte*) main::screen#2 = ((byte*))(word/signed word/dword/signed dword) $400 [phi:main->main::@1#0] -- pbuz1=pbuc1
+ lda #<$400
+ sta screen
+ lda #>$400
+ sta screen+1
+ //SEG13 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1
+ ldx #0
+ jmp b1
+ //SEG14 [5] phi from main::@4 to main::@1 [phi:main::@4->main::@1]
+ b1_from_b4:
+ //SEG15 [5] phi (byte*) main::screen#2 = (byte*) main::screen#5 [phi:main::@4->main::@1#0] -- register_copy
+ //SEG16 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@4->main::@1#1] -- register_copy
+ jmp b1
+ //SEG17 main::@1
+ b1:
+ //SEG18 [6] if(*((const byte[]) main::str#0 + (byte) main::i#2)!=(byte) '@') goto main::@2 -- pbuc1_derefidx_vbuxx_neq_vbuc2_then_la1
+ lda str,x
+ cmp #'@'
+ bne b2
+ jmp breturn
+ //SEG19 main::@return
+ breturn:
+ //SEG20 [7] return
+ rts
+ //SEG21 main::@2
+ b2:
+ //SEG22 [8] if(*((const byte[]) main::str#0 + (byte) main::i#2)!=(byte) ' ') goto main::@3 -- pbuc1_derefidx_vbuxx_neq_vbuc2_then_la1
+ lda str,x
+ cmp #' '
+ bne b3
+ //SEG23 [9] phi from main::@2 main::@3 to main::@4 [phi:main::@2/main::@3->main::@4]
+ b4_from_b2:
+ b4_from_b3:
+ //SEG24 [9] phi (byte*) main::screen#5 = (byte*) main::screen#2 [phi:main::@2/main::@3->main::@4#0] -- register_copy
+ jmp b4
+ //SEG25 main::@4
+ b4:
+ //SEG26 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
+ inx
+ //SEG27 [11] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@1 -- vbuxx_neq_0_then_la1
+ cpx #0
+ bne b1_from_b4
+ jmp breturn
+ //SEG28 main::@3
+ b3:
+ //SEG29 [12] *((byte*) main::screen#2) ← *((const byte[]) main::str#0 + (byte) main::i#2) -- _deref_pbuz1=pbuc1_derefidx_vbuxx
+ lda str,x
+ ldy #0
+ sta (screen),y
+ //SEG30 [13] (byte*) main::screen#1 ← ++ (byte*) main::screen#2 -- pbuz1=_inc_pbuz1
+ inc screen
+ bne !+
+ inc screen+1
+ !:
+ jmp b4_from_b3
+ str: .text "hello brave new world@"
+}
+
+ASSEMBLER OPTIMIZATIONS
+Removing instruction jmp b1
+Removing instruction jmp bend
+Removing instruction jmp b1
+Removing instruction jmp breturn
+Removing instruction jmp b4
+Succesful ASM optimization Pass5NextJumpElimination
+Replacing label b1_from_b4 with b1
+Replacing label b4_from_b3 with b4
+Removing instruction b1_from_bbegin:
+Removing instruction b1:
+Removing instruction main_from_b1:
+Removing instruction bend_from_b1:
+Removing instruction b1_from_b4:
+Removing instruction b4_from_b2:
+Removing instruction b4_from_b3:
+Succesful ASM optimization Pass5RedundantLabelElimination
+Removing instruction bend:
+Removing instruction b1_from_main:
+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::@2
+(label) main::@3
+(label) main::@4
+(label) main::@return
+(byte) main::i
+(byte) main::i#1 reg byte x 16.5
+(byte) main::i#2 reg byte x 9.166666666666666
+(byte*) main::screen
+(byte*) main::screen#1 screen zp ZP_WORD:2 22.0
+(byte*) main::screen#2 screen zp ZP_WORD:2 11.0
+(byte*) main::screen#5 screen zp ZP_WORD:2 11.0
+(byte[]) main::str
+(const byte[]) main::str#0 str = (string) "hello brave new world@"
+
+reg byte x [ main::i#2 main::i#1 ]
+zp ZP_WORD:2 [ main::screen#2 main::screen#5 main::screen#1 ]
+
+
+FINAL ASSEMBLER
+Score: 681
+
+//SEG0 File Comments
+// Illustrates both break & continue statements in a loop
+// Prints a message ending at '@' skipping all spaces
+//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 = 2
+ //SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
+ //SEG12 [5] phi (byte*) main::screen#2 = ((byte*))(word/signed word/dword/signed dword) $400 [phi:main->main::@1#0] -- pbuz1=pbuc1
+ lda #<$400
+ sta screen
+ lda #>$400
+ sta screen+1
+ //SEG13 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1
+ ldx #0
+ //SEG14 [5] phi from main::@4 to main::@1 [phi:main::@4->main::@1]
+ //SEG15 [5] phi (byte*) main::screen#2 = (byte*) main::screen#5 [phi:main::@4->main::@1#0] -- register_copy
+ //SEG16 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@4->main::@1#1] -- register_copy
+ //SEG17 main::@1
+ b1:
+ //SEG18 [6] if(*((const byte[]) main::str#0 + (byte) main::i#2)!=(byte) '@') goto main::@2 -- pbuc1_derefidx_vbuxx_neq_vbuc2_then_la1
+ lda str,x
+ cmp #'@'
+ bne b2
+ //SEG19 main::@return
+ breturn:
+ //SEG20 [7] return
+ rts
+ //SEG21 main::@2
+ b2:
+ //SEG22 [8] if(*((const byte[]) main::str#0 + (byte) main::i#2)!=(byte) ' ') goto main::@3 -- pbuc1_derefidx_vbuxx_neq_vbuc2_then_la1
+ lda str,x
+ cmp #' '
+ bne b3
+ //SEG23 [9] phi from main::@2 main::@3 to main::@4 [phi:main::@2/main::@3->main::@4]
+ //SEG24 [9] phi (byte*) main::screen#5 = (byte*) main::screen#2 [phi:main::@2/main::@3->main::@4#0] -- register_copy
+ //SEG25 main::@4
+ b4:
+ //SEG26 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
+ inx
+ //SEG27 [11] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@1 -- vbuxx_neq_0_then_la1
+ cpx #0
+ bne b1
+ jmp breturn
+ //SEG28 main::@3
+ b3:
+ //SEG29 [12] *((byte*) main::screen#2) ← *((const byte[]) main::str#0 + (byte) main::i#2) -- _deref_pbuz1=pbuc1_derefidx_vbuxx
+ lda str,x
+ ldy #0
+ sta (screen),y
+ //SEG30 [13] (byte*) main::screen#1 ← ++ (byte*) main::screen#2 -- pbuz1=_inc_pbuz1
+ inc screen
+ bne !+
+ inc screen+1
+ !:
+ jmp b4
+ str: .text "hello brave new world@"
+}
+
diff --git a/src/test/ref/loop-break-continue.sym b/src/test/ref/loop-break-continue.sym
new file mode 100644
index 000000000..74a5c3d8d
--- /dev/null
+++ b/src/test/ref/loop-break-continue.sym
@@ -0,0 +1,21 @@
+(label) @1
+(label) @begin
+(label) @end
+(void()) main()
+(label) main::@1
+(label) main::@2
+(label) main::@3
+(label) main::@4
+(label) main::@return
+(byte) main::i
+(byte) main::i#1 reg byte x 16.5
+(byte) main::i#2 reg byte x 9.166666666666666
+(byte*) main::screen
+(byte*) main::screen#1 screen zp ZP_WORD:2 22.0
+(byte*) main::screen#2 screen zp ZP_WORD:2 11.0
+(byte*) main::screen#5 screen zp ZP_WORD:2 11.0
+(byte[]) main::str
+(const byte[]) main::str#0 str = (string) "hello brave new world@"
+
+reg byte x [ main::i#2 main::i#1 ]
+zp ZP_WORD:2 [ main::screen#2 main::screen#5 main::screen#1 ]