6019 - finish supporting all branch primitives
I'd been thinking I didn't need unconditional `break` instructions, but I just realized that non-local unconditional breaks have a use. Stop over-thinking this, just support everything. The code is quite duplicated.
This commit is contained in:
parent
75b9ff5010
commit
01a28c56c7
239
apps/mu.subx
239
apps/mu.subx
|
@ -1531,6 +1531,190 @@ test-convert-function-with-nonlocal-branches-and-loops-and-local-vars:
|
|||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
test-convert-function-with-nonlocal-unconditional-break-and-local-vars:
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
89/<- %ebp 4/r32/esp
|
||||
# setup
|
||||
(clear-stream _test-input-stream)
|
||||
(clear-stream $_test-input-buffered-file->buffer)
|
||||
(clear-stream _test-output-stream)
|
||||
(clear-stream $_test-output-buffered-file->buffer)
|
||||
c7 0/subop/copy *Next-block-index 1/imm32
|
||||
#
|
||||
(write _test-input-stream "fn foo {\n")
|
||||
(write _test-input-stream " a: {\n")
|
||||
(write _test-input-stream " var x: int\n")
|
||||
(write _test-input-stream " {\n")
|
||||
(write _test-input-stream " var y: int\n")
|
||||
(write _test-input-stream " break a\n")
|
||||
(write _test-input-stream " increment x\n")
|
||||
(write _test-input-stream " }\n")
|
||||
(write _test-input-stream " }\n")
|
||||
(write _test-input-stream "}\n")
|
||||
# convert
|
||||
(convert-mu _test-input-buffered-file _test-output-buffered-file)
|
||||
(flush _test-output-buffered-file)
|
||||
#? # dump _test-output-stream {{{
|
||||
#? (write 2 "^")
|
||||
#? (write-stream 2 _test-output-stream)
|
||||
#? (write 2 "$\n")
|
||||
#? (rewind-stream _test-output-stream)
|
||||
#? # }}}
|
||||
# check output
|
||||
(check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/0")
|
||||
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/1")
|
||||
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/2")
|
||||
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/3")
|
||||
(check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/4")
|
||||
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/5")
|
||||
(check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/6")
|
||||
(check-next-stream-line-equal _test-output-stream "a:loop:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/7")
|
||||
(check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/8")
|
||||
(check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/9")
|
||||
(check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/10")
|
||||
(check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/11")
|
||||
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/12")
|
||||
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/13")
|
||||
(check-next-stream-line-equal _test-output-stream " e9/jump a:break/disp32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/14")
|
||||
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/15")
|
||||
(check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/16")
|
||||
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/17")
|
||||
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/18")
|
||||
(check-next-stream-line-equal _test-output-stream "a:break:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/19")
|
||||
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/20")
|
||||
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/21")
|
||||
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/22")
|
||||
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/23")
|
||||
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/24")
|
||||
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/25")
|
||||
# . epilogue
|
||||
89/<- %esp 5/r32/ebp
|
||||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
test-convert-function-with-unconditional-break-and-local-vars:
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
89/<- %ebp 4/r32/esp
|
||||
# setup
|
||||
(clear-stream _test-input-stream)
|
||||
(clear-stream $_test-input-buffered-file->buffer)
|
||||
(clear-stream _test-output-stream)
|
||||
(clear-stream $_test-output-buffered-file->buffer)
|
||||
c7 0/subop/copy *Next-block-index 1/imm32
|
||||
#
|
||||
(write _test-input-stream "fn foo {\n")
|
||||
(write _test-input-stream " {\n")
|
||||
(write _test-input-stream " var x: int\n")
|
||||
(write _test-input-stream " {\n")
|
||||
(write _test-input-stream " var y: int\n")
|
||||
(write _test-input-stream " break\n")
|
||||
(write _test-input-stream " increment x\n")
|
||||
(write _test-input-stream " }\n")
|
||||
(write _test-input-stream " }\n")
|
||||
(write _test-input-stream "}\n")
|
||||
# convert
|
||||
(convert-mu _test-input-buffered-file _test-output-buffered-file)
|
||||
(flush _test-output-buffered-file)
|
||||
#? # dump _test-output-stream {{{
|
||||
#? (write 2 "^")
|
||||
#? (write-stream 2 _test-output-stream)
|
||||
#? (write 2 "$\n")
|
||||
#? (rewind-stream _test-output-stream)
|
||||
#? # }}}
|
||||
# check output
|
||||
(check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-unconditional-break-and-local-vars/0")
|
||||
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-unconditional-break-and-local-vars/1")
|
||||
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-unconditional-break-and-local-vars/2")
|
||||
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-unconditional-break-and-local-vars/3")
|
||||
(check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-break-and-local-vars/4")
|
||||
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-unconditional-break-and-local-vars/5")
|
||||
(check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-break-and-local-vars/6")
|
||||
(check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-unconditional-break-and-local-vars/7")
|
||||
(check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/8")
|
||||
(check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-break-and-local-vars/9")
|
||||
(check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-unconditional-break-and-local-vars/10")
|
||||
(check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/11")
|
||||
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/12")
|
||||
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-break-and-local-vars/13")
|
||||
(check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-unconditional-break-and-local-vars/14")
|
||||
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/15")
|
||||
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-break-and-local-vars/16")
|
||||
(check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-unconditional-break-and-local-vars/17")
|
||||
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-break-and-local-vars/18")
|
||||
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-unconditional-break-and-local-vars/19")
|
||||
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-unconditional-break-and-local-vars/20")
|
||||
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-unconditional-break-and-local-vars/21")
|
||||
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-unconditional-break-and-local-vars/22")
|
||||
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-unconditional-break-and-local-vars/23")
|
||||
# . epilogue
|
||||
89/<- %esp 5/r32/ebp
|
||||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
test-convert-function-with-nonlocal-unconditional-loop-and-local-vars:
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
89/<- %ebp 4/r32/esp
|
||||
# setup
|
||||
(clear-stream _test-input-stream)
|
||||
(clear-stream $_test-input-buffered-file->buffer)
|
||||
(clear-stream _test-output-stream)
|
||||
(clear-stream $_test-output-buffered-file->buffer)
|
||||
c7 0/subop/copy *Next-block-index 1/imm32
|
||||
#
|
||||
(write _test-input-stream "fn foo {\n")
|
||||
(write _test-input-stream " a: {\n")
|
||||
(write _test-input-stream " var x: int\n")
|
||||
(write _test-input-stream " {\n")
|
||||
(write _test-input-stream " var y: int\n")
|
||||
(write _test-input-stream " loop a\n")
|
||||
(write _test-input-stream " increment x\n")
|
||||
(write _test-input-stream " }\n")
|
||||
(write _test-input-stream " }\n")
|
||||
(write _test-input-stream "}\n")
|
||||
# convert
|
||||
(convert-mu _test-input-buffered-file _test-output-buffered-file)
|
||||
(flush _test-output-buffered-file)
|
||||
#? # dump _test-output-stream {{{
|
||||
#? (write 2 "^")
|
||||
#? (write-stream 2 _test-output-stream)
|
||||
#? (write 2 "$\n")
|
||||
#? (rewind-stream _test-output-stream)
|
||||
#? # }}}
|
||||
# check output
|
||||
(check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/0")
|
||||
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/1")
|
||||
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/2")
|
||||
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/3")
|
||||
(check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/4")
|
||||
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/5")
|
||||
(check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/6")
|
||||
(check-next-stream-line-equal _test-output-stream "a:loop:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/7")
|
||||
(check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/8")
|
||||
(check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/9")
|
||||
(check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/10")
|
||||
(check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/11")
|
||||
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/12")
|
||||
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/13")
|
||||
(check-next-stream-line-equal _test-output-stream " e9/jump a:loop/disp32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/14")
|
||||
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/15")
|
||||
(check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/16")
|
||||
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/17")
|
||||
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/18")
|
||||
(check-next-stream-line-equal _test-output-stream "a:break:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/19")
|
||||
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/20")
|
||||
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/21")
|
||||
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/22")
|
||||
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/23")
|
||||
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/24")
|
||||
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/25")
|
||||
# . epilogue
|
||||
89/<- %esp 5/r32/ebp
|
||||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
#######################################################
|
||||
# Parsing
|
||||
#######################################################
|
||||
|
@ -4518,32 +4702,74 @@ $emit-subx-stmt-list:branch-stmt-and-var-seen:
|
|||
(string-equal? *(ecx+4) "loop") # Stmt1-operation => eax
|
||||
3d/compare-eax-and 0/imm32/false
|
||||
0f 84/jump-if-= break/disp32
|
||||
$emit-subx-stmt-list:unconditional-loop:
|
||||
81 7/subop/compare *(ecx+8) 0/imm32 # Stmt1-inouts
|
||||
# simple unconditional loops without a target {{{
|
||||
{
|
||||
0f 85/jump-if-!= break/disp32
|
||||
$emit-subx-stmt-list:zero-arg-unconditional-loop:
|
||||
(emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
|
||||
(emit-indent *(ebp+8) *Curr-block-depth)
|
||||
(write-buffered *(ebp+8) "e9/jump loop/disp32")
|
||||
(write-buffered *(ebp+8) Newline)
|
||||
(clean-up-blocks *(ebp+0x10) *Curr-block-depth)
|
||||
e9/jump $emit-subx-stmt-list:end/disp32 # skip remaining statements; they're dead code
|
||||
e9/jump $emit-subx-stmt-list:cleanup/disp32 # skip remaining statements; they're dead code
|
||||
}
|
||||
# }}}
|
||||
# unconditional loops with a target {{{
|
||||
{
|
||||
0f 84/jump-if-= break/disp32
|
||||
# TODO
|
||||
$emit-subx-stmt-list:unconditional-loop-with-target:
|
||||
# var target/ebx: (addr array byte) = curr-stmt->inouts->value->name
|
||||
8b/-> *(ecx+8) 3/r32/ebx # Stmt1-inouts
|
||||
8b/-> *ebx 3/r32/ebx # List-value
|
||||
8b/-> *ebx 3/r32/ebx # Var-name
|
||||
# clean up until target block
|
||||
(emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %ebx)
|
||||
# emit jump to target block
|
||||
(emit-indent *(ebp+8) *Curr-block-depth)
|
||||
(write-buffered *(ebp+8) "e9/jump ")
|
||||
(write-buffered *(ebp+8) %ebx)
|
||||
(write-buffered *(ebp+8) ":loop/disp32\n")
|
||||
# done
|
||||
e9/jump $emit-subx-stmt-list:cleanup/disp32
|
||||
}
|
||||
# }}}
|
||||
}
|
||||
# }}}
|
||||
# unconditional breaks {{{
|
||||
{
|
||||
# if (!string-equal?(var->operation, "break")) break
|
||||
(string-equal? *(ecx+4) "break") # Stmt1-operation => eax
|
||||
3d/compare-eax-and 0/imm32/false
|
||||
0f 84/jump-if-= break/disp32
|
||||
$emit-subx-stmt-list:unconditional-break:
|
||||
81 7/subop/compare *(ecx+8) 0/imm32 # Stmt1-inouts
|
||||
# simple unconditional breaks without a target
|
||||
0f 84/jump-if-= $emit-subx-stmt-list:emit-cleanup/disp32 # easy: just skip remaining statements
|
||||
# unconditional breaks with a target {{{
|
||||
$emit-subx-stmt-list:unconditional-break-with-target:
|
||||
# var target/ebx: (addr array byte) = curr-stmt->inouts->value->name
|
||||
8b/-> *(ecx+8) 3/r32/ebx # Stmt1-inouts
|
||||
8b/-> *ebx 3/r32/ebx # List-value
|
||||
8b/-> *ebx 3/r32/ebx # Var-name
|
||||
# clean up until target block
|
||||
(emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %ebx)
|
||||
# emit jump to target block
|
||||
(emit-indent *(ebp+8) *Curr-block-depth)
|
||||
(write-buffered *(ebp+8) "e9/jump ")
|
||||
(write-buffered *(ebp+8) %ebx)
|
||||
(write-buffered *(ebp+8) ":break/disp32\n")
|
||||
# done
|
||||
e9/jump $emit-subx-stmt-list:cleanup/disp32
|
||||
# }}}
|
||||
}
|
||||
# }}}
|
||||
# conditional branches {{{
|
||||
# simple conditional branches without a target {{{
|
||||
81 7/subop/compare *(ecx+8) 0/imm32 # Stmt1-inouts
|
||||
{
|
||||
0f 85/jump-if-!= break/disp32
|
||||
$emit-subx-stmt-list:zero-arg-branch:
|
||||
$emit-subx-stmt-list:zero-arg-conditional-branch:
|
||||
# var old-block-depth/eax: int = Curr-block-depth - 1
|
||||
8b/-> *Curr-block-depth 3/r32/ebx
|
||||
# cleanup prologue
|
||||
|
@ -4579,7 +4805,7 @@ $emit-subx-stmt-list:zero-arg-branch:
|
|||
# conditional branches with an explicit target {{{
|
||||
{
|
||||
0f 84/jump-if-= break/disp32
|
||||
$emit-subx-stmt-list:branch-with-target:
|
||||
$emit-subx-stmt-list:conditional-branch-with-target:
|
||||
# var target/ebx: (addr array byte) = curr-stmt->inouts->value->name
|
||||
8b/-> *(ecx+8) 3/r32/ebx # Stmt1-inouts
|
||||
8b/-> *ebx 3/r32/ebx # List-value
|
||||
|
@ -4659,8 +4885,9 @@ $emit-subx-stmt-list:continue:
|
|||
8b/-> *(esi+4) 6/r32/esi # List-next
|
||||
e9/jump loop/disp32
|
||||
}
|
||||
$emit-subx-stmt-list:cleanup:
|
||||
$emit-subx-stmt-list:emit-cleanup:
|
||||
(emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
|
||||
$emit-subx-stmt-list:cleanup:
|
||||
(clean-up-blocks *(ebp+0x10) *Curr-block-depth)
|
||||
$emit-subx-stmt-list:end:
|
||||
# . restore registers
|
||||
|
|
|
@ -184,7 +184,7 @@ Finally, unconditional jumps:
|
|||
|
||||
loop {.name="loop", .subx-name="e9/jump loop/disp32"}
|
||||
loop label {.name="loop", .inouts=[label], .subx-name="e9/jump", .disp32=inouts[0] ":loop"}
|
||||
|
||||
(So far it doesn't seem like unconditional breaks have much use.)
|
||||
break {.name="break", .subx-name="e9/jump break/disp32"}
|
||||
break label {.name="break", .inouts=[label], .subx-name="e9/jump", .disp32=inouts[0] ":break"}
|
||||
|
||||
vim:ft=c:nowrap
|
||||
|
|
|
@ -125,14 +125,15 @@ Jumps can take an optional label starting with '$':
|
|||
loop $foo
|
||||
|
||||
This instruction jumps to the beginning of the block called $foo. It must lie
|
||||
somewhere inside such a box. Jumps are only legal to containing blocks. Use
|
||||
somewhere inside such a block. Jumps are only legal to containing blocks. Use
|
||||
named blocks with restraint; jumps to places far away can get confusing.
|
||||
|
||||
There are two unconditional jumps:
|
||||
|
||||
loop
|
||||
loop label
|
||||
# unconditional break instructions don't seem useful
|
||||
break
|
||||
break label
|
||||
|
||||
The remaining jump instructions are all conditional. Conditional jumps rely on
|
||||
the result of the most recently executed `compare` instruction. (To keep
|
||||
|
|
Loading…
Reference in New Issue