about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2020-09-30 23:46:43 -0700
committerKartik Agaram <vc@akkartik.com>2020-09-30 23:46:43 -0700
commit8d32a9aab9915d78e63d316fcb74fa1afa404798 (patch)
treedac822434e46a849637ab7b85ddc017c91250f90
parentbc3ebe820bee2450d2c902ea1aefeb03ff89234c (diff)
downloadmu-8d32a9aab9915d78e63d316fcb74fa1afa404798.tar.gz
6915 - a new family of Mu branch instructions
The realization of commit 6916 means that we should be using jump-if-addr*
after comparing floats. Which is super ugly. Let's create aliases to them
called jump-if-float*.
-rw-r--r--apps/mu.subx419
-rw-r--r--mu.md9
-rw-r--r--mu_instructions6
3 files changed, 432 insertions, 2 deletions
diff --git a/apps/mu.subx b/apps/mu.subx
index 7d5a8881..590fa595 100644
--- a/apps/mu.subx
+++ b/apps/mu.subx
@@ -3177,6 +3177,65 @@ test-convert-function-with-branches-in-block:
     5d/pop-to-ebp
     c3/return
 
+test-convert-function-with-branches-in-block-2:
+    # . 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)
+    #
+    (write _test-input-stream "fn foo x: int {\n")
+    (write _test-input-stream "  {\n")
+    (write _test-input-stream "    break-if->=\n")
+    (write _test-input-stream "    loop-if-float<\n")
+    (write _test-input-stream "    increment x\n")
+    (write _test-input-stream "    loop\n")
+    (write _test-input-stream "  }\n")
+    (write _test-input-stream "}\n")
+    # convert
+    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
+    (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-branches-in-block/0")
+    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-block/1")
+    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-block/2")
+    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-block/3")
+    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-block/4")
+    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-block/5")
+    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-block/6")
+    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-in-block/7")
+    (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/8")
+    (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-block/9")
+    (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-in-block/10")
+    (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/11")
+    (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/12")
+    (check-next-stream-line-equal _test-output-stream "        0f 83/jump-if-addr>= break/disp32"  "F - test-convert-function-with-branches-in-block/13")
+    (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:loop/disp32"  "F - test-convert-function-with-branches-in-block/14")
+    (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/15")
+    (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-block/16")
+    (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-in-block/17")
+    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-block/18")
+    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-in-block/19")
+    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-block/20")
+    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-block/21")
+    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-block/22")
+    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-block/23")
+    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-block/24")
+    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-block/25")
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
 test-convert-function-with-branches-in-named-block:
     # . prologue
     55/push-ebp
@@ -15616,9 +15675,9 @@ $emit-reverse-break:end:
 # Table from Mu branch instructions to the reverse SubX opcodes for them.
 Reverse-branch:  # (table (handle array byte) (handle array byte))
   # a table is a stream
-  0x140/imm32/write
+  0x1c0/imm32/write
   0/imm32/read
-  0x140/imm32/size
+  0x1c0/imm32/size
   # data
   0x11/imm32/alloc-id   _string-break-if-=/imm32                0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
   0x11/imm32/alloc-id   _string-loop-if-=/imm32                 0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
@@ -15640,6 +15699,14 @@ Reverse-branch:  # (table (handle array byte) (handle array byte))
   0x11/imm32/alloc-id   _string-loop-if-addr<=/imm32            0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
   0x11/imm32/alloc-id   _string-break-if-addr>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
   0x11/imm32/alloc-id   _string-loop-if-addr>=/imm32            0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
+  0x11/imm32/alloc-id   _string-break-if-float</imm32           0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
+  0x11/imm32/alloc-id   _string-loop-if-float</imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
+  0x11/imm32/alloc-id   _string-break-if-float>/imm32           0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
+  0x11/imm32/alloc-id   _string-loop-if-float>/imm32            0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
+  0x11/imm32/alloc-id   _string-break-if-float<=/imm32          0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
+  0x11/imm32/alloc-id   _string-loop-if-float<=/imm32           0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
+  0x11/imm32/alloc-id   _string-break-if-float>=/imm32          0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
+  0x11/imm32/alloc-id   _string-loop-if-float>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
 
 == code
 
@@ -20933,6 +21000,311 @@ _Primitive-loop-named:  # (payload primitive)
     1/imm32/disp32-is-first-inout
     0/imm32/no-xm32
     0/imm32/no-x32
+    0x11/imm32/alloc-id:fake
+    _Primitive-break-if-float</imm32/next
+# - branches based on floating-point comparisons
+_Primitive-break-if-float<:  # (payload primitive)
+    0x11/imm32/alloc-id:fake:payload
+    0x11/imm32/alloc-id:fake
+    _string-break-if-float</imm32/name
+    0/imm32/no-inouts
+    0/imm32/no-inouts
+    0/imm32/no-outputs
+    0/imm32/no-outputs
+    0x11/imm32/alloc-id:fake
+    _string_0f_82_jump_break/imm32/subx-name
+    0/imm32/no-rm32
+    0/imm32/no-r32
+    0/imm32/no-imm32
+    0/imm32/no-imm8
+    0/imm32/no-disp32
+    0/imm32/no-xm32
+    0/imm32/no-x32
+    0x11/imm32/alloc-id:fake
+    _Primitive-break-if-float>=/imm32/next
+_Primitive-break-if-float>=:  # (payload primitive)
+    0x11/imm32/alloc-id:fake:payload
+    0x11/imm32/alloc-id:fake
+    _string-break-if-float>=/imm32/name
+    0/imm32/no-inouts
+    0/imm32/no-inouts
+    0/imm32/no-outputs
+    0/imm32/no-outputs
+    0x11/imm32/alloc-id:fake
+    _string_0f_83_jump_break/imm32/subx-name
+    0/imm32/no-rm32
+    0/imm32/no-r32
+    0/imm32/no-imm32
+    0/imm32/no-imm8
+    0/imm32/no-disp32
+    0/imm32/no-xm32
+    0/imm32/no-x32
+    0x11/imm32/alloc-id:fake
+    _Primitive-break-if-float<=/imm32/next
+_Primitive-break-if-float<=:  # (payload primitive)
+    0x11/imm32/alloc-id:fake:payload
+    0x11/imm32/alloc-id:fake
+    _string-break-if-float<=/imm32/name
+    0/imm32/no-inouts
+    0/imm32/no-inouts
+    0/imm32/no-outputs
+    0/imm32/no-outputs
+    0x11/imm32/alloc-id:fake
+    _string_0f_86_jump_break/imm32/subx-name
+    0/imm32/no-rm32
+    0/imm32/no-r32
+    0/imm32/no-imm32
+    0/imm32/no-imm8
+    0/imm32/no-disp32
+    0/imm32/no-xm32
+    0/imm32/no-x32
+    0x11/imm32/alloc-id:fake
+    _Primitive-break-if-float>/imm32/next
+_Primitive-break-if-float>:  # (payload primitive)
+    0x11/imm32/alloc-id:fake:payload
+    0x11/imm32/alloc-id:fake
+    _string-break-if-float>/imm32/name
+    0/imm32/no-inouts
+    0/imm32/no-inouts
+    0/imm32/no-outputs
+    0/imm32/no-outputs
+    0x11/imm32/alloc-id:fake
+    _string_0f_87_jump_break/imm32/subx-name
+    0/imm32/no-rm32
+    0/imm32/no-r32
+    0/imm32/no-imm32
+    0/imm32/no-imm8
+    0/imm32/no-disp32
+    0/imm32/no-xm32
+    0/imm32/no-x32
+    0x11/imm32/alloc-id:fake
+    _Primitive-loop-if-float</imm32/next
+_Primitive-loop-if-float<:  # (payload primitive)
+    0x11/imm32/alloc-id:fake:payload
+    0x11/imm32/alloc-id:fake
+    _string-loop-if-float</imm32/name
+    0/imm32/no-inouts
+    0/imm32/no-inouts
+    0/imm32/no-outputs
+    0/imm32/no-outputs
+    0x11/imm32/alloc-id:fake
+    _string_0f_82_jump_loop/imm32/subx-name
+    0/imm32/no-rm32
+    0/imm32/no-r32
+    0/imm32/no-imm32
+    0/imm32/no-imm8
+    0/imm32/no-disp32
+    0/imm32/no-xm32
+    0/imm32/no-x32
+    0x11/imm32/alloc-id:fake
+    _Primitive-loop-if-float>=/imm32/next
+_Primitive-loop-if-float>=:  # (payload primitive)
+    0x11/imm32/alloc-id:fake:payload
+    0x11/imm32/alloc-id:fake
+    _string-loop-if-float>=/imm32/name
+    0/imm32/no-inouts
+    0/imm32/no-inouts
+    0/imm32/no-outputs
+    0/imm32/no-outputs
+    0x11/imm32/alloc-id:fake
+    _string_0f_83_jump_loop/imm32/subx-name
+    0/imm32/no-rm32
+    0/imm32/no-r32
+    0/imm32/no-imm32
+    0/imm32/no-imm8
+    0/imm32/no-disp32
+    0/imm32/no-xm32
+    0/imm32/no-x32
+    0x11/imm32/alloc-id:fake
+    _Primitive-loop-if-float<=/imm32/next
+_Primitive-loop-if-float<=:  # (payload primitive)
+    0x11/imm32/alloc-id:fake:payload
+    0x11/imm32/alloc-id:fake
+    _string-loop-if-float<=/imm32/name
+    0/imm32/no-inouts
+    0/imm32/no-inouts
+    0/imm32/no-outputs
+    0/imm32/no-outputs
+    0x11/imm32/alloc-id:fake
+    _string_0f_86_jump_loop/imm32/subx-name
+    0/imm32/no-rm32
+    0/imm32/no-r32
+    0/imm32/no-imm32
+    0/imm32/no-imm8
+    0/imm32/no-disp32
+    0/imm32/no-xm32
+    0/imm32/no-x32
+    0x11/imm32/alloc-id:fake
+    _Primitive-loop-if-float>/imm32/next
+_Primitive-loop-if-float>:  # (payload primitive)
+    0x11/imm32/alloc-id:fake:payload
+    0x11/imm32/alloc-id:fake
+    _string-loop-if-float>/imm32/name
+    0/imm32/no-inouts
+    0/imm32/no-inouts
+    0/imm32/no-outputs
+    0/imm32/no-outputs
+    0x11/imm32/alloc-id:fake
+    _string_0f_87_jump_loop/imm32/subx-name
+    0/imm32/no-rm32
+    0/imm32/no-r32
+    0/imm32/no-imm32
+    0/imm32/no-imm8
+    0/imm32/no-disp32
+    0/imm32/no-xm32
+    0/imm32/no-x32
+    0x11/imm32/alloc-id:fake
+    _Primitive-break-if-float<-named/imm32/next
+_Primitive-break-if-float<-named:  # (payload primitive)
+    0x11/imm32/alloc-id:fake:payload
+    0x11/imm32/alloc-id:fake
+    _string-break-if-float</imm32/name
+    0x11/imm32/alloc-id:fake
+    Single-lit-var/imm32/inouts
+    0/imm32/no-outputs
+    0/imm32/no-outputs
+    0x11/imm32/alloc-id:fake
+    _string_0f_82_jump_label/imm32/subx-name
+    0/imm32/no-rm32
+    0/imm32/no-r32
+    0/imm32/no-imm32
+    0/imm32/no-imm8
+    1/imm32/disp32-is-first-inout
+    0/imm32/no-xm32
+    0/imm32/no-x32
+    0x11/imm32/alloc-id:fake
+    _Primitive-break-if-float>=-named/imm32/next
+_Primitive-break-if-float>=-named:  # (payload primitive)
+    0x11/imm32/alloc-id:fake:payload
+    0x11/imm32/alloc-id:fake
+    _string-break-if-float>=/imm32/name
+    0x11/imm32/alloc-id:fake
+    Single-lit-var/imm32/inouts
+    0/imm32/no-outputs
+    0/imm32/no-outputs
+    0x11/imm32/alloc-id:fake
+    _string_0f_83_jump_label/imm32/subx-name
+    0/imm32/no-rm32
+    0/imm32/no-r32
+    0/imm32/no-imm32
+    0/imm32/no-imm8
+    1/imm32/disp32-is-first-inout
+    0/imm32/no-xm32
+    0/imm32/no-x32
+    0x11/imm32/alloc-id:fake
+    _Primitive-break-if-float<=-named/imm32/next
+_Primitive-break-if-float<=-named:  # (payload primitive)
+    0x11/imm32/alloc-id:fake:payload
+    0x11/imm32/alloc-id:fake
+    _string-break-if-float<=/imm32/name
+    0x11/imm32/alloc-id:fake
+    Single-lit-var/imm32/inouts
+    0/imm32/no-outputs
+    0/imm32/no-outputs
+    0x11/imm32/alloc-id:fake
+    _string_0f_86_jump_label/imm32/subx-name
+    0/imm32/no-rm32
+    0/imm32/no-r32
+    0/imm32/no-imm32
+    0/imm32/no-imm8
+    1/imm32/disp32-is-first-inout
+    0/imm32/no-xm32
+    0/imm32/no-x32
+    0x11/imm32/alloc-id:fake
+    _Primitive-break-if-float>-named/imm32/next
+_Primitive-break-if-float>-named:  # (payload primitive)
+    0x11/imm32/alloc-id:fake:payload
+    0x11/imm32/alloc-id:fake
+    _string-break-if-float>/imm32/name
+    0x11/imm32/alloc-id:fake
+    Single-lit-var/imm32/inouts
+    0/imm32/no-outputs
+    0/imm32/no-outputs
+    0x11/imm32/alloc-id:fake
+    _string_0f_87_jump_label/imm32/subx-name
+    0/imm32/no-rm32
+    0/imm32/no-r32
+    0/imm32/no-imm32
+    0/imm32/no-imm8
+    1/imm32/disp32-is-first-inout
+    0/imm32/no-xm32
+    0/imm32/no-x32
+    0x11/imm32/alloc-id:fake
+    _Primitive-loop-if-float<-named/imm32/next
+_Primitive-loop-if-float<-named:  # (payload primitive)
+    0x11/imm32/alloc-id:fake:payload
+    0x11/imm32/alloc-id:fake
+    _string-loop-if-float</imm32/name
+    0x11/imm32/alloc-id:fake
+    Single-lit-var/imm32/inouts
+    0/imm32/no-outputs
+    0/imm32/no-outputs
+    0x11/imm32/alloc-id:fake
+    _string_0f_82_jump_label/imm32/subx-name
+    0/imm32/no-rm32
+    0/imm32/no-r32
+    0/imm32/no-imm32
+    0/imm32/no-imm8
+    1/imm32/disp32-is-first-inout
+    0/imm32/no-xm32
+    0/imm32/no-x32
+    0x11/imm32/alloc-id:fake
+    _Primitive-loop-if-float>=-named/imm32/next
+_Primitive-loop-if-float>=-named:  # (payload primitive)
+    0x11/imm32/alloc-id:fake:payload
+    0x11/imm32/alloc-id:fake
+    _string-loop-if-float>=/imm32/name
+    0x11/imm32/alloc-id:fake
+    Single-lit-var/imm32/inouts
+    0/imm32/no-outputs
+    0/imm32/no-outputs
+    0x11/imm32/alloc-id:fake
+    _string_0f_83_jump_label/imm32/subx-name
+    0/imm32/no-rm32
+    0/imm32/no-r32
+    0/imm32/no-imm32
+    0/imm32/no-imm8
+    1/imm32/disp32-is-first-inout
+    0/imm32/no-xm32
+    0/imm32/no-x32
+    0x11/imm32/alloc-id:fake
+    _Primitive-loop-if-float<=-named/imm32/next
+_Primitive-loop-if-float<=-named:  # (payload primitive)
+    0x11/imm32/alloc-id:fake:payload
+    0x11/imm32/alloc-id:fake
+    _string-loop-if-float<=/imm32/name
+    0x11/imm32/alloc-id:fake
+    Single-lit-var/imm32/inouts
+    0/imm32/no-outputs
+    0/imm32/no-outputs
+    0x11/imm32/alloc-id:fake
+    _string_0f_86_jump_label/imm32/subx-name
+    0/imm32/no-rm32
+    0/imm32/no-r32
+    0/imm32/no-imm32
+    0/imm32/no-imm8
+    1/imm32/disp32-is-first-inout
+    0/imm32/no-xm32
+    0/imm32/no-x32
+    0x11/imm32/alloc-id:fake
+    _Primitive-loop-if-float>-named/imm32/next
+_Primitive-loop-if-float>-named:  # (payload primitive)
+    0x11/imm32/alloc-id:fake:payload
+    0x11/imm32/alloc-id:fake
+    _string-loop-if-float>/imm32/name
+    0x11/imm32/alloc-id:fake
+    Single-lit-var/imm32/inouts
+    0/imm32/no-outputs
+    0/imm32/no-outputs
+    0x11/imm32/alloc-id:fake
+    _string_0f_87_jump_label/imm32/subx-name
+    0/imm32/no-rm32
+    0/imm32/no-r32
+    0/imm32/no-imm32
+    0/imm32/no-imm8
+    1/imm32/disp32-is-first-inout
+    0/imm32/no-xm32
+    0/imm32/no-x32
     0/imm32/next
     0/imm32/next
 
@@ -21017,6 +21389,26 @@ _string-break-if-addr>=:  # (payload array byte)
     # "break-if-addr>="
     0xf/imm32/size
     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x3d/=
+_string-break-if-float<:  # (payload array byte)
+    0x11/imm32/alloc-id:fake:payload
+    # "break-if-float<"
+    0xf/imm32/size
+    0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3c/<
+_string-break-if-float<=:  # (payload array byte)
+    0x11/imm32/alloc-id:fake:payload
+    # "break-if-float<="
+    0x10/imm32/size
+    0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3c/< 0x3d/=
+_string-break-if-float>:  # (payload array byte)
+    0x11/imm32/alloc-id:fake:payload
+    # "break-if-float>"
+    0xf/imm32/size
+    0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3e/>
+_string-break-if-float>=:  # (payload array byte)
+    0x11/imm32/alloc-id:fake:payload
+    # "break-if-float>="
+    0x10/imm32/size
+    0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3e/> 0x3d/=
 _string-compare:  # (payload array byte)
     0x11/imm32/alloc-id:fake:payload
     # "compare"
@@ -21107,6 +21499,26 @@ _string-loop-if-addr>=:  # (payload array byte)
     # "loop-if-addr>="
     0xe/imm32/size
     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x3d/=
+_string-loop-if-float<:  # (payload array byte)
+    0x11/imm32/alloc-id:fake:payload
+    # "loop-if-float<"
+    0xe/imm32/size
+    0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3c/<
+_string-loop-if-float<=:  # (payload array byte)
+    0x11/imm32/alloc-id:fake:payload
+    # "loop-if-float<="
+    0xf/imm32/size
+    0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3c/< 0x3d/=
+_string-loop-if-float>:  # (payload array byte)
+    0x11/imm32/alloc-id:fake:payload
+    # "loop-if-float>"
+    0xe/imm32/size
+    0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3e/>
+_string-loop-if-float>=:  # (payload array byte)
+    0x11/imm32/alloc-id:fake:payload
+    # "loop-if-float>="
+    0xf/imm32/size
+    0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3e/> 0x3d/=
 _string-multiply:  # (payload array byte)
     0x11/imm32/alloc-id:fake:payload
     # "multiply"
@@ -22748,6 +23160,9 @@ $mu-stmt-matches-primitive?:check-name:
       89/<- %esi 0/r32/eax
       # . var edi: (addr array byte) = lookup(primitive->name)
       (lookup *edx *(edx+4))  # Primitive-name Primitive-name => eax
+#?       (write-buffered Stderr %eax)
+#?       (write-buffered Stderr Newline)
+#?       (flush Stderr)
       89/<- %edi 0/r32/eax
       (string-equal? %esi %edi)  # => eax
       3d/compare-eax-and 0/imm32/false
diff --git a/mu.md b/mu.md
index 9ed2f693..a3271631 100644
--- a/mu.md
+++ b/mu.md
@@ -371,6 +371,15 @@ break-if-addr<=
 break-if-addr<= label
 break-if-addr>=
 break-if-addr>= label
+
+break-if-float<
+break-if-float< label
+break-if-float>
+break-if-float> label
+break-if-float<=
+break-if-float<= label
+break-if-float>=
+break-if-float>= label
 ```
 
 Similarly, conditional loops:
diff --git a/mu_instructions b/mu_instructions
index 2013c764..27fe295c 100644
--- a/mu_instructions
+++ b/mu_instructions
@@ -177,6 +177,12 @@ break-if-addr>= label             => "0f 83/jump-if-addr>= " label ":break/disp3
 loop-if-addr>=                    => "0f 83/jump-if-addr>= loop/disp32"
 loop-if-addr>= label              => "0f 83/jump-if-addr>= " label ":loop/disp32"
 
+Similar float variants like `break-if-loop<` are aliases for the corresponding
+`addr` equivalents. The x86 instruction set stupidly has floating-point
+operations only update a subset of flags.
+
+---
+
 In the following instructions types are provided for clarity even if they must
 be provided in an earlier 'var' declaration.