https://github.com/akkartik/mu/blob/master/apps/mu.subx
    1 # The Mu computer's level-2 language, also called Mu.
    2 # http://akkartik.name/post/mu-2019-2
    3 #
    4 # To run:
    5 #   $ ./translate_subx init.linux [0-9]*.subx apps/mu.subx
    6 
    7 # == Goals
    8 # 1. Be memory safe. It should be impossible to corrupt the heap, or to create
    9 # a bad pointer. (Requires strong type safety.)
   10 # 2. Do as little as possible to achieve goal 1. The translator should be
   11 # implementable in machine code.
   12 #   - minimize impedance mismatch between source language and SubX target
   13 #     (e.g. programmer manages registers manually)
   14 #   - checks over syntax
   15 #     (e.g. programmer's register allocation is checked)
   16 #   - runtime checks to avoid complex static analysis
   17 #     (e.g. array indexing always checks bounds)
   18 
   19 # == Language description
   20 # A program is a sequence of function and type definitions.
   21 #
   22 # Function example:
   23 #   fn foo n: int -> result/eax: int {
   24 #     ...
   25 #   }
   26 #
   27 # Functions consist of a name, optional inputs, optional outputs and a block.
   28 #
   29 # Function inputs and outputs are variables. All variables have a type and
   30 # storage specifier. They can be placed either in memory (on the stack) or in
   31 # one of 6 named registers.
   32 #   eax ecx edx ebx esi edi
   33 # Variables in registers must be primitive 32-bit types.
   34 # Variables not explicitly placed in a register are on the stack.
   35 #
   36 # Function inputs are always passed in memory (on the stack), while outputs
   37 # are always returned in registers.
   38 #
   39 # Blocks mostly consist of statements.
   40 #
   41 # Statements mostly consist of a name, optional inputs and optional outputs.
   42 #
   43 # Statement inputs are variables or literals. Variables need to specify type
   44 # (and storage) the first time they're mentioned but not later.
   45 #
   46 # Statement outputs, like function outputs, must be variables in registers.
   47 #
   48 # Statement names must be either primitives or user-defined functions.
   49 #
   50 # Primitives can write to any register.
   51 # User-defined functions only write to hard-coded registers. Outputs of each
   52 # call must have the same registers as in the function definition.
   53 #
   54 # There are some other statement types:
   55 #   - blocks. Multiple statements surrounded by '{...}' and optionally
   56 #     prefixed with a label name and ':'
   57 #       - {
   58 #           ...
   59 #         }
   60 #       - foo: {
   61 #           ...
   62 #         }
   63 #
   64 #   - variable definitions on the stack. E.g.:
   65 #       - var foo: int
   66 #       - var bar: (array int 3)
   67 #     There's no initializer; variables are automatically initialized.
   68 #     The type of a local variable is either word-length (4 bytes) or starts with 'ref'.
   69 #
   70 #   - variables definitions in a register. E.g.:
   71 #       - var foo/eax: int <- add bar 1
   72 #     The initializer is mandatory and must be a valid instruction that writes
   73 #     a single output to the right register. In practice registers will
   74 #     usually be either initialized by primitives or copied from eax.
   75 #       - var eax: int <- foo bar quux
   76 #         var floo/ecx: int <- copy eax
   77 #
   78 # Still todo:
   79 #   global variables
   80 #   heap allocations (planned name: 'handle')
   81 #   user-defined types: 'type' for structs, 'choice' for unions
   82 #   short-lived 'address' type for efficiently writing inside nested structs
   83 #
   84 # We don't have 'handle' types yet, but we try to distinguish 'ref', 'handle'
   85 # and 'address' in comments. Their definitions are in layer 50, but really you
   86 # can ignore the distinctions on a first reading of this program.
   87 #
   88 # Formal types:
   89 #   A program is a linked list of functions
   90 #   A function contains:
   91 #     name: (handle array byte)
   92 #     inouts: linked list of vars  <-- 'inouts' is more precise than 'inputs'
   93 #       data: (handle var)
   94 #       next: (handle list)
   95 #     outputs: linked list of vars
   96 #       data: (handle var)
   97 #       next: (handle list)
   98 #     body: (handle block)
   99 #   A var-type contains:
  100 #     name: (handle array byte)
  101 #     type: (handle tree type-id)
  102 #
  103 #   A statement can be:
  104 #     tag 0: a block
  105 #     tag 1: a simple statement (stmt1)
  106 #     tag 2: a variable defined on the stack
  107 #     tag 3: a variable defined in a register
  108 #
  109 #   A block contains:
  110 #     tag: 0
  111 #     statements: (handle list stmt)
  112 #     name: (handle array byte) -- starting with '$'
  113 #
  114 #   A regular statement contains:
  115 #     tag: 1
  116 #     operation: (handle array byte)
  117 #     inouts: (handle list operand)
  118 #     outputs: (handle list var)
  119 #
  120 #   A variable defined on the stack contains:
  121 #     tag: 2
  122 #     name: (handle array byte)
  123 #     type: (handle tree type-id)
  124 #
  125 #   A variable defined in a register contains:
  126 #     tag: 3
  127 #     name: (handle array byte)
  128 #     type: (handle tree type-id)
  129 #     reg: (handle array byte)
  130 
  131 # == Translation: managing the stack
  132 # Now that we know what the language looks like in the large, let's think
  133 # about how translation happens from the bottom up. One crucial piece of the
  134 # puzzle is how Mu will clean up variables defined on the stack for you.
  135 #
  136 # Assume that we maintain a 'functions' list while parsing source code. And a
  137 # 'primitives' list is a global constant. Both these contain enough information
  138 # to perform type-checking on function calls or primitive statements, respectively.
  139 #
  140 # Defining variables pushes them on a stack with the current block depth and
  141 # enough information about their location (stack offset or register).
  142 # Starting a block increments the current block id.
  143 # Each statement now has enough information to emit code for it.
  144 # Ending a block is where the magic happens:
  145 #   pop all variables at the current block depth
  146 #   emit code to restore all register variables introduced at the current depth
  147 #   emit code to clean up all stack variables at the current depth (just increment esp)
  148 #   decrement the current block depth
  149 #
  150 # Formal types:
  151 #   live-vars: stack of vars
  152 #   var:
  153 #     name: (handle array byte)
  154 #     type: (handle tree type-id)
  155 #     block: int
  156 #     stack-offset: int  (added to ebp)
  157 #     register: (handle array byte)
  158 #       either usual register names
  159 #       or '*' to indicate any register
  160 #   At most one of stack-offset or register-index must be non-zero.
  161 #   A register of '*' designates a variable _template_. Only legal in formal
  162 #   parameters for primitives.
  163 
  164 # == Translating a single function call
  165 # This one's easy. Assuming we've already checked things, we just drop the
  166 # outputs (which use hard-coded registers) and emit inputs in a standard format.
  167 #
  168 # out1, out2, out3, ... <- name inout1, inout2, inout3, ...
  169 # =>
  170 # (subx-name inout1 inout2 inout3)
  171 #
  172 # Formal types:
  173 #   functions: linked list of info
  174 #     name: (handle array byte)
  175 #     inouts: linked list of vars
  176 #     outputs: linked list of vars
  177 #     body: block (singleton linked list)
  178 #     subx-name: (handle array byte)
  179 
  180 # == Translating a single primitive instruction
  181 # A second crucial piece of the puzzle is how Mu converts fairly regular
  182 # primitives with their uniform syntax to SubX instructions with their gnarly
  183 # x86 details.
  184 #
  185 # Mu instructions have inputs and outputs. Primitives can have up to 2 of
  186 # them.
  187 # SubX instructions have rm32 and r32 operands.
  188 # The translation between them covers almost all the possibilities.
  189 #   Instructions with 1 inout may turn into ones with 1 rm32
  190 #     (e.g. incrementing a var on the stack)
  191 #   Instructions with 1 output may turn into ones with 1 rm32
  192 #     (e.g. incrementing a var in a register)
  193 #   1 inout and 1 output may turn into 1 rm32 and 1 r32
  194 #     (e.g. adding a var to a reg)
  195 #   2 inouts may turn into 1 rm32 and 1 r32
  196 #     (e.g. adding a reg to a var)
  197 #   1 inout and 1 literal may turn into 1 rm32 and 1 imm32
  198 #     (e.g. adding a constant to a var)
  199 #   1 output and 1 literal may turn into 1 rm32 and 1 imm32
  200 #     (e.g. adding a constant to a reg)
  201 #   2 outputs to hardcoded registers and 1 inout may turn into 1 rm32
  202 #     (special-case: divide edx:eax by a var or reg)
  203 # Observations:
  204 #   We always emit rm32. It may be the first inout or the first output.
  205 #   We may emit r32 or imm32 or neither.
  206 #   When we emit r32 it may come from first inout or second inout or first output.
  207 #
  208 # Accordingly, the formal data structure for a primitive looks like this:
  209 #   primitives: linked list of info
  210 #     name: (handle array byte)
  211 #     mu-inouts: linked list of vars to check
  212 #     mu-outputs: linked list of vars to check; at most a singleton
  213 #     subx-name: (handle array byte)
  214 #     subx-rm32: enum arg-location
  215 #     subx-r32: enum arg-location
  216 #     subx-imm32: enum arg-location
  217 #     subx-disp32: enum arg-location
  218 #     output-is-write-only: boolean
  219 #   arg-location: enum
  220 #     0 means none
  221 #     1 means first inout
  222 #     2 means second inout
  223 #     3 means first output
  224 
  225 # == Translating a block
  226 # Emit block name if necessary
  227 # Emit '{'
  228 # When you encounter a statement, emit it as above
  229 # When you encounter a variable declaration
  230 #   emit any code needed for it (bzeros)
  231 #   push it on the var stack
  232 #   update register dict if necessary
  233 # When you encounter '}'
  234 #   While popping variables off the var stack until block id changes
  235 #     Emit code needed to clean up the stack
  236 #       either increment esp
  237 #       or pop into appropriate register
  238 
  239 # The rest is straightforward.
  240 
  241 == data
  242 
  243 Program:
  244 _Program-functions:  # (handle function)
  245   0/imm32
  246 _Program-functions->payload:
  247   0/imm32
  248 _Program-types:  # (handle typeinfo)
  249   0/imm32
  250 _Program-types->payload:
  251   0/imm32
  252 
  253 # Some constants for simulating the data structures described above.
  254 # Many constants here come with a type in a comment.
  255 #
  256 # Sometimes the type is of the value at that offset for the given type. For
  257 # example, if you start at a function record and move forward Function-inouts
  258 # bytes, you'll find a (handle list var).
  259 #
  260 # At other times, the type is of the constant itself. For example, the type of
  261 # the constant Function-size is (addr int). To get the size of a function,
  262 # look in *Function-size.
  263 
  264 Function-name:  # (handle array byte)
  265   0/imm32
  266 Function-inouts:  # (handle list var)
  267   8/imm32
  268 Function-outputs:  # (handle list var)
  269   0x10/imm32
  270 Function-body:  # (handle block)
  271   0x18/imm32
  272 Function-next:  # (handle function)
  273   0x20/imm32
  274 Function-size:  # (addr int)
  275   0x28/imm32/40
  276 
  277 Primitive-name:  # (handle array byte)
  278   0/imm32
  279 Primitive-inouts:  # (handle list var)
  280   8/imm32
  281 Primitive-outputs:  # (handle list var)
  282   0x10/imm32
  283 Primitive-subx-name:  # (handle array byte)
  284   0x18/imm32
  285 Primitive-subx-rm32:  # enum arg-location
  286   0x20/imm32
  287 Primitive-subx-r32:  # enum arg-location
  288   0x24/imm32
  289 Primitive-subx-imm32:  # enum arg-location
  290   0x28/imm32
  291 Primitive-subx-disp32:  # enum arg-location  -- only for branches
  292   0x2c/imm32
  293 Primitive-output-is-write-only:  # boolean
  294   0x30/imm32
  295 Primitive-next:  # (handle function)
  296   0x34/imm32
  297 Primitive-size:  # (addr int)
  298   0x3c/imm32/60
  299 
  300 Stmt-tag:  # int
  301   0/imm32
  302 
  303 Block-stmts:  # (handle list stmt)
  304   4/imm32
  305 Block-var:  # (handle var)
  306   0xc/imm32
  307 
  308 Stmt1-operation:  # (handle array byte)
  309   4/imm32
  310 Stmt1-inouts:  # (handle stmt-var)
  311   0xc/imm32
  312 Stmt1-outputs:  # (handle stmt-var)
  313   0x14/imm32
  314 
  315 Vardef-var:  # (handle var)
  316   4/imm32
  317 
  318 Regvardef-operation:  # (handle array byte)
  319   4/imm32
  320 Regvardef-inouts:  # (handle stmt-var)
  321   0xc/imm32
  322 Regvardef-outputs:  # (handle stmt-var)  # will have exactly one element
  323   0x14/imm32
  324 
  325 Stmt-size:  # (addr int)
  326   0x1c/imm32
  327 
  328 Var-name:  # (handle array byte)
  329   0/imm32
  330 Var-type:  # (handle tree type-id)
  331   8/imm32
  332 Var-block-depth:  # int -- not available until code-generation time
  333   0x10/imm32
  334 Var-offset:  # int -- not available until code-generation time
  335   0x14/imm32
  336 Var-register:  # (handle array byte) -- name of a register
  337   0x18/imm32
  338 Var-size:  # (addr int)
  339   0x20/imm32
  340 
  341 List-value:  # (handle _)
  342   0/imm32
  343 List-next:  # (handle list _)
  344   8/imm32
  345 List-size:  # (addr int)
  346   0x10/imm32
  347 
  348 # A stmt-var is like a list of vars with call-site specific metadata
  349 Stmt-var-value:  # (handle var)
  350   0/imm32
  351 Stmt-var-next:  # (handle stmt-var)
  352   8/imm32
  353 Stmt-var-is-deref:  # boolean
  354   0x10/imm32
  355 Stmt-var-size:  # (addr int)
  356   0x14/imm32
  357 
  358 # Types are expressed as trees (s-expressions) of type-ids (ints).
  359 # However, there's no need for singletons, so we can assume (int) == int
  360 #   - if x->right == nil, x is an atom
  361 #   - x->left contains either a pointer to a pair, or an atomic type-id directly.
  362 
  363 Tree-is-atom:  # boolean
  364   0/imm32
  365 # if left-is-atom?
  366 Tree-value:  # type-id
  367   4/imm32
  368 # unless left-is-atom?
  369 Tree-left:  # (addr tree type-id)
  370   4/imm32
  371 Tree-right:  # (addr tree type-id)
  372   0xc/imm32
  373 #
  374 Tree-size:  # (addr int)
  375   0x14/imm32
  376 
  377 # Types
  378 
  379 # TODO: heap allocations here can't be reclaimed
  380 Type-id:  # (stream (addr array byte))
  381   0x1c/imm32/write
  382   0/imm32/read
  383   0x100/imm32/size
  384   # data
  385   "literal"/imm32  # 0: value is just the name
  386   "int"/imm32  # 1
  387   "addr"/imm32  # 2
  388   "array"/imm32  # 3
  389   "handle"/imm32  # 4
  390   "boolean"/imm32  # 5
  391   "constant"/imm32  # 6: like a literal, but value is an int in Var-offset
  392   "offset"/imm32  # 7: (offset T) is guaranteed to be a 32-bit multiple of size-of(T)
  393   0/imm32
  394   # 0x20
  395   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  396   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  397   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  398   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  399   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  400   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  401   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  402 
  403 # == Type definitions
  404 # Program->types contains some typeinfo for each type definition.
  405 # Types contain vars with types, but can't specify registers.
  406 Typeinfo-id:  # type-id
  407   0/imm32
  408 Typeinfo-fields:  # (handle table (handle array byte) (handle typeinfo-entry))
  409   4/imm32
  410 # Total size must be >= 0
  411 # During parsing it may take on two additional values:
  412 #   -2: not yet initialized
  413 #   -1: in process of being computed
  414 # See populate-mu-type-sizes for details.
  415 Typeinfo-total-size-in-bytes:  # int
  416   0xc/imm32
  417 Typeinfo-next:  # (handle typeinfo)
  418   0x10/imm32
  419 Typeinfo-size:  # (addr int)
  420   0x18/imm32
  421 
  422 # Each entry in the typeinfo->fields table has a pointer to a string and a
  423 # pointer to a typeinfo-entry.
  424 Typeinfo-fields-row-size:  # (addr int)
  425   0x10/imm32
  426 
  427 # typeinfo-entry objects have information about a field in a single record type
  428 #
  429 # each field of a type is represented using two var's:
  430 #   1. the input var: expected type of the field; convenient for creating using parse-var-with-type
  431 #   2. the output var: a constant containing the byte offset; convenient for code-generation
  432 # computing the output happens after parsing; in the meantime we preserve the
  433 # order of fields in the 'index' field.
  434 Typeinfo-entry-input-var:  # (handle var)
  435   0/imm32
  436 Typeinfo-entry-index:  # int
  437   8/imm32
  438 Typeinfo-entry-output-var:  # (handle var)
  439   0xc/imm32
  440 Typeinfo-entry-size:  # (addr int)
  441   0x14/imm32
  442 
  443 == code
  444 
  445 Entry:
  446     # . prologue
  447     89/<- %ebp 4/r32/esp
  448     (new-segment *Heap-size Heap)
  449     # if (argv[1] == "test') run-tests()
  450     {
  451       # if (argc <= 1) break
  452       81 7/subop/compare *ebp 1/imm32
  453       7e/jump-if-<= break/disp8
  454       # if (argv[1] != "test") break
  455       (kernel-string-equal? *(ebp+8) "test")  # => eax
  456       3d/compare-eax-and 0/imm32/false
  457       74/jump-if-= break/disp8
  458       #
  459       (run-tests)
  460       # syscall(exit, *Num-test-failures)
  461       8b/-> *Num-test-failures 3/r32/ebx
  462       eb/jump $mu-main:end/disp8
  463     }
  464     # otherwise convert Stdin
  465     (convert-mu Stdin Stdout)
  466     (flush Stdout)
  467     # syscall(exit, 0)
  468     bb/copy-to-ebx 0/imm32
  469 $mu-main:end:
  470     b8/copy-to-eax 1/imm32/exit
  471     cd/syscall 0x80/imm8
  472 
  473 convert-mu:  # in: (addr buffered-file), out: (addr buffered-file)
  474     # . prologue
  475     55/push-ebp
  476     89/<- %ebp 4/r32/esp
  477     # initialize global data structures
  478     c7 0/subop/copy *Next-block-index 1/imm32
  479     c7 0/subop/copy *Type-id 0x1c/imm32  # stream-write
  480     c7 0/subop/copy *_Program-functions 0/imm32
  481     c7 0/subop/copy *_Program-functions->payload 0/imm32
  482     c7 0/subop/copy *_Program-types 0/imm32
  483     c7 0/subop/copy *_Program-types->payload 0/imm32
  484     #
  485     (parse-mu *(ebp+8))
  486     (populate-mu-type-sizes)
  487 #?     (dump-typeinfos "=== typeinfos\n")
  488     (check-mu-types)
  489     (emit-subx *(ebp+0xc))
  490 $convert-mu:end:
  491     # . epilogue
  492     89/<- %esp 5/r32/ebp
  493     5d/pop-to-ebp
  494     c3/return
  495 
  496 test-convert-empty-input:
  497     # empty input => empty output
  498     # . prologue
  499     55/push-ebp
  500     89/<- %ebp 4/r32/esp
  501     # setup
  502     (clear-stream _test-input-stream)
  503     (clear-stream $_test-input-buffered-file->buffer)
  504     (clear-stream _test-output-stream)
  505     (clear-stream $_test-output-buffered-file->buffer)
  506     #
  507     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  508     (flush _test-output-buffered-file)
  509     (check-stream-equal _test-output-stream "" "F - test-convert-empty-input")
  510     # . epilogue
  511     89/<- %esp 5/r32/ebp
  512     5d/pop-to-ebp
  513     c3/return
  514 
  515 test-convert-function-skeleton:
  516     # . prologue
  517     55/push-ebp
  518     89/<- %ebp 4/r32/esp
  519     # setup
  520     (clear-stream _test-input-stream)
  521     (clear-stream $_test-input-buffered-file->buffer)
  522     (clear-stream _test-output-stream)
  523     (clear-stream $_test-output-buffered-file->buffer)
  524     #
  525     (write _test-input-stream "fn foo {\n")
  526     (write _test-input-stream "}\n")
  527     # convert
  528     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  529     (flush _test-output-buffered-file)
  530 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  536     # check output
  537     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-skeleton/0")
  538     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-skeleton/1")
  539     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-skeleton/2")
  540     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-skeleton/3")
  541     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-skeleton/4")
  542     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-skeleton/5")
  543     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-skeleton/6")
  544     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-skeleton/7")
  545     # . epilogue
  546     89/<- %esp 5/r32/ebp
  547     5d/pop-to-ebp
  548     c3/return
  549 
  550 test-convert-multiple-function-skeletons:
  551     # . prologue
  552     55/push-ebp
  553     89/<- %ebp 4/r32/esp
  554     # setup
  555     (clear-stream _test-input-stream)
  556     (clear-stream $_test-input-buffered-file->buffer)
  557     (clear-stream _test-output-stream)
  558     (clear-stream $_test-output-buffered-file->buffer)
  559     #
  560     (write _test-input-stream "fn foo {\n")
  561     (write _test-input-stream "}\n")
  562     (write _test-input-stream "fn bar {\n")
  563     (write _test-input-stream "}\n")
  564     # convert
  565     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  566     (flush _test-output-buffered-file)
  567 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  573     # check first function
  574     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-multiple-function-skeletons/0")
  575     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/1")
  576     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/2")
  577     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/3")
  578     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/4")
  579     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/5")
  580     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/6")
  581     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/7")
  582     # check second function
  583     (check-next-stream-line-equal _test-output-stream "bar:"                    "F - test-convert-multiple-function-skeletons/10")
  584     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/11")
  585     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/12")
  586     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/13")
  587     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/14")
  588     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/15")
  589     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/16")
  590     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/17")
  591     # . epilogue
  592     89/<- %esp 5/r32/ebp
  593     5d/pop-to-ebp
  594     c3/return
  595 
  596 test-convert-function-with-arg:
  597     # . prologue
  598     55/push-ebp
  599     89/<- %ebp 4/r32/esp
  600     # setup
  601     (clear-stream _test-input-stream)
  602     (clear-stream $_test-input-buffered-file->buffer)
  603     (clear-stream _test-output-stream)
  604     (clear-stream $_test-output-buffered-file->buffer)
  605     #
  606     (write _test-input-stream "fn foo n: int {\n")
  607     (write _test-input-stream "}\n")
  608     # convert
  609     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  610     (flush _test-output-buffered-file)
  611 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  617     # check output
  618     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg/0")
  619     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg/1")
  620     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg/2")
  621     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg/3")
  622     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg/4")
  623     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg/5")
  624     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg/6")
  625     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg/7")
  626     # . epilogue
  627     89/<- %esp 5/r32/ebp
  628     5d/pop-to-ebp
  629     c3/return
  630 
  631 test-convert-function-with-arg-and-body:
  632     # . prologue
  633     55/push-ebp
  634     89/<- %ebp 4/r32/esp
  635     # setup
  636     (clear-stream _test-input-stream)
  637     (clear-stream $_test-input-buffered-file->buffer)
  638     (clear-stream _test-output-stream)
  639     (clear-stream $_test-output-buffered-file->buffer)
  640     #
  641     (write _test-input-stream "fn foo n: int {\n")
  642     (write _test-input-stream "  increment n\n")
  643     (write _test-input-stream "}\n")
  644     # convert
  645     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  646     (flush _test-output-buffered-file)
  647 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  653     # check output
  654     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg-and-body/0")
  655     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg-and-body/1")
  656     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg-and-body/2")
  657     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg-and-body/3")
  658     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-arg-and-body/4")
  659     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-arg-and-body/5")
  660     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-arg-and-body/6")
  661     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-arg-and-body/7")
  662     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-arg-and-body/8")
  663     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg-and-body/9")
  664     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg-and-body/10")
  665     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg-and-body/11")
  666     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg-and-body/12")
  667     # . epilogue
  668     89/<- %esp 5/r32/ebp
  669     5d/pop-to-ebp
  670     c3/return
  671 
  672 test-convert-function-distinguishes-args:
  673     # . prologue
  674     55/push-ebp
  675     89/<- %ebp 4/r32/esp
  676     # setup
  677     (clear-stream _test-input-stream)
  678     (clear-stream $_test-input-buffered-file->buffer)
  679     (clear-stream _test-output-stream)
  680     (clear-stream $_test-output-buffered-file->buffer)
  681     #
  682     (write _test-input-stream "fn foo a: int, b: int {\n")
  683     (write _test-input-stream "  increment b\n")
  684     (write _test-input-stream "}\n")
  685     # convert
  686     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  687     (flush _test-output-buffered-file)
  688 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  694     # check output
  695     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-distinguishes-args/0")
  696     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-distinguishes-args/1")
  697     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-distinguishes-args/2")
  698     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-distinguishes-args/3")
  699     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-distinguishes-args/4")
  700     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-distinguishes-args/5")
  701     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x0000000c)"  "F - test-convert-function-distinguishes-args/6")
  702     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-distinguishes-args/7")
  703     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-distinguishes-args/8")
  704     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-distinguishes-args/9")
  705     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-distinguishes-args/10")
  706     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-distinguishes-args/11")
  707     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-distinguishes-args/12")
  708     # . epilogue
  709     89/<- %esp 5/r32/ebp
  710     5d/pop-to-ebp
  711     c3/return
  712 
  713 test-convert-function-returns-result:
  714     # . prologue
  715     55/push-ebp
  716     89/<- %ebp 4/r32/esp
  717     # setup
  718     (clear-stream _test-input-stream)
  719     (clear-stream $_test-input-buffered-file->buffer)
  720     (clear-stream _test-output-stream)
  721     (clear-stream $_test-output-buffered-file->buffer)
  722     #
  723     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  724     (write _test-input-stream "  result <- copy a\n")
  725     (write _test-input-stream "  result <- increment\n")
  726     (write _test-input-stream "}\n")
  727     # convert
  728     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  729     (flush _test-output-buffered-file)
  730 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  736     # check output
  737     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-returns-result/0")
  738     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-returns-result/1")
  739     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-returns-result/2")
  740     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-returns-result/3")
  741     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-returns-result/4")
  742     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-returns-result/5")
  743     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-returns-result/6")
  744     (check-next-stream-line-equal _test-output-stream "    40/increment-eax"    "F - test-convert-function-returns-result/7")
  745     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-returns-result/8")
  746     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-returns-result/9")
  747     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-returns-result/10")
  748     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-returns-result/11")
  749     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-returns-result/12")
  750     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-returns-result/13")
  751     # . epilogue
  752     89/<- %esp 5/r32/ebp
  753     5d/pop-to-ebp
  754     c3/return
  755 
  756 test-convert-function-with-literal-arg:
  757     # . prologue
  758     55/push-ebp
  759     89/<- %ebp 4/r32/esp
  760     # setup
  761     (clear-stream _test-input-stream)
  762     (clear-stream $_test-input-buffered-file->buffer)
  763     (clear-stream _test-output-stream)
  764     (clear-stream $_test-output-buffered-file->buffer)
  765     #
  766     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  767     (write _test-input-stream "  result <- copy a\n")
  768     (write _test-input-stream "  result <- add 1\n")
  769     (write _test-input-stream "}\n")
  770     # convert
  771     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  772     (flush _test-output-buffered-file)
  773 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  779     # check output
  780     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg/0")
  781     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg/1")
  782     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg/2")
  783     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg/3")
  784     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg/4")
  785     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg/5")
  786     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-with-literal-arg/6")
  787     (check-next-stream-line-equal _test-output-stream "    05/add-to-eax 1/imm32"  "F - test-convert-function-with-literal-arg/7")
  788     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg/8")
  789     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg/9")
  790     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg/10")
  791     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg/11")
  792     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg/12")
  793     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg/13")
  794     # . epilogue
  795     89/<- %esp 5/r32/ebp
  796     5d/pop-to-ebp
  797     c3/return
  798 
  799 test-convert-function-with-literal-arg-2:
  800     # . prologue
  801     55/push-ebp
  802     89/<- %ebp 4/r32/esp
  803     # setup
  804     (clear-stream _test-input-stream)
  805     (clear-stream $_test-input-buffered-file->buffer)
  806     (clear-stream _test-output-stream)
  807     (clear-stream $_test-output-buffered-file->buffer)
  808     #
  809     (write _test-input-stream "fn foo a: int, b: int -> result/ebx: int {\n")
  810     (write _test-input-stream "  result <- copy a\n")
  811     (write _test-input-stream "  result <- add 1\n")
  812     (write _test-input-stream "}\n")
  813     # convert
  814     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  815     (flush _test-output-buffered-file)
  816 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  822     # check output
  823     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg-2/0")
  824     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg-2/1")
  825     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg-2/2")
  826     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg-2/3")
  827     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg-2/4")
  828     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg-2/5")
  829     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-with-literal-arg-2/6")
  830     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %ebx 1/imm32"  "F - test-convert-function-with-literal-arg-2/7")
  831     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg-2/8")
  832     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg-2/9")
  833     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg-2/10")
  834     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg-2/11")
  835     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg-2/12")
  836     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg-2/13")
  837     # . epilogue
  838     89/<- %esp 5/r32/ebp
  839     5d/pop-to-ebp
  840     c3/return
  841 
  842 test-convert-function-call-with-literal-arg:
  843     # . prologue
  844     55/push-ebp
  845     89/<- %ebp 4/r32/esp
  846     # setup
  847     (clear-stream _test-input-stream)
  848     (clear-stream $_test-input-buffered-file->buffer)
  849     (clear-stream _test-output-stream)
  850     (clear-stream $_test-output-buffered-file->buffer)
  851     #
  852     (write _test-input-stream "fn main -> result/ebx: int {\n")
  853     (write _test-input-stream "  result <- do-add 3 4\n")
  854     (write _test-input-stream "}\n")
  855     (write _test-input-stream "fn do-add a: int, b: int -> result/ebx: int {\n")
  856     (write _test-input-stream "  result <- copy a\n")
  857     (write _test-input-stream "  result <- add b\n")
  858     (write _test-input-stream "}\n")
  859     # convert
  860     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  861     (flush _test-output-buffered-file)
  862 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  868     # check output
  869     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-literal-arg/0")
  870     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/1")
  871     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/2")
  872     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/3")
  873     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/4")
  874     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-literal-arg/5")
  875     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-literal-arg/6")
  876     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/7")
  877     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-literal-arg/8")
  878     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/9")
  879     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/10")
  880     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/11")
  881     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/12")
  882     (check-next-stream-line-equal _test-output-stream "do-add:"                 "F - test-convert-function-call-with-literal-arg/13")
  883     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/14")
  884     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/15")
  885     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/16")
  886     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/17")
  887     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:loop:"  "F - test-convert-function-call-with-literal-arg/18")
  888     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/19")
  889     (check-next-stream-line-equal _test-output-stream "    03/add *(ebp+0x0000000c) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/20")
  890     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/21")
  891     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:break:"  "F - test-convert-function-call-with-literal-arg/22")
  892     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/23")
  893     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/24")
  894     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/25")
  895     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/26")
  896     # . epilogue
  897     89/<- %esp 5/r32/ebp
  898     5d/pop-to-ebp
  899     c3/return
  900 
  901 test-convert-function-with-local-var-in-mem:
  902     # . prologue
  903     55/push-ebp
  904     89/<- %ebp 4/r32/esp
  905     # setup
  906     (clear-stream _test-input-stream)
  907     (clear-stream $_test-input-buffered-file->buffer)
  908     (clear-stream _test-output-stream)
  909     (clear-stream $_test-output-buffered-file->buffer)
  910     #
  911     (write _test-input-stream "fn foo {\n")
  912     (write _test-input-stream "  var x: int\n")
  913     (write _test-input-stream "  increment x\n")
  914     (write _test-input-stream "}\n")
  915     # convert
  916     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  917     (flush _test-output-buffered-file)
  918 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  924     # check output
  925     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-mem/0")
  926     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-mem/1")
  927     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-mem/2")
  928     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-mem/3")
  929     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-mem/4")
  930     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-mem/5")
  931     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-in-mem/6")
  932     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-mem/7")
  933     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-in-mem/8")
  934     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-mem/9")
  935     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-mem/10")
  936     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-mem/11")
  937     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-mem/12")
  938     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-mem/13")
  939     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-mem/14")
  940     # . epilogue
  941     89/<- %esp 5/r32/ebp
  942     5d/pop-to-ebp
  943     c3/return
  944 
  945 test-convert-function-with-local-var-with-compound-type-in-mem:
  946     # . prologue
  947     55/push-ebp
  948     89/<- %ebp 4/r32/esp
  949     # setup
  950     (clear-stream _test-input-stream)
  951     (clear-stream $_test-input-buffered-file->buffer)
  952     (clear-stream _test-output-stream)
  953     (clear-stream $_test-output-buffered-file->buffer)
  954     #
  955     (write _test-input-stream "fn foo {\n")
  956     (write _test-input-stream "  var x: (addr int)\n")
  957     (write _test-input-stream "  copy-to x, 0\n")
  958     (write _test-input-stream "}\n")
  959     # convert
  960     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  961     (flush _test-output-buffered-file)
  962 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  968     # check output
  969     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-compound-type-in-mem/0")
  970     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/1")
  971     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-compound-type-in-mem/2")
  972     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/3")
  973     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/4")
  974     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-compound-type-in-mem/5")
  975     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-compound-type-in-mem/6")
  976     (check-next-stream-line-equal _test-output-stream "    c7 0/subop/copy *(ebp+0xfffffffc) 0/imm32"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/7")
  977     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/8")
  978     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/9")
  979     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/10")
  980     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/11")
  981     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/12")
  982     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-compound-type-in-mem/13")
  983     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-compound-type-in-mem/14")
  984     # . epilogue
  985     89/<- %esp 5/r32/ebp
  986     5d/pop-to-ebp
  987     c3/return
  988 
  989 test-convert-function-with-local-var-in-reg:
  990     # . prologue
  991     55/push-ebp
  992     89/<- %ebp 4/r32/esp
  993     # setup
  994     (clear-stream _test-input-stream)
  995     (clear-stream $_test-input-buffered-file->buffer)
  996     (clear-stream _test-output-stream)
  997     (clear-stream $_test-output-buffered-file->buffer)
  998     #
  999     (write _test-input-stream "fn foo {\n")
 1000     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1001     (write _test-input-stream "  x <- increment\n")
 1002     (write _test-input-stream "}\n")
 1003     # convert
 1004     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1005     (flush _test-output-buffered-file)
 1006 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1012     # check output
 1013     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-reg/0")
 1014     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-reg/1")
 1015     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-reg/2")
 1016     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-reg/3")
 1017     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-reg/4")
 1018     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-reg/5")
 1019     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-in-reg/6")
 1020     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-local-var-in-reg/7")
 1021     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-local-var-in-reg/8")
 1022     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-reg/9")
 1023     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-reg/10")
 1024     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-reg/11")
 1025     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-reg/12")
 1026     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-reg/13")
 1027     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-reg/14")
 1028     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-reg/15")
 1029     # . epilogue
 1030     89/<- %esp 5/r32/ebp
 1031     5d/pop-to-ebp
 1032     c3/return
 1033 
 1034 test-convert-function-with-second-local-var-in-same-reg:
 1035     # . prologue
 1036     55/push-ebp
 1037     89/<- %ebp 4/r32/esp
 1038     # setup
 1039     (clear-stream _test-input-stream)
 1040     (clear-stream $_test-input-buffered-file->buffer)
 1041     (clear-stream _test-output-stream)
 1042     (clear-stream $_test-output-buffered-file->buffer)
 1043     #
 1044     (write _test-input-stream "fn foo {\n")
 1045     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1046     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1047     (write _test-input-stream "  y <- increment\n")
 1048     (write _test-input-stream "}\n")
 1049     # convert
 1050     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1051     (flush _test-output-buffered-file)
 1052 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1058     # check output
 1059     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-second-local-var-in-same-reg/0")
 1060     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-second-local-var-in-same-reg/1")
 1061     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-second-local-var-in-same-reg/2")
 1062     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-second-local-var-in-same-reg/3")
 1063     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-second-local-var-in-same-reg/4")
 1064     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-second-local-var-in-same-reg/5")
 1065     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-second-local-var-in-same-reg/6")
 1066     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-second-local-var-in-same-reg/7")
 1067     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-convert-function-with-second-local-var-in-same-reg/8")
 1068     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-second-local-var-in-same-reg/9")
 1069     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-second-local-var-in-same-reg/10")
 1070     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-second-local-var-in-same-reg/11")
 1071     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-second-local-var-in-same-reg/12")
 1072     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-second-local-var-in-same-reg/13")
 1073     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-second-local-var-in-same-reg/14")
 1074     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-second-local-var-in-same-reg/15")
 1075     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-second-local-var-in-same-reg/16")
 1076     # . epilogue
 1077     89/<- %esp 5/r32/ebp
 1078     5d/pop-to-ebp
 1079     c3/return
 1080 
 1081 test-convert-function-with-local-var-dereferenced:
 1082     # . prologue
 1083     55/push-ebp
 1084     89/<- %ebp 4/r32/esp
 1085     # setup
 1086     (clear-stream _test-input-stream)
 1087     (clear-stream $_test-input-buffered-file->buffer)
 1088     (clear-stream _test-output-stream)
 1089     (clear-stream $_test-output-buffered-file->buffer)
 1090     #
 1091     (write _test-input-stream "fn foo {\n")
 1092     (write _test-input-stream "  var x/ecx: (addr int) <- copy 0\n")
 1093     (write _test-input-stream "  increment *x\n")
 1094     (write _test-input-stream "}\n")
 1095     # convert
 1096     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1097     (flush _test-output-buffered-file)
 1098 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1104     # check output
 1105     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-dereferenced/0")
 1106     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-dereferenced/1")
 1107     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-dereferenced/2")
 1108     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-dereferenced/3")
 1109     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-dereferenced/4")
 1110     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-dereferenced/5")
 1111     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-dereferenced/6")
 1112     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-local-var-dereferenced/7")
 1113     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *ecx"  "F - test-convert-function-with-local-var-dereferenced/8")
 1114     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-dereferenced/9")
 1115     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-dereferenced/10")
 1116     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-dereferenced/11")
 1117     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-dereferenced/12")
 1118     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-dereferenced/13")
 1119     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-dereferenced/14")
 1120     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-dereferenced/15")
 1121     # . epilogue
 1122     89/<- %esp 5/r32/ebp
 1123     5d/pop-to-ebp
 1124     c3/return
 1125 
 1126 test-convert-compare-register-with-literal:
 1127     # . prologue
 1128     55/push-ebp
 1129     89/<- %ebp 4/r32/esp
 1130     # setup
 1131     (clear-stream _test-input-stream)
 1132     (clear-stream $_test-input-buffered-file->buffer)
 1133     (clear-stream _test-output-stream)
 1134     (clear-stream $_test-output-buffered-file->buffer)
 1135     #
 1136     (write _test-input-stream "fn foo {\n")
 1137     (write _test-input-stream "  var x/ecx: int <- copy 0\n")
 1138     (write _test-input-stream "  compare x, 0\n")
 1139     (write _test-input-stream "}\n")
 1140     # convert
 1141     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1142     (flush _test-output-buffered-file)
 1143 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1149     # check output
 1150     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-compare-register-with-literal/0")
 1151     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-compare-register-with-literal/1")
 1152     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-compare-register-with-literal/2")
 1153     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-compare-register-with-literal/3")
 1154     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-compare-register-with-literal/4")
 1155     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-compare-register-with-literal/5")
 1156     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 1157     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-compare-register-with-literal/7")
 1158     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0/imm32"  "F - test-convert-compare-register-with-literal/8")
 1159     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 1160     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-compare-register-with-literal/10")
 1161     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-compare-register-with-literal/11")
 1162     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-compare-register-with-literal/12")
 1163     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-compare-register-with-literal/13")
 1164     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-compare-register-with-literal/14")
 1165     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-compare-register-with-literal/15")
 1166     # . epilogue
 1167     89/<- %esp 5/r32/ebp
 1168     5d/pop-to-ebp
 1169     c3/return
 1170 
 1171 test-convert-function-with-local-var-in-block:
 1172     # . prologue
 1173     55/push-ebp
 1174     89/<- %ebp 4/r32/esp
 1175     # setup
 1176     (clear-stream _test-input-stream)
 1177     (clear-stream $_test-input-buffered-file->buffer)
 1178     (clear-stream _test-output-stream)
 1179     (clear-stream $_test-output-buffered-file->buffer)
 1180     #
 1181     (write _test-input-stream "fn foo {\n")
 1182     (write _test-input-stream "  {\n")
 1183     (write _test-input-stream "    var x: int\n")
 1184     (write _test-input-stream "    increment x\n")
 1185     (write _test-input-stream "  }\n")
 1186     (write _test-input-stream "}\n")
 1187     # convert
 1188     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1189     (flush _test-output-buffered-file)
 1190 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1196     # check output
 1197     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-block/0")
 1198     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-block/1")
 1199     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-block/2")
 1200     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-block/3")
 1201     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-block/4")
 1202     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-block/5")
 1203     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-block/6")
 1204     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-local-var-in-block/7")
 1205     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-block/8")
 1206     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-block/9")
 1207     (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-in-block/10")
 1208     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-block/11")
 1209     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-local-var-in-block/12")
 1210     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-block/13")
 1211     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-block/14")
 1212     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-block/15")
 1213     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-block/16")
 1214     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-block/17")
 1215     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-block/18")
 1216     # . epilogue
 1217     89/<- %esp 5/r32/ebp
 1218     5d/pop-to-ebp
 1219     c3/return
 1220 
 1221 test-convert-function-with-local-var-in-named-block:
 1222     # . prologue
 1223     55/push-ebp
 1224     89/<- %ebp 4/r32/esp
 1225     # setup
 1226     (clear-stream _test-input-stream)
 1227     (clear-stream $_test-input-buffered-file->buffer)
 1228     (clear-stream _test-output-stream)
 1229     (clear-stream $_test-output-buffered-file->buffer)
 1230     #
 1231     (write _test-input-stream "fn foo {\n")
 1232     (write _test-input-stream "  $bar: {\n")
 1233     (write _test-input-stream "    var x: int\n")
 1234     (write _test-input-stream "    increment x\n")
 1235     (write _test-input-stream "  }\n")
 1236     (write _test-input-stream "}\n")
 1237     # convert
 1238     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1239     (flush _test-output-buffered-file)
 1240 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1246     # check output
 1247     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-named-block/0")
 1248     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-named-block/1")
 1249     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-named-block/2")
 1250     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-named-block/3")
 1251     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-named-block/4")
 1252     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-named-block/5")
 1253     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-named-block/6")
 1254     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-local-var-in-named-block/7")
 1255     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-named-block/8")
 1256     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-named-block/9")
 1257     (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-in-named-block/10")
 1258     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-named-block/11")
 1259     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-local-var-in-named-block/12")
 1260     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-named-block/13")
 1261     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-named-block/14")
 1262     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-named-block/15")
 1263     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-named-block/16")
 1264     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-named-block/17")
 1265     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-named-block/18")
 1266     # . epilogue
 1267     89/<- %esp 5/r32/ebp
 1268     5d/pop-to-ebp
 1269     c3/return
 1270 
 1271 test-always-shadow-outermost-reg-vars-in-function:
 1272     # . prologue
 1273     55/push-ebp
 1274     89/<- %ebp 4/r32/esp
 1275     # setup
 1276     (clear-stream _test-input-stream)
 1277     (clear-stream $_test-input-buffered-file->buffer)
 1278     (clear-stream _test-output-stream)
 1279     (clear-stream $_test-output-buffered-file->buffer)
 1280     #
 1281     (write _test-input-stream "fn foo {\n")
 1282     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1283     (write _test-input-stream "}\n")
 1284     # convert
 1285     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1286     (flush _test-output-buffered-file)
 1287 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1293     # check output
 1294     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-always-shadow-outermost-reg-vars-in-function/0")
 1295     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-always-shadow-outermost-reg-vars-in-function/1")
 1296     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-always-shadow-outermost-reg-vars-in-function/2")
 1297     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-always-shadow-outermost-reg-vars-in-function/3")
 1298     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-always-shadow-outermost-reg-vars-in-function/4")
 1299     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-always-shadow-outermost-reg-vars-in-function/5")
 1300     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 1301     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-always-shadow-outermost-reg-vars-in-function/8")
 1302     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 1303     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-always-shadow-outermost-reg-vars-in-function/12")
 1304     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-always-shadow-outermost-reg-vars-in-function/13")
 1305     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-always-shadow-outermost-reg-vars-in-function/14")
 1306     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-always-shadow-outermost-reg-vars-in-function/15")
 1307     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-always-shadow-outermost-reg-vars-in-function/16")
 1308     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-always-shadow-outermost-reg-vars-in-function/17")
 1309     # . epilogue
 1310     89/<- %esp 5/r32/ebp
 1311     5d/pop-to-ebp
 1312     c3/return
 1313 
 1314 _pending-test-clobber-dead-local:
 1315     # . prologue
 1316     55/push-ebp
 1317     89/<- %ebp 4/r32/esp
 1318     # setup
 1319     (clear-stream _test-input-stream)
 1320     (clear-stream $_test-input-buffered-file->buffer)
 1321     (clear-stream _test-output-stream)
 1322     (clear-stream $_test-output-buffered-file->buffer)
 1323     #
 1324     (write _test-input-stream "fn foo {\n")
 1325     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1326     (write _test-input-stream "  {\n")
 1327     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 1328     (write _test-input-stream "  }\n")
 1329     (write _test-input-stream "}\n")
 1330     # convert
 1331     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1332     (flush _test-output-buffered-file)
 1333 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1339     # check output
 1340     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-clobber-dead-local/0")
 1341     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-clobber-dead-local/1")
 1342     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-clobber-dead-local/2")
 1343     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-clobber-dead-local/3")
 1344     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-clobber-dead-local/4")
 1345     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-clobber-dead-local/5")
 1346     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-clobber-dead-local/6")
 1347     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-clobber-dead-local/7")
 1348     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-clobber-dead-local/8")
 1349     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-clobber-dead-local/9")
 1350     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-clobber-dead-local/10")  # no push/pop here
 1351     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-clobber-dead-local/11")
 1352     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-clobber-dead-local/12")
 1353     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-clobber-dead-local/13")
 1354     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-clobber-dead-local/14")
 1355     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-clobber-dead-local/15")
 1356     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-clobber-dead-local/16")
 1357     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-clobber-dead-local/17")
 1358     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-clobber-dead-local/18")
 1359     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-clobber-dead-local/19")
 1360     # . epilogue
 1361     89/<- %esp 5/r32/ebp
 1362     5d/pop-to-ebp
 1363     c3/return
 1364 
 1365 test-shadow-live-local:
 1366     # . prologue
 1367     55/push-ebp
 1368     89/<- %ebp 4/r32/esp
 1369     # setup
 1370     (clear-stream _test-input-stream)
 1371     (clear-stream $_test-input-buffered-file->buffer)
 1372     (clear-stream _test-output-stream)
 1373     (clear-stream $_test-output-buffered-file->buffer)
 1374     #
 1375     (write _test-input-stream "fn foo {\n")
 1376     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1377     (write _test-input-stream "  {\n")
 1378     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 1379     (write _test-input-stream "  }\n")
 1380     (write _test-input-stream "  x <- increment\n")
 1381     (write _test-input-stream "}\n")
 1382     # convert
 1383     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1384     (flush _test-output-buffered-file)
 1385 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1391     # check output
 1392     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-local/0")
 1393     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-local/1")
 1394     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-local/2")
 1395     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-local/3")
 1396     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-local/4")
 1397     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-local/5")
 1398     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-live-local/6")
 1399     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-live-local/7")
 1400     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-local/8")
 1401     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-local/9")
 1402     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-local/10")
 1403     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-local/11")
 1404     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-local/12")
 1405     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-local/13")
 1406     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-local/14")
 1407     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-local/15")
 1408     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-live-local/16")
 1409     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-local/17")
 1410     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-local/18")
 1411     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-local/19")
 1412     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-local/20")
 1413     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-local/21")
 1414     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-local/21")
 1415     # . epilogue
 1416     89/<- %esp 5/r32/ebp
 1417     5d/pop-to-ebp
 1418     c3/return
 1419 
 1420 test-do-not-spill-same-register-in-block:
 1421     # . prologue
 1422     55/push-ebp
 1423     89/<- %ebp 4/r32/esp
 1424     # setup
 1425     (clear-stream _test-input-stream)
 1426     (clear-stream $_test-input-buffered-file->buffer)
 1427     (clear-stream _test-output-stream)
 1428     (clear-stream $_test-output-buffered-file->buffer)
 1429     #
 1430     (write _test-input-stream "fn foo {\n")
 1431     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1432     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1433     (write _test-input-stream "  y <- increment\n")
 1434     (write _test-input-stream "}\n")
 1435     # convert
 1436     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1437     (flush _test-output-buffered-file)
 1438 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1444     # check output
 1445     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-do-not-spill-same-register-in-block/0")
 1446     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-do-not-spill-same-register-in-block/1")
 1447     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-do-not-spill-same-register-in-block/2")
 1448     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-do-not-spill-same-register-in-block/3")
 1449     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-do-not-spill-same-register-in-block/4")
 1450     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-do-not-spill-same-register-in-block/5")
 1451     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-do-not-spill-same-register-in-block/6")
 1452     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-do-not-spill-same-register-in-block/7")
 1453     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-do-not-spill-same-register-in-block/8")
 1454     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-do-not-spill-same-register-in-block/9")
 1455     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-do-not-spill-same-register-in-block/10")
 1456     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-do-not-spill-same-register-in-block/11")
 1457     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-do-not-spill-same-register-in-block/12")
 1458     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-do-not-spill-same-register-in-block/13")
 1459     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-do-not-spill-same-register-in-block/14")
 1460     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-do-not-spill-same-register-in-block/15")
 1461     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-do-not-spill-same-register-in-block/16")
 1462     # . epilogue
 1463     89/<- %esp 5/r32/ebp
 1464     5d/pop-to-ebp
 1465     c3/return
 1466 
 1467 test-spill-different-register-in-block:
 1468     # . prologue
 1469     55/push-ebp
 1470     89/<- %ebp 4/r32/esp
 1471     # setup
 1472     (clear-stream _test-input-stream)
 1473     (clear-stream $_test-input-buffered-file->buffer)
 1474     (clear-stream _test-output-stream)
 1475     (clear-stream $_test-output-buffered-file->buffer)
 1476     #
 1477     (write _test-input-stream "fn foo {\n")
 1478     (write _test-input-stream "  var x/eax: int <- copy 3\n")
 1479     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1480     (write _test-input-stream "  y <- increment\n")
 1481     (write _test-input-stream "}\n")
 1482     # convert
 1483     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1484     (flush _test-output-buffered-file)
 1485 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1491     # check output
 1492     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-spill-different-register-in-block/0")
 1493     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-spill-different-register-in-block/1")
 1494     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-spill-different-register-in-block/2")
 1495     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-spill-different-register-in-block/3")
 1496     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-spill-different-register-in-block/4")
 1497     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-spill-different-register-in-block/5")
 1498     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-spill-different-register-in-block/6")
 1499     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-spill-different-register-in-block/7")
 1500     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-spill-different-register-in-block/8")
 1501     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-spill-different-register-in-block/9")
 1502     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-spill-different-register-in-block/10")
 1503     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-spill-different-register-in-block/11")
 1504     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-spill-different-register-in-block/12")
 1505     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-spill-different-register-in-block/13")
 1506     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-spill-different-register-in-block/14")
 1507     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-spill-different-register-in-block/15")
 1508     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-spill-different-register-in-block/16")
 1509     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-spill-different-register-in-block/17")
 1510     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-spill-different-register-in-block/18")
 1511     # . epilogue
 1512     89/<- %esp 5/r32/ebp
 1513     5d/pop-to-ebp
 1514     c3/return
 1515 
 1516 test-shadow-live-output:
 1517     # . prologue
 1518     55/push-ebp
 1519     89/<- %ebp 4/r32/esp
 1520     # setup
 1521     (clear-stream _test-input-stream)
 1522     (clear-stream $_test-input-buffered-file->buffer)
 1523     (clear-stream _test-output-stream)
 1524     (clear-stream $_test-output-buffered-file->buffer)
 1525     #
 1526     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 1527     (write _test-input-stream "  x <- copy 3\n")
 1528     (write _test-input-stream "  {\n")
 1529     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 1530     (write _test-input-stream "  }\n")
 1531     (write _test-input-stream "  x <- increment\n")
 1532     (write _test-input-stream "}\n")
 1533     # convert
 1534     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1535     (flush _test-output-buffered-file)
 1536 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1542     # check output
 1543     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-output/0")
 1544     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-output/1")
 1545     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-output/2")
 1546     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-output/3")
 1547     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-output/4")
 1548     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-output/5")
 1549     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-live-output/7")  # no push because it's an output reg
 1550     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-output/8")
 1551     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-output/9")
 1552     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-output/10")
 1553     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-output/11")
 1554     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-output/12")
 1555     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-output/13")
 1556     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-output/14")
 1557     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-output/15")
 1558     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-output/17")
 1559     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-output/18")
 1560     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-output/19")
 1561     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-output/20")
 1562     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-output/21")
 1563     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-output/21")
 1564     # . epilogue
 1565     89/<- %esp 5/r32/ebp
 1566     5d/pop-to-ebp
 1567     c3/return
 1568 
 1569 _pending-test-local-clobbered-by-output:
 1570     # also doesn't spill
 1571     # . prologue
 1572     55/push-ebp
 1573     89/<- %ebp 4/r32/esp
 1574     # setup
 1575     (clear-stream _test-input-stream)
 1576     (clear-stream $_test-input-buffered-file->buffer)
 1577     (clear-stream _test-output-stream)
 1578     (clear-stream $_test-output-buffered-file->buffer)
 1579     #
 1580     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 1581     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1582     (write _test-input-stream "  x <- copy y\n")
 1583     (write _test-input-stream "}\n")
 1584     # convert
 1585     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1586     (flush _test-output-buffered-file)
 1587 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1593     # check output
 1594     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-local-clobbered-by-output/0")
 1595     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-local-clobbered-by-output/1")
 1596     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-local-clobbered-by-output/2")
 1597     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-local-clobbered-by-output/3")
 1598     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-local-clobbered-by-output/4")
 1599     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-local-clobbered-by-output/5")
 1600     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-local-clobbered-by-output/6")
 1601     (check-next-stream-line-equal _test-output-stream "    89/<- %ecx 0x00000001/r32"  "F - test-local-clobbered-by-output/7")
 1602     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-local-clobbered-by-output/8")
 1603     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-local-clobbered-by-output/9")
 1604     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-local-clobbered-by-output/10")
 1605     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-local-clobbered-by-output/11")
 1606     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-local-clobbered-by-output/12")
 1607     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-local-clobbered-by-output/13")
 1608     # . epilogue
 1609     89/<- %esp 5/r32/ebp
 1610     5d/pop-to-ebp
 1611     c3/return
 1612 
 1613 test-convert-function-with-branches-in-block:
 1614     # . prologue
 1615     55/push-ebp
 1616     89/<- %ebp 4/r32/esp
 1617     # setup
 1618     (clear-stream _test-input-stream)
 1619     (clear-stream $_test-input-buffered-file->buffer)
 1620     (clear-stream _test-output-stream)
 1621     (clear-stream $_test-output-buffered-file->buffer)
 1622     #
 1623     (write _test-input-stream "fn foo x: int {\n")
 1624     (write _test-input-stream "  {\n")
 1625     (write _test-input-stream "    break-if->=\n")
 1626     (write _test-input-stream "    loop-if-addr<\n")
 1627     (write _test-input-stream "    increment x\n")
 1628     (write _test-input-stream "    loop\n")
 1629     (write _test-input-stream "  }\n")
 1630     (write _test-input-stream "}\n")
 1631     # convert
 1632     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1633     (flush _test-output-buffered-file)
 1634 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1640     # check output
 1641     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-block/0")
 1642     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-block/1")
 1643     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-block/2")
 1644     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-block/3")
 1645     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-block/4")
 1646     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-block/5")
 1647     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-block/6")
 1648     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-in-block/7")
 1649     (check-next-stream-line-equal _test-output-stream "      0f 8d/jump-if->= break/disp32"  "F - test-convert-function-with-branches-in-block/8")
 1650     (check-next-stream-line-equal _test-output-stream "      0f 82/jump-if-addr< loop/disp32"  "F - test-convert-function-with-branches-in-block/9")
 1651     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-block/10")
 1652     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-in-block/11")
 1653     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-block/12")
 1654     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-in-block/13")
 1655     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-block/14")
 1656     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-block/15")
 1657     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-block/16")
 1658     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-block/17")
 1659     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-block/18")
 1660     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-block/19")
 1661     # . epilogue
 1662     89/<- %esp 5/r32/ebp
 1663     5d/pop-to-ebp
 1664     c3/return
 1665 
 1666 test-convert-function-with-branches-in-named-block:
 1667     # . prologue
 1668     55/push-ebp
 1669     89/<- %ebp 4/r32/esp
 1670     # setup
 1671     (clear-stream _test-input-stream)
 1672     (clear-stream $_test-input-buffered-file->buffer)
 1673     (clear-stream _test-output-stream)
 1674     (clear-stream $_test-output-buffered-file->buffer)
 1675     #
 1676     (write _test-input-stream "fn foo x: int {\n")
 1677     (write _test-input-stream "  $bar: {\n")
 1678     (write _test-input-stream "    break-if->= $bar\n")
 1679     (write _test-input-stream "    loop-if-addr< $bar\n")
 1680     (write _test-input-stream "    increment x\n")
 1681     (write _test-input-stream "    loop\n")
 1682     (write _test-input-stream "  }\n")
 1683     (write _test-input-stream "}\n")
 1684     # convert
 1685     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1686     (flush _test-output-buffered-file)
 1687 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1693     # check output
 1694     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-named-block/0")
 1695     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-named-block/1")
 1696     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-named-block/2")
 1697     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-named-block/3")
 1698     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-named-block/4")
 1699     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-named-block/5")
 1700     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-named-block/6")
 1701     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-branches-in-named-block/7")
 1702     (check-next-stream-line-equal _test-output-stream "      0f 8d/jump-if->= $bar:break/disp32"  "F - test-convert-function-with-branches-in-named-block/8")
 1703     (check-next-stream-line-equal _test-output-stream "      0f 82/jump-if-addr< $bar:loop/disp32"  "F - test-convert-function-with-branches-in-named-block/9")
 1704     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-named-block/10")
 1705     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"   "F - test-convert-function-with-branches-in-named-block/11")
 1706     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-named-block/12")
 1707     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-branches-in-named-block/13")
 1708     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-named-block/14")
 1709     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-named-block/15")
 1710     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-named-block/16")
 1711     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-named-block/17")
 1712     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-named-block/18")
 1713     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-named-block/19")
 1714     # . epilogue
 1715     89/<- %esp 5/r32/ebp
 1716     5d/pop-to-ebp
 1717     c3/return
 1718 
 1719 test-convert-function-with-var-in-nested-block:
 1720     # . prologue
 1721     55/push-ebp
 1722     89/<- %ebp 4/r32/esp
 1723     # setup
 1724     (clear-stream _test-input-stream)
 1725     (clear-stream $_test-input-buffered-file->buffer)
 1726     (clear-stream _test-output-stream)
 1727     (clear-stream $_test-output-buffered-file->buffer)
 1728     #
 1729     (write _test-input-stream "fn foo x: int {\n")
 1730     (write _test-input-stream "  {\n")
 1731     (write _test-input-stream "    {\n")
 1732     (write _test-input-stream "      var x: int\n")
 1733     (write _test-input-stream "      increment x\n")
 1734     (write _test-input-stream "    }\n")
 1735     (write _test-input-stream "  }\n")
 1736     (write _test-input-stream "}\n")
 1737     # convert
 1738     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1739     (flush _test-output-buffered-file)
 1740 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1746     # check output
 1747     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-var-in-nested-block/0")
 1748     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-var-in-nested-block/1")
 1749     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-var-in-nested-block/2")
 1750     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-var-in-nested-block/3")
 1751     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-var-in-nested-block/4")
 1752     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-var-in-nested-block/5")
 1753     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-var-in-nested-block/6")
 1754     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-var-in-nested-block/7")
 1755     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-var-in-nested-block/8")
 1756     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-var-in-nested-block/9")
 1757     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-var-in-nested-block/10")
 1758     (check-next-stream-line-equal _test-output-stream "        ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-var-in-nested-block/11")
 1759     (check-next-stream-line-equal _test-output-stream "        81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-var-in-nested-block/12")
 1760     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-var-in-nested-block/13")
 1761     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-var-in-nested-block/14")
 1762     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-var-in-nested-block/15")
 1763     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-var-in-nested-block/16")
 1764     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-var-in-nested-block/17")
 1765     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-var-in-nested-block/18")
 1766     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-var-in-nested-block/19")
 1767     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-var-in-nested-block/20")
 1768     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-var-in-nested-block/21")
 1769     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-var-in-nested-block/22")
 1770     # . epilogue
 1771     89/<- %esp 5/r32/ebp
 1772     5d/pop-to-ebp
 1773     c3/return
 1774 
 1775 test-convert-function-with-multiple-vars-in-nested-blocks:
 1776     # . prologue
 1777     55/push-ebp
 1778     89/<- %ebp 4/r32/esp
 1779     # setup
 1780     (clear-stream _test-input-stream)
 1781     (clear-stream $_test-input-buffered-file->buffer)
 1782     (clear-stream _test-output-stream)
 1783     (clear-stream $_test-output-buffered-file->buffer)
 1784     #
 1785     (write _test-input-stream "fn foo x: int {\n")
 1786     (write _test-input-stream "  {\n")
 1787     (write _test-input-stream "    var x/eax: int <- copy 0\n")
 1788     (write _test-input-stream "    {\n")
 1789     (write _test-input-stream "      var y: int\n")
 1790     (write _test-input-stream "      x <- add y\n")
 1791     (write _test-input-stream "    }\n")
 1792     (write _test-input-stream "  }\n")
 1793     (write _test-input-stream "}\n")
 1794     # convert
 1795     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1796     (flush _test-output-buffered-file)
 1797 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1803     # check output
 1804     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-multiple-vars-in-nested-blocks/0")
 1805     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/1")
 1806     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-multiple-vars-in-nested-blocks/2")
 1807     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/3")
 1808     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/4")
 1809     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/5")
 1810     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/6")
 1811     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/7")
 1812     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %eax"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/8")
 1813     (check-next-stream-line-equal _test-output-stream "      b8/copy-to-eax 0/imm32"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/9")
 1814     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/10")
 1815     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/11")
 1816     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/12")
 1817     (check-next-stream-line-equal _test-output-stream "        03/add *(ebp+0xfffffff8) 0x00000000/r32"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/13")
 1818     (check-next-stream-line-equal _test-output-stream "        81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/14")
 1819     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/15")
 1820     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/16")
 1821     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %eax"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/17")
 1822     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/18")
 1823     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/19")
 1824     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/20")
 1825     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/21")
 1826     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/22")
 1827     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/23")
 1828     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-multiple-vars-in-nested-blocks/24")
 1829     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-multiple-vars-in-nested-blocks/25")
 1830     # . epilogue
 1831     89/<- %esp 5/r32/ebp
 1832     5d/pop-to-ebp
 1833     c3/return
 1834 
 1835 test-convert-function-with-branches-and-local-vars:
 1836     # A conditional 'break' after a 'var' in a block is converted into a
 1837     # nested block that performs all necessary cleanup before jumping. This
 1838     # results in some ugly code duplication.
 1839     # . prologue
 1840     55/push-ebp
 1841     89/<- %ebp 4/r32/esp
 1842     # setup
 1843     (clear-stream _test-input-stream)
 1844     (clear-stream $_test-input-buffered-file->buffer)
 1845     (clear-stream _test-output-stream)
 1846     (clear-stream $_test-output-buffered-file->buffer)
 1847     #
 1848     (write _test-input-stream "fn foo {\n")
 1849     (write _test-input-stream "  {\n")
 1850     (write _test-input-stream "    var x: int\n")
 1851     (write _test-input-stream "    break-if->=\n")
 1852     (write _test-input-stream "    increment x\n")
 1853     (write _test-input-stream "  }\n")
 1854     (write _test-input-stream "}\n")
 1855     # convert
 1856     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1857     (flush _test-output-buffered-file)
 1858 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1864     # check output
 1865     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-local-vars/0")
 1866     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-local-vars/1")
 1867     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-local-vars/2")
 1868     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-and-local-vars/3")
 1869     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-local-vars/4")
 1870     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-local-vars/5")
 1871     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-local-vars/6")
 1872     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-local-vars/7")
 1873     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-local-vars/8")
 1874     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-local-vars/9")
 1875     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-and-local-vars/10")
 1876     (check-next-stream-line-equal _test-output-stream "        81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-branches-and-local-vars/11")
 1877     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-and-local-vars/12")
 1878     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-local-vars/13")
 1879     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-branches-and-local-vars/14")
 1880     (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-branches-and-local-vars/15")
 1881     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-local-vars/16")
 1882     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-local-vars/17")
 1883     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-local-vars/18")
 1884     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-local-vars/19")
 1885     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-local-vars/20")
 1886     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-and-local-vars/21")
 1887     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-local-vars/22")
 1888     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-local-vars/23")
 1889     # . epilogue
 1890     89/<- %esp 5/r32/ebp
 1891     5d/pop-to-ebp
 1892     c3/return
 1893 
 1894 test-convert-function-with-conditional-loops-and-local-vars:
 1895     # A conditional 'loop' after a 'var' in a block is converted into a nested
 1896     # block that performs all necessary cleanup before jumping. This results
 1897     # in some ugly code duplication.
 1898     # . prologue
 1899     55/push-ebp
 1900     89/<- %ebp 4/r32/esp
 1901     # setup
 1902     (clear-stream _test-input-stream)
 1903     (clear-stream $_test-input-buffered-file->buffer)
 1904     (clear-stream _test-output-stream)
 1905     (clear-stream $_test-output-buffered-file->buffer)
 1906     #
 1907     (write _test-input-stream "fn foo {\n")
 1908     (write _test-input-stream "  {\n")
 1909     (write _test-input-stream "    var x: int\n")
 1910     (write _test-input-stream "    loop-if->=\n")
 1911     (write _test-input-stream "    increment x\n")
 1912     (write _test-input-stream "  }\n")
 1913     (write _test-input-stream "}\n")
 1914     # convert
 1915     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1916     (flush _test-output-buffered-file)
 1917 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1923     # check output
 1924     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-conditional-loops-and-local-vars/0")
 1925     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-conditional-loops-and-local-vars/1")
 1926     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-conditional-loops-and-local-vars/2")
 1927     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-conditional-loops-and-local-vars/3")
 1928     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-conditional-loops-and-local-vars/4")
 1929     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/5")
 1930     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-conditional-loops-and-local-vars/6")
 1931     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/7")
 1932     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-conditional-loops-and-local-vars/8")
 1933     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-conditional-loops-and-local-vars/9")
 1934     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-conditional-loops-and-local-vars/10")
 1935     (check-next-stream-line-equal _test-output-stream "        81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-conditional-loops-and-local-vars/11")
 1936     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:loop/disp32"  "F - test-convert-function-with-conditional-loops-and-local-vars/12")
 1937     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-conditional-loops-and-local-vars/13")
 1938     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-conditional-loops-and-local-vars/14")
 1939     (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-conditional-loops-and-local-vars/15")
 1940     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-conditional-loops-and-local-vars/16")
 1941     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/17")
 1942     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-conditional-loops-and-local-vars/18")
 1943     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/19")
 1944     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-conditional-loops-and-local-vars/20")
 1945     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-conditional-loops-and-local-vars/21")
 1946     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-conditional-loops-and-local-vars/22")
 1947     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-conditional-loops-and-local-vars/23")
 1948     # . epilogue
 1949     89/<- %esp 5/r32/ebp
 1950     5d/pop-to-ebp
 1951     c3/return
 1952 
 1953 test-convert-function-with-unconditional-loops-and-local-vars:
 1954     # An unconditional 'loop' after a 'var' in a block is emitted _after_ the
 1955     # regular block cleanup. Any instructions after 'loop' are dead and
 1956     # therefore skipped.
 1957     # . prologue
 1958     55/push-ebp
 1959     89/<- %ebp 4/r32/esp
 1960     # setup
 1961     (clear-stream _test-input-stream)
 1962     (clear-stream $_test-input-buffered-file->buffer)
 1963     (clear-stream _test-output-stream)
 1964     (clear-stream $_test-output-buffered-file->buffer)
 1965     #
 1966     (write _test-input-stream "fn foo {\n")
 1967     (write _test-input-stream "  {\n")
 1968     (write _test-input-stream "    var x: int\n")
 1969     (write _test-input-stream "    loop\n")
 1970     (write _test-input-stream "    increment x\n")
 1971     (write _test-input-stream "  }\n")
 1972     (write _test-input-stream "}\n")
 1973     # convert
 1974     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1975     (flush _test-output-buffered-file)
 1976 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1982     # check output
 1983     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-loops-and-local-vars/0")
 1984     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/1")
 1985     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-loops-and-local-vars/2")
 1986     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/3")
 1987     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/4")
 1988     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/5")
 1989     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/6")
 1990     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/7")
 1991     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-loops-and-local-vars/8")
 1992     (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-unconditional-loops-and-local-vars/9")
 1993     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-unconditional-loops-and-local-vars/10")
 1994     # not emitted:                                           ff 0/subop/increment *(ebp+0xfffffffc)
 1995     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/11")
 1996     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/12")
 1997     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/13")
 1998     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/14")
 1999     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/15")
 2000     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/16")
 2001     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-loops-and-local-vars/17")
 2002     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-loops-and-local-vars/18")
 2003     # . epilogue
 2004     89/<- %esp 5/r32/ebp
 2005     5d/pop-to-ebp
 2006     c3/return
 2007 
 2008 test-convert-function-with-branches-and-loops-and-local-vars:
 2009     # . prologue
 2010     55/push-ebp
 2011     89/<- %ebp 4/r32/esp
 2012     # setup
 2013     (clear-stream _test-input-stream)
 2014     (clear-stream $_test-input-buffered-file->buffer)
 2015     (clear-stream _test-output-stream)
 2016     (clear-stream $_test-output-buffered-file->buffer)
 2017     #
 2018     (write _test-input-stream "fn foo {\n")
 2019     (write _test-input-stream "  {\n")
 2020     (write _test-input-stream "    var x: int\n")
 2021     (write _test-input-stream "    break-if->=\n")
 2022     (write _test-input-stream "    increment x\n")
 2023     (write _test-input-stream "    loop\n")
 2024     (write _test-input-stream "  }\n")
 2025     (write _test-input-stream "}\n")
 2026     # convert
 2027     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2028     (flush _test-output-buffered-file)
 2029 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2035     # check output
 2036     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-loops-and-local-vars/0")
 2037     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/1")
 2038     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-loops-and-local-vars/2")
 2039     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-and-loops-and-local-vars/3")
 2040     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/4")
 2041     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/5")
 2042     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/6")
 2043     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/7")
 2044     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-loops-and-local-vars/8")
 2045     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/9")
 2046     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/10")
 2047     (check-next-stream-line-equal _test-output-stream "        81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/11")
 2048     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/12")
 2049     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/13")
 2050     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-branches-and-loops-and-local-vars/14")
 2051     (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/15")
 2052     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/16")
 2053     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/17")
 2054     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/18")
 2055     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/19")
 2056     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/20")
 2057     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/21")
 2058     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-and-loops-and-local-vars/22")
 2059     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-loops-and-local-vars/23")
 2060     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-loops-and-local-vars/24")
 2061     # . epilogue
 2062     89/<- %esp 5/r32/ebp
 2063     5d/pop-to-ebp
 2064     c3/return
 2065 
 2066 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars:
 2067     # . prologue
 2068     55/push-ebp
 2069     89/<- %ebp 4/r32/esp
 2070     # setup
 2071     (clear-stream _test-input-stream)
 2072     (clear-stream $_test-input-buffered-file->buffer)
 2073     (clear-stream _test-output-stream)
 2074     (clear-stream $_test-output-buffered-file->buffer)
 2075     #
 2076     (write _test-input-stream "fn foo {\n")
 2077     (write _test-input-stream "  a: {\n")
 2078     (write _test-input-stream "    var x: int\n")
 2079     (write _test-input-stream "    {\n")
 2080     (write _test-input-stream "      var y: int\n")
 2081     (write _test-input-stream "      break-if->= a\n")
 2082     (write _test-input-stream "      increment x\n")
 2083     (write _test-input-stream "      loop\n")
 2084     (write _test-input-stream "    }\n")
 2085     (write _test-input-stream "  }\n")
 2086     (write _test-input-stream "}\n")
 2087     # convert
 2088     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2089     (flush _test-output-buffered-file)
 2090 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2096     # check output
 2097     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/0")
 2098     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/1")
 2099     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/2")
 2100     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/3")
 2101     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/4")
 2102     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/5")
 2103     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/6")
 2104     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/7")
 2105     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/8")
 2106     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/9")
 2107     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/10")
 2108     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/11")
 2109     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/12")
 2110     (check-next-stream-line-equal _test-output-stream "          0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/13")
 2111     (check-next-stream-line-equal _test-output-stream "          81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/14")
 2112     (check-next-stream-line-equal _test-output-stream "          81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/15")
 2113     (check-next-stream-line-equal _test-output-stream "          e9/jump a:break/disp32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/16")
 2114     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/17")
 2115     (check-next-stream-line-equal _test-output-stream "        ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/18")
 2116     (check-next-stream-line-equal _test-output-stream "        81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/19")
 2117     (check-next-stream-line-equal _test-output-stream "        e9/jump loop/disp32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/20")
 2118     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/21")
 2119     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/22")
 2120     (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/23")
 2121     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/24")
 2122     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/25")
 2123     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/26")
 2124     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/27")
 2125     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/28")
 2126     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/29")
 2127     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/30")
 2128     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/31")
 2129     # . epilogue
 2130     89/<- %esp 5/r32/ebp
 2131     5d/pop-to-ebp
 2132     c3/return
 2133 
 2134 test-convert-function-with-nonlocal-unconditional-break-and-local-vars:
 2135     # . prologue
 2136     55/push-ebp
 2137     89/<- %ebp 4/r32/esp
 2138     # setup
 2139     (clear-stream _test-input-stream)
 2140     (clear-stream $_test-input-buffered-file->buffer)
 2141     (clear-stream _test-output-stream)
 2142     (clear-stream $_test-output-buffered-file->buffer)
 2143     #
 2144     (write _test-input-stream "fn foo {\n")
 2145     (write _test-input-stream "  a: {\n")
 2146     (write _test-input-stream "    var x: int\n")
 2147     (write _test-input-stream "    {\n")
 2148     (write _test-input-stream "      var y: int\n")
 2149     (write _test-input-stream "      break a\n")
 2150     (write _test-input-stream "      increment x\n")
 2151     (write _test-input-stream "    }\n")
 2152     (write _test-input-stream "  }\n")
 2153     (write _test-input-stream "}\n")
 2154     # convert
 2155     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2156     (flush _test-output-buffered-file)
 2157 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2163     # check output
 2164     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/0")
 2165     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/1")
 2166     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/2")
 2167     (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")
 2168     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/4")
 2169     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/5")
 2170     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/6")
 2171     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/7")
 2172     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/8")
 2173     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/9")
 2174     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/10")
 2175     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/11")
 2176     (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")
 2177     (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")
 2178     (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")
 2179     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/15")
 2180     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/16")
 2181     (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")
 2182     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/18")
 2183     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/19")
 2184     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/20")
 2185     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/21")
 2186     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/22")
 2187     (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")
 2188     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/24")
 2189     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/25")
 2190     # . epilogue
 2191     89/<- %esp 5/r32/ebp
 2192     5d/pop-to-ebp
 2193     c3/return
 2194 
 2195 test-convert-function-with-unconditional-break-and-local-vars:
 2196     # . prologue
 2197     55/push-ebp
 2198     89/<- %ebp 4/r32/esp
 2199     # setup
 2200     (clear-stream _test-input-stream)
 2201     (clear-stream $_test-input-buffered-file->buffer)
 2202     (clear-stream _test-output-stream)
 2203     (clear-stream $_test-output-buffered-file->buffer)
 2204     #
 2205     (write _test-input-stream "fn foo {\n")
 2206     (write _test-input-stream "  {\n")
 2207     (write _test-input-stream "    var x: int\n")
 2208     (write _test-input-stream "    {\n")
 2209     (write _test-input-stream "      var y: int\n")
 2210     (write _test-input-stream "      break\n")
 2211     (write _test-input-stream "      increment x\n")
 2212     (write _test-input-stream "    }\n")
 2213     (write _test-input-stream "  }\n")
 2214     (write _test-input-stream "}\n")
 2215     # convert
 2216     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2217     (flush _test-output-buffered-file)
 2218 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2224     # check output
 2225     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-break-and-local-vars/0")
 2226     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-break-and-local-vars/1")
 2227     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-break-and-local-vars/2")
 2228     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-break-and-local-vars/3")
 2229     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-break-and-local-vars/4")
 2230     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/5")
 2231     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-break-and-local-vars/6")
 2232     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/7")
 2233     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-break-and-local-vars/8")
 2234     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-unconditional-break-and-local-vars/9")
 2235     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/10")
 2236     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/11")
 2237     (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")
 2238     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-unconditional-break-and-local-vars/13")
 2239     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/14")
 2240     (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")
 2241     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-break-and-local-vars/16")
 2242     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/17")
 2243     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-break-and-local-vars/18")
 2244     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/19")
 2245     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-break-and-local-vars/20")
 2246     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-break-and-local-vars/21")
 2247     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-break-and-local-vars/22")
 2248     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-break-and-local-vars/23")
 2249     # . epilogue
 2250     89/<- %esp 5/r32/ebp
 2251     5d/pop-to-ebp
 2252     c3/return
 2253 
 2254 test-convert-function-with-nonlocal-unconditional-loop-and-local-vars:
 2255     # . prologue
 2256     55/push-ebp
 2257     89/<- %ebp 4/r32/esp
 2258     # setup
 2259     (clear-stream _test-input-stream)
 2260     (clear-stream $_test-input-buffered-file->buffer)
 2261     (clear-stream _test-output-stream)
 2262     (clear-stream $_test-output-buffered-file->buffer)
 2263     #
 2264     (write _test-input-stream "fn foo {\n")
 2265     (write _test-input-stream "  a: {\n")
 2266     (write _test-input-stream "    var x: int\n")
 2267     (write _test-input-stream "    {\n")
 2268     (write _test-input-stream "      var y: int\n")
 2269     (write _test-input-stream "      loop a\n")
 2270     (write _test-input-stream "      increment x\n")
 2271     (write _test-input-stream "    }\n")
 2272     (write _test-input-stream "  }\n")
 2273     (write _test-input-stream "}\n")
 2274     # convert
 2275     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2276     (flush _test-output-buffered-file)
 2277 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2283     # check output
 2284     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/0")
 2285     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/1")
 2286     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/2")
 2287     (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")
 2288     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/4")
 2289     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/5")
 2290     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/6")
 2291     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/7")
 2292     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/8")
 2293     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/9")
 2294     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/10")
 2295     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/11")
 2296     (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")
 2297     (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")
 2298     (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")
 2299     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/15")
 2300     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/16")
 2301     (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")
 2302     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/18")
 2303     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/19")
 2304     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/20")
 2305     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/21")
 2306     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/22")
 2307     (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")
 2308     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/24")
 2309     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/25")
 2310     # . epilogue
 2311     89/<- %esp 5/r32/ebp
 2312     5d/pop-to-ebp
 2313     c3/return
 2314 
 2315 test-convert-function-with-local-array-var-in-mem:
 2316     # . prologue
 2317     55/push-ebp
 2318     89/<- %ebp 4/r32/esp
 2319     # setup
 2320     (clear-stream _test-input-stream)
 2321     (clear-stream $_test-input-buffered-file->buffer)
 2322     (clear-stream _test-output-stream)
 2323     (clear-stream $_test-output-buffered-file->buffer)
 2324     #
 2325     (write _test-input-stream "fn foo {\n")
 2326     (write _test-input-stream "  var x: (array int 3)\n")
 2327     (write _test-input-stream "}\n")
 2328     # convert
 2329     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2330     (flush _test-output-buffered-file)
 2331 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2337     # check output
 2338     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-var-in-mem/0")
 2339     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-var-in-mem/1")
 2340     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-var-in-mem/2")
 2341     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-array-var-in-mem/3")
 2342     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-var-in-mem/4")
 2343     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-var-in-mem/5")
 2344     # define x
 2345     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-function-with-local-array-var-in-mem/7")
 2346     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-function-with-local-array-var-in-mem/8")
 2347     # reclaim x
 2348     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"  "F - test-convert-function-with-local-array-var-in-mem/9")
 2349     #
 2350     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-var-in-mem/10")
 2351     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-var-in-mem/11")
 2352     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-var-in-mem/12")
 2353     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-array-var-in-mem/13")
 2354     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-var-in-mem/14")
 2355     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-var-in-mem/15")
 2356     # . epilogue
 2357     89/<- %esp 5/r32/ebp
 2358     5d/pop-to-ebp
 2359     c3/return
 2360 
 2361 test-convert-address:
 2362     # . prologue
 2363     55/push-ebp
 2364     89/<- %ebp 4/r32/esp
 2365     # setup
 2366     (clear-stream _test-input-stream)
 2367     (clear-stream $_test-input-buffered-file->buffer)
 2368     (clear-stream _test-output-stream)
 2369     (clear-stream $_test-output-buffered-file->buffer)
 2370     #
 2371     (write _test-input-stream "fn foo {\n")
 2372     (write _test-input-stream "  var a: int\n")
 2373     (write _test-input-stream "  var b/eax: (addr int) <- address a\n")
 2374     (write _test-input-stream "}\n")
 2375     # convert
 2376     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2377     (flush _test-output-buffered-file)
 2378 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2384     # check output
 2385     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-address/0")
 2386     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-address/1")
 2387     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-address/2")
 2388     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-address/3")
 2389     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-address/4")
 2390     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-address/5")
 2391     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-address/6")
 2392     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-address/7")
 2393     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000000/r32"  "F - test-convert-address/8")
 2394     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-address/9")
 2395     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-address/10")
 2396     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-address/11")
 2397     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-address/12")
 2398     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-address/13")
 2399     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-address/14")
 2400     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-address/15")
 2401     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-address/16")
 2402     # . epilogue
 2403     89/<- %esp 5/r32/ebp
 2404     5d/pop-to-ebp
 2405     c3/return
 2406 
 2407 test-convert-length-of-array:
 2408     # . prologue
 2409     55/push-ebp
 2410     89/<- %ebp 4/r32/esp
 2411     # setup
 2412     (clear-stream _test-input-stream)
 2413     (clear-stream $_test-input-buffered-file->buffer)
 2414     (clear-stream _test-output-stream)
 2415     (clear-stream $_test-output-buffered-file->buffer)
 2416     #
 2417     (write _test-input-stream "fn foo a: (addr array int) {\n")
 2418     (write _test-input-stream "  var b/eax: (addr array int) <- copy a\n")
 2419     (write _test-input-stream "  var c/eax: int <- length b\n")
 2420     (write _test-input-stream "}\n")
 2421     # convert
 2422     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2423     (flush _test-output-buffered-file)
 2424 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2430     # check output
 2431     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array/0")
 2432     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array/1")
 2433     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array/2")
 2434     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array/3")
 2435     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array/4")
 2436     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array/5")
 2437     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array/6")
 2438     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array/7")
 2439     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array/8")
 2440     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array/9")
 2441     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array/10")
 2442     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array/11")
 2443     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array/12")
 2444     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array/13")
 2445     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array/14")
 2446     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array/15")
 2447     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array/16")
 2448     # . epilogue
 2449     89/<- %esp 5/r32/ebp
 2450     5d/pop-to-ebp
 2451     c3/return
 2452 
 2453 test-convert-length-of-array-on-stack:
 2454     # . prologue
 2455     55/push-ebp
 2456     89/<- %ebp 4/r32/esp
 2457     # setup
 2458     (clear-stream _test-input-stream)
 2459     (clear-stream $_test-input-buffered-file->buffer)
 2460     (clear-stream _test-output-stream)
 2461     (clear-stream $_test-output-buffered-file->buffer)
 2462     #
 2463     (write _test-input-stream "fn foo {\n")
 2464     (write _test-input-stream "  var a: (array int 3)\n")
 2465     (write _test-input-stream "  var b/eax: int <- length a\n")
 2466     (write _test-input-stream "}\n")
 2467     # convert
 2468     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2469     (flush _test-output-buffered-file)
 2470 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2476     # check output
 2477     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-on-stack/0")
 2478     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-on-stack/1")
 2479     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-on-stack/2")
 2480     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-on-stack/3")
 2481     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-on-stack/4")
 2482     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-on-stack/5")
 2483     # define x
 2484     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-length-of-array-on-stack/6")
 2485     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-length-of-array-on-stack/7")
 2486     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-on-stack/8")
 2487     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0xfffffff0) 0x00000000/r32"  "F - test-convert-length-of-array-on-stack/9")
 2488     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array-on-stack/10")
 2489     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-on-stack/11")
 2490     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"  "F - test-convert-length-of-array-on-stack/12")
 2491     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-on-stack/13")
 2492     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-on-stack/14")
 2493     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-on-stack/15")
 2494     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-on-stack/16")
 2495     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-on-stack/17")
 2496     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-on-stack/18")
 2497     # . epilogue
 2498     89/<- %esp 5/r32/ebp
 2499     5d/pop-to-ebp
 2500     c3/return
 2501 
 2502 test-convert-index-into-array:
 2503     # . prologue
 2504     55/push-ebp
 2505     89/<- %ebp 4/r32/esp
 2506     # setup
 2507     (clear-stream _test-input-stream)
 2508     (clear-stream $_test-input-buffered-file->buffer)
 2509     (clear-stream _test-output-stream)
 2510     (clear-stream $_test-output-buffered-file->buffer)
 2511     #
 2512     (write _test-input-stream "fn foo {\n")
 2513     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 2514     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 2515     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 2516     (write _test-input-stream "}\n")
 2517     # convert
 2518     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2519     (flush _test-output-buffered-file)
 2520 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2526     # check output
 2527     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array/0")
 2528     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array/1")
 2529     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array/2")
 2530     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array/3")
 2531     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array/4")
 2532     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array/5")
 2533     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array/6")
 2534     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array/7")
 2535     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array/8")
 2536     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array/9")
 2537     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32"  "F - test-convert-index-into-array/11")
 2538     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array/13")
 2539     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array/14")
 2540     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array/15")
 2541     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array/16")
 2542     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array/17")
 2543     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array/18")
 2544     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array/19")
 2545     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array/20")
 2546     # . epilogue
 2547     89/<- %esp 5/r32/ebp
 2548     5d/pop-to-ebp
 2549     c3/return
 2550 
 2551 test-convert-index-into-array-with-literal:
 2552     # . prologue
 2553     55/push-ebp
 2554     89/<- %ebp 4/r32/esp
 2555     # setup
 2556     (clear-stream _test-input-stream)
 2557     (clear-stream $_test-input-buffered-file->buffer)
 2558     (clear-stream _test-output-stream)
 2559     (clear-stream $_test-output-buffered-file->buffer)
 2560     #
 2561     (write _test-input-stream "fn foo {\n")
 2562     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 2563     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 2564     (write _test-input-stream "}\n")
 2565     # convert
 2566     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2567     (flush _test-output-buffered-file)
 2568 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2574     # check output
 2575     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-with-literal/0")
 2576     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-with-literal/1")
 2577     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-with-literal/2")
 2578     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-with-literal/3")
 2579     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-with-literal/4")
 2580     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-with-literal/5")
 2581     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-with-literal/6")
 2582     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-with-literal/7")
 2583                                                                                  # 2 * 4 bytes/elem + 4 bytes for size = offset 12
 2584     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x0000000c) 0x00000000/r32"  "F - test-convert-index-into-array-with-literal/8")
 2585     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-with-literal/9")
 2586     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-with-literal/10")
 2587     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-with-literal/11")
 2588     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-with-literal/12")
 2589     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-with-literal/13")
 2590     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-with-literal/14")
 2591     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-with-literal/15")
 2592     # . epilogue
 2593     89/<- %esp 5/r32/ebp
 2594     5d/pop-to-ebp
 2595     c3/return
 2596 
 2597 test-convert-index-into-array-on-stack:
 2598     # . prologue
 2599     55/push-ebp
 2600     89/<- %ebp 4/r32/esp
 2601     # setup
 2602     (clear-stream _test-input-stream)
 2603     (clear-stream $_test-input-buffered-file->buffer)
 2604     (clear-stream _test-output-stream)
 2605     (clear-stream $_test-output-buffered-file->buffer)
 2606     #
 2607     (write _test-input-stream "fn foo {\n")
 2608     (write _test-input-stream "  var arr: (array int 3)\n")
 2609     (write _test-input-stream "  var idx/eax: int <- copy 2\n")
 2610     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 2611     (write _test-input-stream "}\n")
 2612     # convert
 2613     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2614     (flush _test-output-buffered-file)
 2615 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2621     # check output
 2622     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack/0")
 2623     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack/1")
 2624     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack/2")
 2625     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack/3")
 2626     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack/4")
 2627     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack/5")
 2628     # var arr
 2629     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack/6")
 2630     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack/7")
 2631     # var idx
 2632     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack/8")
 2633     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 2/imm32"                  "F - test-convert-index-into-array-on-stack/9")
 2634     # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc
 2635     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp + eax<<0x00000002 + 0xfffffff4) 0x00000000/r32"  "F - test-convert-index-into-array-on-stack/10")
 2636     # reclaim idx
 2637     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack/11")
 2638     # reclaim arr
 2639     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"    "F - test-convert-index-into-array-on-stack/12")
 2640     #
 2641     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack/13")
 2642     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack/14")
 2643     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack/15")
 2644     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack/16")
 2645     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack/17")
 2646     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack/18")
 2647     # . epilogue
 2648     89/<- %esp 5/r32/ebp
 2649     5d/pop-to-ebp
 2650     c3/return
 2651 
 2652 test-convert-index-into-array-on-stack-with-literal:
 2653     # . prologue
 2654     55/push-ebp
 2655     89/<- %ebp 4/r32/esp
 2656     # setup
 2657     (clear-stream _test-input-stream)
 2658     (clear-stream $_test-input-buffered-file->buffer)
 2659     (clear-stream _test-output-stream)
 2660     (clear-stream $_test-output-buffered-file->buffer)
 2661     #
 2662     (write _test-input-stream "fn foo {\n")
 2663     (write _test-input-stream "  var arr: (array int 3)\n")
 2664     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 2665     (write _test-input-stream "}\n")
 2666     # convert
 2667     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2668     (flush _test-output-buffered-file)
 2669 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2675     # check output
 2676     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack-with-literal/0")
 2677     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack-with-literal/1")
 2678     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack-with-literal/2")
 2679     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack-with-literal/3")
 2680     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack-with-literal/4")
 2681     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack-with-literal/5")
 2682     # var arr
 2683     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack-with-literal/6")
 2684     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack-with-literal/7")
 2685     # var x
 2686     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack-with-literal/8")
 2687     # x is at (ebp-0x10) + 4 + 2*4 = ebp-4
 2688     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp + 0xfffffffc) 0x00000000/r32"  "F - test-convert-index-into-array-on-stack-with-literal/9")
 2689     # reclaim x
 2690     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack-with-literal/10")
 2691     # reclaim arr
 2692     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"    "F - test-convert-index-into-array-on-stack-with-literal/11")
 2693     #
 2694     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack-with-literal/12")
 2695     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack-with-literal/13")
 2696     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack-with-literal/14")
 2697     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack-with-literal/15")
 2698     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack-with-literal/16")
 2699     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack-with-literal/17")
 2700     # . epilogue
 2701     89/<- %esp 5/r32/ebp
 2702     5d/pop-to-ebp
 2703     c3/return
 2704 
 2705 test-convert-index-into-array-using-offset:
 2706     # . prologue
 2707     55/push-ebp
 2708     89/<- %ebp 4/r32/esp
 2709     # setup
 2710     (clear-stream _test-input-stream)
 2711     (clear-stream $_test-input-buffered-file->buffer)
 2712     (clear-stream _test-output-stream)
 2713     (clear-stream $_test-output-buffered-file->buffer)
 2714     #
 2715     (write _test-input-stream "fn foo {\n")
 2716     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 2717     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 2718     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 2719     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 2720     (write _test-input-stream "}\n")
 2721     # convert
 2722     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2723     (flush _test-output-buffered-file)
 2724 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2730     # check output
 2731     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset/0")
 2732     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset/1")
 2733     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset/2")
 2734     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset/3")
 2735     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset/4")
 2736     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset/5")
 2737     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset/6")
 2738     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-using-offset/7")
 2739     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset/8")
 2740     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-using-offset/9")
 2741     (check-next-stream-line-equal _test-output-stream "    69/multiply %ecx 0x00000004/imm32 0x00000001/r32"  "F - test-convert-index-into-array-using-offset/10")
 2742     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx + 4) 0x00000000/r32"  "F - test-convert-index-into-array-using-offset/11")
 2743     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset/12")
 2744     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset/13")
 2745     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset/14")
 2746     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset/15")
 2747     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset/16")
 2748     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset/17")
 2749     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset/18")
 2750     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset/19")
 2751     # . epilogue
 2752     89/<- %esp 5/r32/ebp
 2753     5d/pop-to-ebp
 2754     c3/return
 2755 
 2756 test-convert-index-into-array-using-offset-on-stack:
 2757     # . prologue
 2758     55/push-ebp
 2759     89/<- %ebp 4/r32/esp
 2760     # setup
 2761     (clear-stream _test-input-stream)
 2762     (clear-stream $_test-input-buffered-file->buffer)
 2763     (clear-stream _test-output-stream)
 2764     (clear-stream $_test-output-buffered-file->buffer)
 2765     #
 2766     (write _test-input-stream "fn foo {\n")
 2767     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 2768     (write _test-input-stream "  var idx: int\n")
 2769     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 2770     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 2771     (write _test-input-stream "}\n")
 2772     # convert
 2773     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2774     (flush _test-output-buffered-file)
 2775 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2781     # check output
 2782     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset-on-stack/0")
 2783     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset-on-stack/1")
 2784     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset-on-stack/2")
 2785     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset-on-stack/3")
 2786     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset-on-stack/4")
 2787     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset-on-stack/5")
 2788     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset-on-stack/6")
 2789     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-using-offset-on-stack/7")
 2790     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                         "F - test-convert-index-into-array-using-offset-on-stack/8")
 2791     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset-on-stack/9")
 2792     (check-next-stream-line-equal _test-output-stream "    69/multiply *(ebp+0xfffffff8) 0x00000004/imm32 0x00000001/r32"  "F - test-convert-index-into-array-using-offset-on-stack/10")
 2793     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx + 4) 0x00000000/r32"  "F - test-convert-index-into-array-using-offset-on-stack/11")
 2794     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset-on-stack/12")
 2795     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"    "F - test-convert-index-into-array-using-offset-on-stack/13")
 2796     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset-on-stack/14")
 2797     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset-on-stack/15")
 2798     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset-on-stack/16")
 2799     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset-on-stack/17")
 2800     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset-on-stack/18")
 2801     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset-on-stack/19")
 2802     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset-on-stack/20")
 2803     # . epilogue
 2804     89/<- %esp 5/r32/ebp
 2805     5d/pop-to-ebp
 2806     c3/return
 2807 
 2808 test-convert-function-and-type-definition:
 2809     # . prologue
 2810     55/push-ebp
 2811     89/<- %ebp 4/r32/esp
 2812     # setup
 2813     (clear-stream _test-input-stream)
 2814     (clear-stream $_test-input-buffered-file->buffer)
 2815     (clear-stream _test-output-stream)
 2816     (clear-stream $_test-output-buffered-file->buffer)
 2817     #
 2818     (write _test-input-stream "fn foo a: (addr t) {\n")
 2819     (write _test-input-stream "  var _a/eax: (addr t) <- copy a\n")
 2820     (write _test-input-stream "  var b/ecx: (addr int) <- get _a, x\n")
 2821     (write _test-input-stream "  var c/ecx: (addr int) <- get _a, y\n")
 2822     (write _test-input-stream "}\n")
 2823     (write _test-input-stream "type t {\n")
 2824     (write _test-input-stream "  x: int\n")
 2825     (write _test-input-stream "  y: int\n")
 2826     (write _test-input-stream "}\n")
 2827     # convert
 2828     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2829     (flush _test-output-buffered-file)
 2830 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2836     # check output
 2837     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-and-type-definition/0")
 2838     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-and-type-definition/1")
 2839     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-and-type-definition/2")
 2840     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-and-type-definition/3")
 2841     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-and-type-definition/4")
 2842     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-and-type-definition/5")
 2843     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-and-type-definition/6")
 2844     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-and-type-definition/7")
 2845     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-and-type-definition/8")
 2846     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000000) 0x00000001/r32"  "F - test-convert-function-and-type-definition/9")
 2847     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000004) 0x00000001/r32"  "F - test-convert-function-and-type-definition/11")
 2848     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-and-type-definition/13")
 2849     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-and-type-definition/14")
 2850     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-and-type-definition/15")
 2851     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-and-type-definition/16")
 2852     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-and-type-definition/17")
 2853     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-and-type-definition/18")
 2854     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-and-type-definition/19")
 2855     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-and-type-definition/20")
 2856     # . epilogue
 2857     89/<- %esp 5/r32/ebp
 2858     5d/pop-to-ebp
 2859     c3/return
 2860 
 2861 test-convert-function-with-local-var-with-user-defined-type:
 2862     # . prologue
 2863     55/push-ebp
 2864     89/<- %ebp 4/r32/esp
 2865     # setup
 2866     (clear-stream _test-input-stream)
 2867     (clear-stream $_test-input-buffered-file->buffer)
 2868     (clear-stream _test-output-stream)
 2869     (clear-stream $_test-output-buffered-file->buffer)
 2870     #
 2871     (write _test-input-stream "fn foo {\n")
 2872     (write _test-input-stream "  var a: t\n")
 2873     (write _test-input-stream "}\n")
 2874     (write _test-input-stream "type t {\n")
 2875     (write _test-input-stream "  x: int\n")
 2876     (write _test-input-stream "  y: int\n")
 2877     (write _test-input-stream "}\n")
 2878     # convert
 2879     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2880     (flush _test-output-buffered-file)
 2881 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2887     # check output
 2888     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-user-defined-type/0")
 2889     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-user-defined-type/1")
 2890     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-user-defined-type/2")
 2891     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-with-user-defined-type/3")
 2892     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type/4")
 2893     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-user-defined-type/5")
 2894     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/6")
 2895     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/7")
 2896     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-function-with-local-var-with-user-defined-type/8")
 2897     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type/9")
 2898     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-user-defined-type/10")
 2899     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-user-defined-type/11")
 2900     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-with-user-defined-type/12")
 2901     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-user-defined-type/13")
 2902     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-user-defined-type/14")
 2903     # . epilogue
 2904     89/<- %esp 5/r32/ebp
 2905     5d/pop-to-ebp
 2906     c3/return
 2907 
 2908 test-convert-function-call-with-arg-of-user-defined-type:
 2909     # . prologue
 2910     55/push-ebp
 2911     89/<- %ebp 4/r32/esp
 2912     # setup
 2913     (clear-stream _test-input-stream)
 2914     (clear-stream $_test-input-buffered-file->buffer)
 2915     (clear-stream _test-output-stream)
 2916     (clear-stream $_test-output-buffered-file->buffer)
 2917     #
 2918     (write _test-input-stream "fn f {\n")
 2919     (write _test-input-stream "  var a: t\n")
 2920     (write _test-input-stream "  foo a\n")
 2921     (write _test-input-stream "}\n")
 2922     (write _test-input-stream "fn foo x: t {\n")
 2923     (write _test-input-stream "}\n")
 2924     (write _test-input-stream "type t {\n")
 2925     (write _test-input-stream "  x: int\n")
 2926     (write _test-input-stream "  y: int\n")
 2927     (write _test-input-stream "}\n")
 2928     # convert
 2929     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2930     (flush _test-output-buffered-file)
 2931 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2937     # check output
 2938     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 2939     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 2940     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 2941     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-arg-of-user-defined-type/3")
 2942     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 2943     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 2944     # var a: t
 2945     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/6")
 2946     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/7")
 2947     # foo a
 2948     (check-next-stream-line-equal _test-output-stream "    (foo *(ebp+0xfffffff8) *(ebp+0xfffffffc))"  "F - test-convert-function-call-with-arg-of-user-defined-type/8")
 2949     #
 2950     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-function-call-with-arg-of-user-defined-type/9")
 2951     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 2952     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 2953     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 2954     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-arg-of-user-defined-type/13")
 2955     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 2956     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 2957     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 2958     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 2959     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 2960     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-arg-of-user-defined-type/19")
 2961     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 2962     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-arg-of-user-defined-type/21")
 2963     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 2964     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 2965     # . epilogue
 2966     89/<- %esp 5/r32/ebp
 2967     5d/pop-to-ebp
 2968     c3/return
 2969 
 2970 test-convert-function-call-with-arg-of-user-defined-type-register-indirect:
 2971     # . prologue
 2972     55/push-ebp
 2973     89/<- %ebp 4/r32/esp
 2974     # setup
 2975     (clear-stream _test-input-stream)
 2976     (clear-stream $_test-input-buffered-file->buffer)
 2977     (clear-stream _test-output-stream)
 2978     (clear-stream $_test-output-buffered-file->buffer)
 2979     #
 2980     (write _test-input-stream "fn f {\n")
 2981     (write _test-input-stream "  var a/eax: (addr t) <- copy 0\n")
 2982     (write _test-input-stream "  foo *a\n")
 2983     (write _test-input-stream "}\n")
 2984     (write _test-input-stream "fn foo x: t {\n")
 2985     (write _test-input-stream "}\n")
 2986     (write _test-input-stream "type t {\n")
 2987     (write _test-input-stream "  x: int\n")
 2988     (write _test-input-stream "  y: int\n")
 2989     (write _test-input-stream "}\n")
 2990     # convert
 2991     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2992     (flush _test-output-buffered-file)
 2993 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2999     # check output
 3000     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 3001     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 3002     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 3003     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-arg-of-user-defined-type/3")
 3004     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 3005     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 3006     # var a
 3007     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-call-with-arg-of-user-defined-type/6")
 3008     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"  "F - test-convert-function-call-with-arg-of-user-defined-type/7")
 3009     # foo a
 3010     (check-next-stream-line-equal _test-output-stream "    (foo *(eax+0x00000000) *(eax+0x00000004))"  "F - test-convert-function-call-with-arg-of-user-defined-type/8")
 3011     #
 3012     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-call-with-arg-of-user-defined-type/9")
 3013     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 3014     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 3015     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 3016     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-arg-of-user-defined-type/13")
 3017     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 3018     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 3019     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 3020     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 3021     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 3022     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-arg-of-user-defined-type/19")
 3023     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 3024     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-arg-of-user-defined-type/21")
 3025     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 3026     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 3027     # . epilogue
 3028     89/<- %esp 5/r32/ebp
 3029     5d/pop-to-ebp
 3030     c3/return
 3031 
 3032 # we don't have special support for call-by-reference; just explicitly create
 3033 # a new variable with the address of the arg
 3034 test-convert-function-call-with-arg-of-user-defined-type-by-reference:
 3035     # . prologue
 3036     55/push-ebp
 3037     89/<- %ebp 4/r32/esp
 3038     # setup
 3039     (clear-stream _test-input-stream)
 3040     (clear-stream $_test-input-buffered-file->buffer)
 3041     (clear-stream _test-output-stream)
 3042     (clear-stream $_test-output-buffered-file->buffer)
 3043     #
 3044     (write _test-input-stream "fn f {\n")
 3045     (write _test-input-stream "  var a: t\n")
 3046     (write _test-input-stream "  var b/eax: (addr t) <- address a\n")
 3047     (write _test-input-stream "  foo b\n")
 3048     (write _test-input-stream "}\n")
 3049     (write _test-input-stream "fn foo x: (addr t) {\n")
 3050     (write _test-input-stream "  var x/ecx: (addr int) <- copy x\n")
 3051     (write _test-input-stream "  increment *x\n")
 3052     (write _test-input-stream "}\n")
 3053     (write _test-input-stream "type t {\n")
 3054     (write _test-input-stream "  x: int\n")
 3055     (write _test-input-stream "  y: int\n")
 3056     (write _test-input-stream "}\n")
 3057     # convert
 3058     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3059     (flush _test-output-buffered-file)
 3060 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3066     # check output
 3067     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/0")
 3068     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/1")
 3069     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/2")
 3070     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/3")
 3071     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/4")
 3072     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/5")
 3073     # var a: t
 3074     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/6")
 3075     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/7")
 3076     # var b/eax: (addr t)
 3077     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/8")
 3078     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffff8) 0x00000000/r32"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/9")
 3079     # foo a
 3080     (check-next-stream-line-equal _test-output-stream "    (foo %eax)"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/10")
 3081     #
 3082     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/11")
 3083     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/12")
 3084     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/13")
 3085     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/14")
 3086     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/15")
 3087     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/16")
 3088     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/17")
 3089     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/18")
 3090     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/19")
 3091     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/20")
 3092     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/21")
 3093     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/22")
 3094     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/23")
 3095     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/24")
 3096     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/25")
 3097     (check-next-stream-line-equal _test-output-stream "    89/<- %ecx 0x00000001/r32"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/26")
 3098     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *ecx"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/27")
 3099     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/28")
 3100     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/29")
 3101     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/30")
 3102     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/31")
 3103     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/32")
 3104     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/33")
 3105     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/34")
 3106     # . epilogue
 3107     89/<- %esp 5/r32/ebp
 3108     5d/pop-to-ebp
 3109     c3/return
 3110 
 3111 test-convert-get-on-local-variable:
 3112     # . prologue
 3113     55/push-ebp
 3114     89/<- %ebp 4/r32/esp
 3115     # setup
 3116     (clear-stream _test-input-stream)
 3117     (clear-stream $_test-input-buffered-file->buffer)
 3118     (clear-stream _test-output-stream)
 3119     (clear-stream $_test-output-buffered-file->buffer)
 3120     #
 3121     (write _test-input-stream "fn foo {\n")
 3122     (write _test-input-stream "  var a: t\n")
 3123     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 3124     (write _test-input-stream "}\n")
 3125     (write _test-input-stream "type t {\n")
 3126     (write _test-input-stream "  x: int\n")
 3127     (write _test-input-stream "  y: int\n")
 3128     (write _test-input-stream "}\n")
 3129     # convert
 3130     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3131     (flush _test-output-buffered-file)
 3132 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3138     # check output
 3139     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-local-variable/0")
 3140     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-local-variable/1")
 3141     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-local-variable/2")
 3142     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-local-variable/3")
 3143     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-local-variable/4")
 3144     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-local-variable/5")
 3145     # var a
 3146     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/6")
 3147     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/7")
 3148     # var c
 3149     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-local-variable/8")
 3150     # get
 3151     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32"  "F - test-convert-get-on-local-variable/9")
 3152     # reclaim c
 3153     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-local-variable/10")
 3154     # reclaim a
 3155     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-get-on-local-variable/11")
 3156     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-local-variable/12")
 3157     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-local-variable/13")
 3158     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-local-variable/14")
 3159     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-local-variable/15")
 3160     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-local-variable/16")
 3161     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-local-variable/17")
 3162     # . epilogue
 3163     89/<- %esp 5/r32/ebp
 3164     5d/pop-to-ebp
 3165     c3/return
 3166 
 3167 test-convert-get-on-function-argument:
 3168     # . prologue
 3169     55/push-ebp
 3170     89/<- %ebp 4/r32/esp
 3171     # setup
 3172     (clear-stream _test-input-stream)
 3173     (clear-stream $_test-input-buffered-file->buffer)
 3174     (clear-stream _test-output-stream)
 3175     (clear-stream $_test-output-buffered-file->buffer)
 3176     #
 3177     (write _test-input-stream "fn foo a: t {\n")
 3178     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 3179     (write _test-input-stream "}\n")
 3180     (write _test-input-stream "type t {\n")
 3181     (write _test-input-stream "  x: int\n")
 3182     (write _test-input-stream "  y: int\n")
 3183     (write _test-input-stream "}\n")
 3184     # convert
 3185     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3186     (flush _test-output-buffered-file)
 3187 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3193     # check output
 3194     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument/0")
 3195     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument/1")
 3196     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument/2")
 3197     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument/3")
 3198     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument/4")
 3199     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument/5")
 3200     # var c
 3201     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument/6")
 3202     # get
 3203     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0x0000000c) 0x00000001/r32"  "F - test-convert-get-on-function-argument/7")
 3204     # reclaim c
 3205     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument/8")
 3206     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument/9")
 3207     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument/10")
 3208     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument/11")
 3209     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument/12")
 3210     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument/13")
 3211     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument/14")
 3212     # . epilogue
 3213     89/<- %esp 5/r32/ebp
 3214     5d/pop-to-ebp
 3215     c3/return
 3216 
 3217 test-convert-get-on-function-argument-with-known-type:
 3218     # . prologue
 3219     55/push-ebp
 3220     89/<- %ebp 4/r32/esp
 3221     # setup
 3222     (clear-stream _test-input-stream)
 3223     (clear-stream $_test-input-buffered-file->buffer)
 3224     (clear-stream _test-output-stream)
 3225     (clear-stream $_test-output-buffered-file->buffer)
 3226     #
 3227     (write _test-input-stream "type t {\n")
 3228     (write _test-input-stream "  x: int\n")
 3229     (write _test-input-stream "  y: int\n")
 3230     (write _test-input-stream "}\n")
 3231     (write _test-input-stream "fn foo a: t {\n")
 3232     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 3233     (write _test-input-stream "}\n")
 3234     # convert
 3235     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3236     (flush _test-output-buffered-file)
 3237 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3243     # check output
 3244     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument-with-known-type/0")
 3245     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument-with-known-type/1")
 3246     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument-with-known-type/2")
 3247     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument-with-known-type/3")
 3248     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument-with-known-type/4")
 3249     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument-with-known-type/5")
 3250     # var c
 3251     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument-with-known-type/6")
 3252     # get
 3253     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0x0000000c) 0x00000001/r32"  "F - test-convert-get-on-function-argument-with-known-type/7")
 3254     # reclaim c
 3255     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument-with-known-type/8")
 3256     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument-with-known-type/9")
 3257     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument-with-known-type/10")
 3258     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument-with-known-type/11")
 3259     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument-with-known-type/12")
 3260     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument-with-known-type/13")
 3261     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument-with-known-type/14")
 3262     # . epilogue
 3263     89/<- %esp 5/r32/ebp
 3264     5d/pop-to-ebp
 3265     c3/return
 3266 
 3267 test-convert-array-of-user-defined-types:
 3268     # . prologue
 3269     55/push-ebp
 3270     89/<- %ebp 4/r32/esp
 3271     # setup
 3272     (clear-stream _test-input-stream)
 3273     (clear-stream $_test-input-buffered-file->buffer)
 3274     (clear-stream _test-output-stream)
 3275     (clear-stream $_test-output-buffered-file->buffer)
 3276     #
 3277     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 3278     (write _test-input-stream "  x: int\n")
 3279     (write _test-input-stream "  y: int\n")
 3280     (write _test-input-stream "}\n")
 3281     (write _test-input-stream "fn foo {\n")
 3282     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 3283     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 3284     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 3285     (write _test-input-stream "}\n")
 3286     # convert
 3287     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3288     (flush _test-output-buffered-file)
 3289 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3295     # check output
 3296     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-array-of-user-defined-types/0")
 3297     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-array-of-user-defined-types/1")
 3298     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-array-of-user-defined-types/2")
 3299     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-array-of-user-defined-types/3")
 3300     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-array-of-user-defined-types/4")
 3301     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-array-of-user-defined-types/5")
 3302     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-array-of-user-defined-types/6")
 3303     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-array-of-user-defined-types/7")
 3304     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-array-of-user-defined-types/8")
 3305     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-array-of-user-defined-types/9")
 3306     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000003 + 4) 0x00000000/r32"  "F - test-convert-array-of-user-defined-types/11")
 3307     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-array-of-user-defined-types/13")
 3308     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-array-of-user-defined-types/14")
 3309     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-array-of-user-defined-types/15")
 3310     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-array-of-user-defined-types/16")
 3311     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-array-of-user-defined-types/17")
 3312     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-array-of-user-defined-types/18")
 3313     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-array-of-user-defined-types/19")
 3314     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-array-of-user-defined-types/20")
 3315     # . epilogue
 3316     89/<- %esp 5/r32/ebp
 3317     5d/pop-to-ebp
 3318     c3/return
 3319 
 3320 test-convert-length-of-array-of-user-defined-types-to-eax:
 3321     # . prologue
 3322     55/push-ebp
 3323     89/<- %ebp 4/r32/esp
 3324     # setup
 3325     (clear-stream _test-input-stream)
 3326     (clear-stream $_test-input-buffered-file->buffer)
 3327     (clear-stream _test-output-stream)
 3328     (clear-stream $_test-output-buffered-file->buffer)
 3329     #
 3330     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 3331     (write _test-input-stream "  x: int\n")
 3332     (write _test-input-stream "  y: int\n")
 3333     (write _test-input-stream "  z: int\n")
 3334     (write _test-input-stream "}\n")
 3335     (write _test-input-stream "fn foo {\n")
 3336     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 3337     (write _test-input-stream "  var x/eax: (addr t) <- length arr\n")
 3338     (write _test-input-stream "}\n")
 3339     # convert
 3340     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3341     (flush _test-output-buffered-file)
 3342 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3348     # check output
 3349     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-eax/0")
 3350     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/1")
 3351     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-eax/2")
 3352     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/3")
 3353     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/4")
 3354     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-eax/5")
 3355     # var arr
 3356     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/6")
 3357     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/7")
 3358     # length instruction
 3359     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/8")
 3360     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/9")
 3361     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/10")
 3362     (check-next-stream-line-equal _test-output-stream "    31/xor %edx 2/r32/edx"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/11")
 3363     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x0000000c/imm32"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/12")
 3364     (check-next-stream-line-equal _test-output-stream "    f7 7/subop/idiv-eax-edx-by %ecx"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/13")
 3365     (check-next-stream-line-equal _test-output-stream "    5a/pop-to-edx"       "F - test-convert-length-of-array-of-user-defined-types-to-eax/14")
 3366     (check-next-stream-line-equal _test-output-stream "    59/pop-to-ecx"       "F - test-convert-length-of-array-of-user-defined-types-to-eax/15")
 3367     # reclaim arr
 3368     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/16")
 3369     #
 3370     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/17")
 3371     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/18")
 3372     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/19")
 3373     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/20")
 3374     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/21")
 3375     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-eax/22")
 3376     # . epilogue
 3377     89/<- %esp 5/r32/ebp
 3378     5d/pop-to-ebp
 3379     c3/return
 3380 
 3381 test-convert-length-of-array-of-user-defined-types-to-ecx:
 3382     # . prologue
 3383     55/push-ebp
 3384     89/<- %ebp 4/r32/esp
 3385     # setup
 3386     (clear-stream _test-input-stream)
 3387     (clear-stream $_test-input-buffered-file->buffer)
 3388     (clear-stream _test-output-stream)
 3389     (clear-stream $_test-output-buffered-file->buffer)
 3390     #
 3391     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 3392     (write _test-input-stream "  x: int\n")
 3393     (write _test-input-stream "  y: int\n")
 3394     (write _test-input-stream "  z: int\n")
 3395     (write _test-input-stream "}\n")
 3396     (write _test-input-stream "fn foo {\n")
 3397     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 3398     (write _test-input-stream "  var x/ecx: (addr t) <- length arr\n")
 3399     (write _test-input-stream "}\n")
 3400     # convert
 3401     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3402     (flush _test-output-buffered-file)
 3403 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3409     # check output
 3410     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-ecx/0")
 3411     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/1")
 3412     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-ecx/2")
 3413     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/3")
 3414     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/4")
 3415     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-ecx/5")
 3416     # var a
 3417     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/6")
 3418     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/7")
 3419     # var x
 3420     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/8")
 3421     # length instruction
 3422     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/9")
 3423     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/10")
 3424     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/11")
 3425     (check-next-stream-line-equal _test-output-stream "    31/xor %edx 2/r32/edx"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/12")
 3426     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x0000000c/imm32"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/13")
 3427     (check-next-stream-line-equal _test-output-stream "    f7 7/subop/idiv-eax-edx-by %ecx"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/14")
 3428     (check-next-stream-line-equal _test-output-stream "    89/<- %ecx 0/r32/eax"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/15")
 3429     (check-next-stream-line-equal _test-output-stream "    5a/pop-to-edx"       "F - test-convert-length-of-array-of-user-defined-types-to-ecx/16")
 3430     (check-next-stream-line-equal _test-output-stream "    58/pop-to-eax"       "F - test-convert-length-of-array-of-user-defined-types-to-ecx/17")
 3431     # reclaim x
 3432     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/18")
 3433     # reclaim a
 3434     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/19")
 3435     #
 3436     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/20")
 3437     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/21")
 3438     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/22")
 3439     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/23")
 3440     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/24")
 3441     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-ecx/25")
 3442     # . epilogue
 3443     89/<- %esp 5/r32/ebp
 3444     5d/pop-to-ebp
 3445     c3/return
 3446 
 3447 test-convert-length-of-array-of-user-defined-types-to-edx:
 3448     # . prologue
 3449     55/push-ebp
 3450     89/<- %ebp 4/r32/esp
 3451     # setup
 3452     (clear-stream _test-input-stream)
 3453     (clear-stream $_test-input-buffered-file->buffer)
 3454     (clear-stream _test-output-stream)
 3455     (clear-stream $_test-output-buffered-file->buffer)
 3456     #
 3457     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 3458     (write _test-input-stream "  x: int\n")
 3459     (write _test-input-stream "  y: int\n")
 3460     (write _test-input-stream "  z: int\n")
 3461     (write _test-input-stream "}\n")
 3462     (write _test-input-stream "fn foo {\n")
 3463     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 3464     (write _test-input-stream "  var x/edx: (addr t) <- length arr\n")
 3465     (write _test-input-stream "}\n")
 3466     # convert
 3467     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3468     (flush _test-output-buffered-file)
 3469 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3475     # check output
 3476     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-edx/0")
 3477     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/1")
 3478     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-edx/2")
 3479     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/3")
 3480     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/4")
 3481     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-edx/5")
 3482     # var a
 3483     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/6")
 3484     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/7")
 3485     # var x
 3486     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %edx"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/8")
 3487     # length instruction
 3488     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/9")
 3489     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/10")
 3490     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/11")
 3491     (check-next-stream-line-equal _test-output-stream "    31/xor %edx 2/r32/edx"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/12")
 3492     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x0000000c/imm32"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/13")
 3493     (check-next-stream-line-equal _test-output-stream "    f7 7/subop/idiv-eax-edx-by %ecx"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/14")
 3494     (check-next-stream-line-equal _test-output-stream "    89/<- %edx 0/r32/eax"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/15")
 3495     (check-next-stream-line-equal _test-output-stream "    59/pop-to-ecx"       "F - test-convert-length-of-array-of-user-defined-types-to-edx/16")
 3496     (check-next-stream-line-equal _test-output-stream "    58/pop-to-eax"       "F - test-convert-length-of-array-of-user-defined-types-to-edx/17")
 3497     # reclaim x
 3498     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %edx"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/18")
 3499     # reclaim a
 3500     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/19")
 3501     #
 3502     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/20")
 3503     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/21")
 3504     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/22")
 3505     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/23")
 3506     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/24")
 3507     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-edx/25")
 3508     # . epilogue
 3509     89/<- %esp 5/r32/ebp
 3510     5d/pop-to-ebp
 3511     c3/return
 3512 
 3513 test-convert-length-of-array-of-user-defined-types:
 3514     # . prologue
 3515     55/push-ebp
 3516     89/<- %ebp 4/r32/esp
 3517     # setup
 3518     (clear-stream _test-input-stream)
 3519     (clear-stream $_test-input-buffered-file->buffer)
 3520     (clear-stream _test-output-stream)
 3521     (clear-stream $_test-output-buffered-file->buffer)
 3522     #
 3523     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 3524     (write _test-input-stream "  x: int\n")
 3525     (write _test-input-stream "  y: int\n")
 3526     (write _test-input-stream "  z: int\n")
 3527     (write _test-input-stream "}\n")
 3528     (write _test-input-stream "fn foo {\n")
 3529     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 3530     (write _test-input-stream "  var x/ebx: (addr t) <- length arr\n")
 3531     (write _test-input-stream "}\n")
 3532     # convert
 3533     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3534     (flush _test-output-buffered-file)
 3535 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3541     # check output
 3542     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types/0")
 3543     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types/1")
 3544     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types/2")
 3545     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types/3")
 3546     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types/4")
 3547     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types/5")
 3548     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types/6")
 3549     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"  "F - test-convert-length-of-array-of-user-defined-types/7")
 3550     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ebx"  "F - test-convert-length-of-array-of-user-defined-types/8")
 3551     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types/9")
 3552     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types/10")
 3553     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types/11")
 3554     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types/12")
 3555     (check-next-stream-line-equal _test-output-stream "    31/xor %edx 2/r32/edx"  "F - test-convert-length-of-array-of-user-defined-types/13")
 3556     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x0000000c/imm32"  "F - test-convert-length-of-array-of-user-defined-types/14")
 3557     (check-next-stream-line-equal _test-output-stream "    f7 7/subop/idiv-eax-edx-by %ecx"  "F - test-convert-length-of-array-of-user-defined-types/15")
 3558     (check-next-stream-line-equal _test-output-stream "    89/<- %ebx 0/r32/eax"  "F - test-convert-length-of-array-of-user-defined-types/16")
 3559     (check-next-stream-line-equal _test-output-stream "    5a/pop-to-edx"       "F - test-convert-length-of-array-of-user-defined-types/17")
 3560     (check-next-stream-line-equal _test-output-stream "    59/pop-to-ecx"       "F - test-convert-length-of-array-of-user-defined-types/18")
 3561     (check-next-stream-line-equal _test-output-stream "    58/pop-to-eax"       "F - test-convert-length-of-array-of-user-defined-types/19")
 3562     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ebx"  "F - test-convert-length-of-array-of-user-defined-types/20")
 3563     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types/21")
 3564     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types/22")
 3565     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types/23")
 3566     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types/24")
 3567     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types/25")
 3568     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types/26")
 3569     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types/27")
 3570     # . epilogue
 3571     89/<- %esp 5/r32/ebp
 3572     5d/pop-to-ebp
 3573     c3/return
 3574 
 3575 #######################################################
 3576 # Parsing
 3577 #######################################################
 3578 
 3579 parse-mu:  # in: (addr buffered-file)
 3580     # pseudocode
 3581     #   var curr-function: (addr handle function) = Program->functions
 3582     #   var curr-type: (addr handle typeinfo) = Program->types
 3583     #   var line: (stream byte 512)
 3584     #   var word-slice: slice
 3585     #   while true                                  # line loop
 3586     #     clear-stream(line)
 3587     #     read-line-buffered(in, line)
 3588     #     if (line->write == 0) break               # end of file
 3589     #     word-slice = next-mu-token(line)
 3590     #     if slice-empty?(word-slice)               # end of line
 3591     #       continue
 3592     #     else if slice-starts-with?(word-slice, "#")  # comment
 3593     #       continue                                # end of line
 3594     #     else if slice-equal?(word-slice, "fn")
 3595     #       var new-function: (handle function) = allocate(function)
 3596     #       var vars: (stack (handle var) 256)
 3597     #       populate-mu-function-header(line, new-function, vars)
 3598     #       populate-mu-function-body(in, new-function, vars)
 3599     #       assert(vars->top == 0)
 3600     #       *curr-function = new-function
 3601     #       curr-function = &new-function->next
 3602     #     else if slice-equal?(word-slice, "type")
 3603     #       word-slice = next-mu-token(line)
 3604     #       type-id = pos-or-insert-slice(Type-id, word-slice)
 3605     #       var new-type: (handle typeinfo) = find-or-create-typeinfo(type-id)
 3606     #       assert(next-word(line) == "{")
 3607     #       populate-mu-type(in, new-type)
 3608     #     else
 3609     #       abort()
 3610     #
 3611     # . prologue
 3612     55/push-ebp
 3613     89/<- %ebp 4/r32/esp
 3614     # . save registers
 3615     50/push-eax
 3616     51/push-ecx
 3617     52/push-edx
 3618     53/push-ebx
 3619     56/push-esi
 3620     57/push-edi
 3621     # var line/ecx: (stream byte 512)
 3622     81 5/subop/subtract %esp 0x200/imm32
 3623     68/push 0x200/imm32/size
 3624     68/push 0/imm32/read
 3625     68/push 0/imm32/write
 3626     89/<- %ecx 4/r32/esp
 3627     # var word-slice/edx: slice
 3628     68/push 0/imm32/end
 3629     68/push 0/imm32/start
 3630     89/<- %edx 4/r32/esp
 3631     # var curr-function/edi: (addr handle function)
 3632     bf/copy-to-edi _Program-functions/imm32
 3633     # var vars/ebx: (stack (handle var) 256)
 3634     81 5/subop/subtract %esp 0x800/imm32
 3635     68/push 0x800/imm32/size
 3636     68/push 0/imm32/top
 3637     89/<- %ebx 4/r32/esp
 3638     {
 3639 $parse-mu:line-loop:
 3640       (clear-stream %ecx)
 3641       (read-line-buffered *(ebp+8) %ecx)
 3642       # if (line->write == 0) break
 3643       81 7/subop/compare *ecx 0/imm32
 3644       0f 84/jump-if-= break/disp32
 3645 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
 3651       (next-mu-token %ecx %edx)
 3652       # if slice-empty?(word-slice) continue
 3653       (slice-empty? %edx)  # => eax
 3654       3d/compare-eax-and 0/imm32/false
 3655       0f 85/jump-if-!= loop/disp32
 3656       # if (*word-slice->start == "#") continue
 3657       # . eax = *word-slice->start
 3658       8b/-> *edx 0/r32/eax
 3659       8a/copy-byte *eax 0/r32/AL
 3660       81 4/subop/and %eax 0xff/imm32
 3661       # . if (eax == '#') continue
 3662       3d/compare-eax-and 0x23/imm32/hash
 3663       0f 84/jump-if-= loop/disp32
 3664       # if (slice-equal?(word-slice, "fn")) parse a function
 3665       {
 3666 $parse-mu:fn:
 3667         (slice-equal? %edx "fn")  # => eax
 3668         3d/compare-eax-and 0/imm32/false
 3669         0f 84/jump-if-= break/disp32
 3670         # var new-function/esi: (handle function)
 3671         68/push 0/imm32
 3672         68/push 0/imm32
 3673         89/<- %esi 4/r32/esp
 3674         # populate-mu-function(line, in, vars, new-function)
 3675         (allocate Heap *Function-size %esi)
 3676         # var new-function-addr/eax: (addr function)
 3677         (lookup *esi *(esi+4))  # => eax
 3678         (clear-stack %ebx)
 3679         (populate-mu-function-header %ecx %eax %ebx)
 3680         (populate-mu-function-body *(ebp+8) %eax %ebx)
 3681         # *curr-function = new-function
 3682         8b/-> *esi 0/r32/eax
 3683         89/<- *edi 0/r32/eax
 3684         8b/-> *(esi+4) 0/r32/eax
 3685         89/<- *(edi+4) 0/r32/eax
 3686         # curr-function = &new-function->next
 3687         # . var tmp/eax: (addr function) = lookup(new-function)
 3688         (lookup *esi *(esi+4))  # => eax
 3689         # . curr-function = &tmp->next
 3690         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 3691         # reclaim new-function
 3692         81 0/subop/add %esp 8/imm32
 3693         #
 3694         e9/jump $parse-mu:line-loop/disp32
 3695       }
 3696       # if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition
 3697       {
 3698 $parse-mu:type:
 3699         (slice-equal? %edx "type")  # => eax
 3700         3d/compare-eax-and 0/imm32
 3701         0f 84/jump-if-= break/disp32
 3702         (next-mu-token %ecx %edx)
 3703         # var type-id/eax: int
 3704         (pos-or-insert-slice Type-id %edx)  # => eax
 3705         # spill
 3706         51/push-ecx
 3707         # var new-type/ecx: (handle typeinfo)
 3708         68/push 0/imm32
 3709         68/push 0/imm32
 3710         89/<- %ecx 4/r32/esp
 3711         (find-or-create-typeinfo %eax %ecx)
 3712         #
 3713         (lookup *ecx *(ecx+4))  # => eax
 3714         # TODO: ensure that 'line' has nothing else but '{'
 3715 #? (dump-typeinfos "=== aaa\n")
 3716         (populate-mu-type *(ebp+8) %eax)  # => eax
 3717 #? (dump-typeinfos "=== zzz\n")
 3718         # reclaim new-type
 3719         81 0/subop/add %esp 8/imm32
 3720         # restore
 3721         59/pop-to-ecx
 3722         e9/jump $parse-mu:line-loop/disp32
 3723       }
 3724       # otherwise abort
 3725       e9/jump $parse-mu:error1/disp32
 3726     } # end line loop
 3727 $parse-mu:end:
 3728     # . reclaim locals
 3729     81 0/subop/add %esp 0x630/imm32
 3730     # . restore registers
 3731     5f/pop-to-edi
 3732     5e/pop-to-esi
 3733     5b/pop-to-ebx
 3734     5a/pop-to-edx
 3735     59/pop-to-ecx
 3736     58/pop-to-eax
 3737     # . epilogue
 3738     89/<- %esp 5/r32/ebp
 3739     5d/pop-to-ebp
 3740     c3/return
 3741 
 3742 $parse-mu:error1:
 3743     # error("unexpected top-level command: " word-slice "\n")
 3744     (write-buffered Stderr "unexpected top-level command: ")
 3745     (write-slice-buffered Stderr %edx)
 3746     (write-buffered Stderr "\n")
 3747     (flush Stderr)
 3748     # . syscall(exit, 1)
 3749     bb/copy-to-ebx  1/imm32
 3750     b8/copy-to-eax  1/imm32/exit
 3751     cd/syscall  0x80/imm8
 3752     # never gets here
 3753 
 3754 $parse-mu:error2:
 3755     # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n")
 3756     (print-int32-buffered Stderr *ebx)
 3757     (write-buffered Stderr " vars not reclaimed after fn '")
 3758     (write-slice-buffered Stderr *eax)  # Function-name
 3759     (write-buffered Stderr "'\n")
 3760     (flush Stderr)
 3761     # . syscall(exit, 1)
 3762     bb/copy-to-ebx  1/imm32
 3763     b8/copy-to-eax  1/imm32/exit
 3764     cd/syscall  0x80/imm8
 3765     # never gets here
 3766 
 3767 # scenarios considered:
 3768 # ✗ fn foo  # no block
 3769 # ✓ fn foo {
 3770 # ✗ fn foo { {
 3771 # ✗ fn foo { }
 3772 # ✗ fn foo { } {
 3773 # ✗ fn foo x {
 3774 # ✗ fn foo x: {
 3775 # ✓ fn foo x: int {
 3776 # ✓ fn foo x: int {
 3777 # ✓ fn foo x: int -> y/eax: int {
 3778 populate-mu-function-header:  # first-line: (addr stream byte), out: (addr function), vars: (addr stack (handle var))
 3779     # pseudocode:
 3780     #   var name: slice
 3781     #   next-mu-token(first-line, name)
 3782     #   assert(name not in '{' '}' '->')
 3783     #   out->name = slice-to-string(name)
 3784     #   ## inouts
 3785     #   while true
 3786     #     ## name
 3787     #     name = next-mu-token(first-line)
 3788     #     if (name == '{') goto done
 3789     #     if (name == '->') break
 3790     #     assert(name != '}')
 3791     #     var v: (handle var) = parse-var-with-type(name, first-line)
 3792     #     assert(v->register == null)
 3793     #     # v->block-depth is implicitly 0
 3794     #     out->inouts = append(v, out->inouts)
 3795     #     push(vars, v)
 3796     #   ## outputs
 3797     #   while true
 3798     #     ## name
 3799     #     name = next-mu-token(first-line)
 3800     #     assert(name not in '{' '}' '->')
 3801     #     var v: (handle var) = parse-var-with-type(name, first-line)
 3802     #     assert(v->register != null)
 3803     #     out->outputs = append(v, out->outputs)
 3804     #   done:
 3805     #
 3806     # . prologue
 3807     55/push-ebp
 3808     89/<- %ebp 4/r32/esp
 3809     # . save registers
 3810     50/push-eax
 3811     51/push-ecx
 3812     52/push-edx
 3813     53/push-ebx
 3814     57/push-edi
 3815     # edi = out
 3816     8b/-> *(ebp+0xc) 7/r32/edi
 3817     # var word-slice/ecx: slice
 3818     68/push 0/imm32/end
 3819     68/push 0/imm32/start
 3820     89/<- %ecx 4/r32/esp
 3821     # var v/ebx: (handle var)
 3822     68/push 0/imm32
 3823     68/push 0/imm32
 3824     89/<- %ebx 4/r32/esp
 3825     # read function name
 3826     (next-mu-token *(ebp+8) %ecx)
 3827     # error checking
 3828     # TODO: error if name starts with 'break' or 'loop'
 3829     # if (word-slice == '{') abort
 3830     (slice-equal? %ecx "{")   # => eax
 3831     3d/compare-eax-and 0/imm32/false
 3832     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 3833     # if (word-slice == '->') abort
 3834     (slice-equal? %ecx "->")   # => eax
 3835     3d/compare-eax-and 0/imm32/false
 3836     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 3837     # if (word-slice == '}') abort
 3838     (slice-equal? %ecx "}")   # => eax
 3839     3d/compare-eax-and 0/imm32/false
 3840     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 3841     # save function name
 3842     (slice-to-string Heap %ecx %edi)  # Function-name
 3843     # save function inouts
 3844     {
 3845 $populate-mu-function-header:check-for-inout:
 3846       (next-mu-token *(ebp+8) %ecx)
 3847       # if (word-slice == '{') goto done
 3848       (slice-equal? %ecx "{")   # => eax
 3849       3d/compare-eax-and 0/imm32/false
 3850       0f 85/jump-if-!= $populate-mu-function-header:done/disp32
 3851       # if (word-slice == '->') break
 3852       (slice-equal? %ecx "->")   # => eax
 3853       3d/compare-eax-and 0/imm32/false
 3854       0f 85/jump-if-!= break/disp32
 3855       # if (word-slice == '}') abort
 3856       (slice-equal? %ecx "}")   # => eax
 3857       3d/compare-eax-and 0/imm32/false
 3858       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 3859       # v = parse-var-with-type(word-slice, first-line)
 3860       (parse-var-with-type %ecx *(ebp+8) %ebx)
 3861       # assert(v->register == null)
 3862       # . eax: (addr var) = lookup(v)
 3863       (lookup *ebx *(ebx+4))  # => eax
 3864       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 3865       0f 85/jump-if-!= $populate-mu-function-header:error2/disp32
 3866       # v->block-depth is implicitly 0
 3867       #
 3868       # out->inouts = append(v, out->inouts)
 3869       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 3870       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 3871       # push(vars, v)
 3872       (push *(ebp+0x10) *ebx)
 3873       (push *(ebp+0x10) *(ebx+4))
 3874       #
 3875       e9/jump loop/disp32
 3876     }
 3877     # save function outputs
 3878     {
 3879 $populate-mu-function-header:check-for-out:
 3880       (next-mu-token *(ebp+8) %ecx)
 3881       # if (word-slice == '{') break
 3882       (slice-equal? %ecx "{")   # => eax
 3883       3d/compare-eax-and 0/imm32/false
 3884       0f 85/jump-if-!= break/disp32
 3885       # if (word-slice == '->') abort
 3886       (slice-equal? %ecx "->")   # => eax
 3887       3d/compare-eax-and 0/imm32/false
 3888       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 3889       # if (word-slice == '}') abort
 3890       (slice-equal? %ecx "}")   # => eax
 3891       3d/compare-eax-and 0/imm32/false
 3892       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 3893       # v = parse-var-with-type(word-slice, first-line)
 3894       (parse-var-with-type %ecx *(ebp+8) %ebx)
 3895       # assert(var->register != null)
 3896       # . eax: (addr var) = lookup(v)
 3897       (lookup *ebx *(ebx+4))  # => eax
 3898       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 3899       0f 84/jump-if-= $populate-mu-function-header:error3/disp32
 3900       # out->outputs = append(v, out->outputs)
 3901       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 3902       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 3903       #
 3904       e9/jump loop/disp32
 3905     }
 3906 $populate-mu-function-header:done:
 3907     (check-no-tokens-left *(ebp+8))
 3908 $populate-mu-function-header:end:
 3909     # . reclaim locals
 3910     81 0/subop/add %esp 0x10/imm32
 3911     # . restore registers
 3912     5f/pop-to-edi
 3913     5b/pop-to-ebx
 3914     5a/pop-to-edx
 3915     59/pop-to-ecx
 3916     58/pop-to-eax
 3917     # . epilogue
 3918     89/<- %esp 5/r32/ebp
 3919     5d/pop-to-ebp
 3920     c3/return
 3921 
 3922 $populate-mu-function-header:error1:
 3923     # error("function header not in form 'fn <name> {'")
 3924     (write-buffered Stderr "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 3925     (flush Stderr)
 3926     (rewind-stream *(ebp+8))
 3927     (write-stream 2 *(ebp+8))
 3928     (write-buffered Stderr "'\n")
 3929     (flush Stderr)
 3930     # . syscall(exit, 1)
 3931     bb/copy-to-ebx  1/imm32
 3932     b8/copy-to-eax  1/imm32/exit
 3933     cd/syscall  0x80/imm8
 3934     # never gets here
 3935 
 3936 $populate-mu-function-header:error2:
 3937     # error("function input '" var "' cannot be in a register")
 3938     (write-buffered Stderr "function input '")
 3939     (write-buffered Stderr *ebx)  # Var-name
 3940     (write-buffered Stderr "' cannot be in a register")
 3941     (flush Stderr)
 3942     # . syscall(exit, 1)
 3943     bb/copy-to-ebx  1/imm32
 3944     b8/copy-to-eax  1/imm32/exit
 3945     cd/syscall  0x80/imm8
 3946     # never gets here
 3947 
 3948 $populate-mu-function-header:error3:
 3949     # error("function input '" var "' must be in a register")
 3950     (write-buffered Stderr "function input '")
 3951     (lookup *ebx *(ebx+4))  # => eax
 3952     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 3953     (write-buffered Stderr %eax)
 3954     (write-buffered Stderr "' must be in a register, in instruction '")
 3955     (flush Stderr)
 3956     (rewind-stream *(ebp+8))
 3957     (write-stream 2 *(ebp+8))
 3958     (write-buffered Stderr "'\n")
 3959     (flush Stderr)
 3960     # . syscall(exit, 1)
 3961     bb/copy-to-ebx  1/imm32
 3962     b8/copy-to-eax  1/imm32/exit
 3963     cd/syscall  0x80/imm8
 3964     # never gets here
 3965 
 3966 test-function-header-with-arg:
 3967     # . prologue
 3968     55/push-ebp
 3969     89/<- %ebp 4/r32/esp
 3970     # setup
 3971     (clear-stream _test-input-stream)
 3972     (write _test-input-stream "foo n: int {\n")
 3973     # var result/ecx: function
 3974     2b/subtract *Function-size 4/r32/esp
 3975     89/<- %ecx 4/r32/esp
 3976     (zero-out %ecx *Function-size)
 3977     # var vars/ebx: (stack (handle var) 16)
 3978     81 5/subop/subtract %esp 0x80/imm32
 3979     68/push 0x80/imm32/size
 3980     68/push 0/imm32/top
 3981     89/<- %ebx 4/r32/esp
 3982     # convert
 3983     (populate-mu-function-header _test-input-stream %ecx %ebx)
 3984     # check result->name
 3985     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 3986     (check-strings-equal %eax "foo" "F - test-function-header-with-arg/name")
 3987     # var v/edx: (addr var) = result->inouts->value
 3988     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 3989     (lookup *eax *(eax+4))  # List-value List-value => eax
 3990     89/<- %edx 0/r32/eax
 3991     # check v->name
 3992     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 3993     (check-strings-equal %eax "n" "F - test-function-header-with-arg/inout:0")
 3994     # check v->type
 3995     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 3996     (check-ints-equal *eax 1 "F - test-function-header-with-arg/inout:0/type:0")  # Tree-is-atom
 3997     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-arg/inout:0/type:1")  # Tree-value
 3998     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-arg/inout:0/type:2")  # Tree-right
 3999     # . epilogue
 4000     89/<- %esp 5/r32/ebp
 4001     5d/pop-to-ebp
 4002     c3/return
 4003 
 4004 test-function-header-with-multiple-args:
 4005     # . prologue
 4006     55/push-ebp
 4007     89/<- %ebp 4/r32/esp
 4008     # setup
 4009     (clear-stream _test-input-stream)
 4010     (write _test-input-stream "foo a: int, b: int c: int {\n")
 4011     # result/ecx: function
 4012     2b/subtract *Function-size 4/r32/esp
 4013     89/<- %ecx 4/r32/esp
 4014     (zero-out %ecx *Function-size)
 4015     # var vars/ebx: (stack (handle var) 16)
 4016     81 5/subop/subtract %esp 0x80/imm32
 4017     68/push 0x80/imm32/size
 4018     68/push 0/imm32/top
 4019     89/<- %ebx 4/r32/esp
 4020     # convert
 4021     (populate-mu-function-header _test-input-stream %ecx %ebx)
 4022     # check result->name
 4023     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 4024     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args/name")
 4025     # var inouts/edx: (addr list var) = lookup(result->inouts)
 4026     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 4027     89/<- %edx 0/r32/eax
 4028 $test-function-header-with-multiple-args:inout0:
 4029     # var v/ebx: (addr var) = lookup(inouts->value)
 4030     (lookup *edx *(edx+4))  # List-value List-value => eax
 4031     89/<- %ebx 0/r32/eax
 4032     # check v->name
 4033     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4034     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args/inout:0")  # Var-name
 4035     # check v->type
 4036     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4037     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:0/type:0")  # Tree-is-atom
 4038     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:0/type:1")  # Tree-value
 4039     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:0/type:2")  # Tree-right
 4040 $test-function-header-with-multiple-args:inout1:
 4041     # inouts = lookup(inouts->next)
 4042     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 4043     89/<- %edx 0/r32/eax
 4044     # v = lookup(inouts->value)
 4045     (lookup *edx *(edx+4))  # List-value List-value => eax
 4046     89/<- %ebx 0/r32/eax
 4047     # check v->name
 4048     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4049     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args/inout:1")  # Var-name
 4050     # check v->type
 4051     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4052     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:1/type:0")  # Tree-is-atom
 4053     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:1/type:1")  # Tree-value
 4054     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:1/type:2")  # Tree-right
 4055 $test-function-header-with-multiple-args:inout2:
 4056     # inouts = lookup(inouts->next)
 4057     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 4058     89/<- %edx 0/r32/eax
 4059     # v = lookup(inouts->value)
 4060     (lookup *edx *(edx+4))  # List-value List-value => eax
 4061     89/<- %ebx 0/r32/eax
 4062     # check v->name
 4063     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4064     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args/inout:2")  # Var-name
 4065     # check v->type
 4066     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4067     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:2/type:0")  # Tree-is-atom
 4068     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:2/type:1")  # Tree-value
 4069     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:2/type:2")  # Tree-right
 4070     # . epilogue
 4071     89/<- %esp 5/r32/ebp
 4072     5d/pop-to-ebp
 4073     c3/return
 4074 
 4075 test-function-header-with-multiple-args-and-outputs:
 4076     # . prologue
 4077     55/push-ebp
 4078     89/<- %ebp 4/r32/esp
 4079     # setup
 4080     (clear-stream _test-input-stream)
 4081     (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n")
 4082     # result/ecx: function
 4083     2b/subtract *Function-size 4/r32/esp
 4084     89/<- %ecx 4/r32/esp
 4085     (zero-out %ecx *Function-size)
 4086     # var vars/ebx: (stack (handle var) 16)
 4087     81 5/subop/subtract %esp 0x80/imm32
 4088     68/push 0x80/imm32/size
 4089     68/push 0/imm32/top
 4090     89/<- %ebx 4/r32/esp
 4091     # convert
 4092     (populate-mu-function-header _test-input-stream %ecx %ebx)
 4093     # check result->name
 4094     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 4095     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args-and-outputs/name")
 4096     # var inouts/edx: (addr list var) = lookup(result->inouts)
 4097     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 4098     89/<- %edx 0/r32/eax
 4099 $test-function-header-with-multiple-args-and-outputs:inout0:
 4100     # var v/ebx: (addr var) = lookup(inouts->value)
 4101     (lookup *edx *(edx+4))  # List-value List-value => eax
 4102     89/<- %ebx 0/r32/eax
 4103     # check v->name
 4104     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4105     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0")
 4106     # check v->type
 4107     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4108     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0")  # Tree-is-atom
 4109     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1")  # Tree-value
 4110     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:2")  # Tree-right
 4111 $test-function-header-with-multiple-args-and-outputs:inout1:
 4112     # inouts = lookup(inouts->next)
 4113     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 4114     89/<- %edx 0/r32/eax
 4115     # v = lookup(inouts->value)
 4116     (lookup *edx *(edx+4))  # List-value List-value => eax
 4117     89/<- %ebx 0/r32/eax
 4118     # check v->name
 4119     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4120     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1")
 4121     # check v->type
 4122     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4123     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0")  # Tree-is-atom
 4124     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1")  # Tree-value
 4125     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:2")  # Tree-right
 4126 $test-function-header-with-multiple-args-and-outputs:inout2:
 4127     # inouts = lookup(inouts->next)
 4128     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 4129     89/<- %edx 0/r32/eax
 4130     # v = lookup(inouts->value)
 4131     (lookup *edx *(edx+4))  # List-value List-value => eax
 4132     89/<- %ebx 0/r32/eax
 4133     # check v->name
 4134     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4135     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2")
 4136     # check v->type
 4137     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4138     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0")  # Tree-is-atom
 4139     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1")  # Tree-value
 4140     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:2")  # Tree-right
 4141 $test-function-header-with-multiple-args-and-outputs:out0:
 4142     # var outputs/edx: (addr list var) = lookup(result->outputs)
 4143     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 4144     89/<- %edx 0/r32/eax
 4145     # v = lookup(outputs->value)
 4146     (lookup *edx *(edx+4))  # List-value List-value => eax
 4147     89/<- %ebx 0/r32/eax
 4148     # check v->name
 4149     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4150     (check-strings-equal %eax "x" "F - test-function-header-with-multiple-args-and-outputs/output:0")
 4151     # check v->register
 4152     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 4153     (check-strings-equal %eax "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register")
 4154     # check v->type
 4155     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4156     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:0")  # Tree-is-atom
 4157     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1")  # Tree-value
 4158     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:2")  # Tree-right
 4159 $test-function-header-with-multiple-args-and-outputs:out1:
 4160     # outputs = lookup(outputs->next)
 4161     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 4162     89/<- %edx 0/r32/eax
 4163     # v = lookup(inouts->value)
 4164     (lookup *edx *(edx+4))  # List-value List-value => eax
 4165     89/<- %ebx 0/r32/eax
 4166     # check v->name
 4167     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4168     (check-strings-equal %eax "y" "F - test-function-header-with-multiple-args-and-outputs/output:1")
 4169     # check v->register
 4170     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 4171     (check-strings-equal %eax "edx" "F - test-function-header-with-multiple-args-and-outputs/output:1/register")
 4172     # check v->type
 4173     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4174     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:0")  # Tree-is-atom
 4175     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1")  # Tree-value
 4176     (check-ints-equal *(eax+0c) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:2")  # Tree-right
 4177     # . epilogue
 4178     89/<- %esp 5/r32/ebp
 4179     5d/pop-to-ebp
 4180     c3/return
 4181 
 4182 # format for variables with types
 4183 #   x: int
 4184 #   x: int,
 4185 #   x/eax: int
 4186 #   x/eax: int,
 4187 # ignores at most one trailing comma
 4188 # WARNING: modifies name
 4189 parse-var-with-type:  # name: (addr slice), first-line: (addr stream byte), out: (addr handle var)
 4190     # pseudocode:
 4191     #   var s: slice
 4192     #   if (!slice-ends-with(name, ":"))
 4193     #     abort
 4194     #   --name->end to skip ':'
 4195     #   next-token-from-slice(name->start, name->end, '/', s)
 4196     #   new-var-from-slice(s, out)
 4197     #   ## register
 4198     #   next-token-from-slice(s->end, name->end, '/', s)
 4199     #   if (!slice-empty?(s))
 4200     #     out->register = slice-to-string(s)
 4201     #   ## type
 4202     #   var type: (handle tree type-id) = parse-type(first-line)
 4203     #   out->type = type
 4204     #
 4205     # . prologue
 4206     55/push-ebp
 4207     89/<- %ebp 4/r32/esp
 4208     # . save registers
 4209     50/push-eax
 4210     51/push-ecx
 4211     52/push-edx
 4212     53/push-ebx
 4213     56/push-esi
 4214     57/push-edi
 4215     # esi = name
 4216     8b/-> *(ebp+8) 6/r32/esi
 4217     # if (!slice-ends-with?(name, ":")) abort
 4218     8b/-> *(esi+4) 1/r32/ecx  # Slice-end
 4219     49/decrement-ecx
 4220     8a/copy-byte *ecx 1/r32/CL
 4221     81 4/subop/and %ecx 0xff/imm32
 4222     81 7/subop/compare %ecx 0x3a/imm32/colon
 4223     0f 85/jump-if-!= $parse-var-with-type:abort/disp32
 4224     # --name->end to skip ':'
 4225     ff 1/subop/decrement *(esi+4)
 4226     # var s/ecx: slice
 4227     68/push 0/imm32/end
 4228     68/push 0/imm32/start
 4229     89/<- %ecx 4/r32/esp
 4230 $parse-var-with-type:parse-name:
 4231     (next-token-from-slice *esi *(esi+4) 0x2f %ecx)  # Slice-start, Slice-end, '/'
 4232 $parse-var-with-type:create-var:
 4233     # new-var-from-slice(s, out)
 4234     (new-var-from-slice Heap %ecx *(ebp+0x10))
 4235     # save out->register
 4236 $parse-var-with-type:save-register:
 4237     # . var out-addr/edi: (addr var) = lookup(*out)
 4238     8b/-> *(ebp+0x10) 7/r32/edi
 4239     (lookup *edi *(edi+4))  # => eax
 4240     89/<- %edi 0/r32/eax
 4241     # . s = next-token(...)
 4242     (next-token-from-slice *(ecx+4) *(esi+4) 0x2f %ecx)  # s->end, name->end, '/'
 4243     # . if (!slice-empty?(s)) out->register = slice-to-string(s)
 4244     {
 4245 $parse-var-with-type:write-register:
 4246       (slice-empty? %ecx)  # => eax
 4247       3d/compare-eax-and 0/imm32/false
 4248       75/jump-if-!= break/disp8
 4249       # out->register = slice-to-string(s)
 4250       8d/copy-address *(edi+0x18) 0/r32/eax  # Var-register
 4251       (slice-to-string Heap %ecx %eax)
 4252     }
 4253 $parse-var-with-type:save-type:
 4254     8d/copy-address *(edi+8) 0/r32/eax  # Var-type
 4255     (parse-type Heap *(ebp+0xc) %eax)
 4256 $parse-var-with-type:end:
 4257     # . reclaim locals
 4258     81 0/subop/add %esp 8/imm32
 4259     # . restore registers
 4260     5f/pop-to-edi
 4261     5e/pop-to-esi
 4262     5b/pop-to-ebx
 4263     5a/pop-to-edx
 4264     59/pop-to-ecx
 4265     58/pop-to-eax
 4266     # . epilogue
 4267     89/<- %esp 5/r32/ebp
 4268     5d/pop-to-ebp
 4269     c3/return
 4270 
 4271 $parse-var-with-type:abort:
 4272     # error("var should have form 'name: type' in '" line "'\n")
 4273     (write-buffered Stderr "var should have form 'name: type' in '")
 4274     (flush Stderr)
 4275     (rewind-stream *(ebp+0xc))
 4276     (write-stream 2 *(ebp+0xc))
 4277     (write-buffered Stderr "'\n")
 4278     (flush Stderr)
 4279     # . syscall(exit, 1)
 4280     bb/copy-to-ebx  1/imm32
 4281     b8/copy-to-eax  1/imm32/exit
 4282     cd/syscall  0x80/imm8
 4283     # never gets here
 4284 
 4285 parse-type:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle tree type-id)
 4286     # pseudocode:
 4287     #   var s: slice = next-mu-token(in)
 4288     #   assert s != ""
 4289     #   assert s != "->"
 4290     #   assert s != "{"
 4291     #   assert s != "}"
 4292     #   if s == ")"
 4293     #     return
 4294     #   out = allocate(Tree)
 4295     #   if s != "("
 4296     #     HACK: if s is an int, parse and return it
 4297     #     out->left-is-atom? = true
 4298     #     out->value = pos-or-insert-slice(Type-id, s)
 4299     #     return
 4300     #   out->left = parse-type(ad, in)
 4301     #   out->right = parse-type-tree(ad, in)
 4302     #
 4303     # . prologue
 4304     55/push-ebp
 4305     89/<- %ebp 4/r32/esp
 4306     # . save registers
 4307     50/push-eax
 4308     51/push-ecx
 4309     52/push-edx
 4310     # clear out
 4311     (zero-out *(ebp+0x10) *Handle-size)
 4312     # var s/ecx: slice
 4313     68/push 0/imm32
 4314     68/push 0/imm32
 4315     89/<- %ecx 4/r32/esp
 4316     # s = next-mu-token(in)
 4317     (next-mu-token *(ebp+0xc) %ecx)
 4318 #?     (write-buffered Stderr "tok: ")
 4319 #?     (write-slice-buffered Stderr %ecx)
 4320 #?     (write-buffered Stderr "$\n")
 4321 #?     (flush Stderr)
 4322     # assert s != ""
 4323     (slice-equal? %ecx "")  # => eax
 4324     3d/compare-eax-and 0/imm32/false
 4325     0f 85/jump-if-!= $parse-type:abort/disp32
 4326     # assert s != "{"
 4327     (slice-equal? %ecx "{")  # => eax
 4328     3d/compare-eax-and 0/imm32/false
 4329     0f 85/jump-if-!= $parse-type:abort/disp32
 4330     # assert s != "}"
 4331     (slice-equal? %ecx "}")  # => eax
 4332     3d/compare-eax-and 0/imm32/false
 4333     0f 85/jump-if-!= $parse-type:abort/disp32
 4334     # assert s != "->"
 4335     (slice-equal? %ecx "->")  # => eax
 4336     3d/compare-eax-and 0/imm32/false
 4337     0f 85/jump-if-!= $parse-type:abort/disp32
 4338     # if (s == ")") return
 4339     (slice-equal? %ecx ")")  # => eax
 4340     3d/compare-eax-and 0/imm32/false
 4341     0f 85/jump-if-!= $parse-type:end/disp32
 4342     # out = new tree
 4343     (allocate *(ebp+8) *Tree-size *(ebp+0x10))
 4344     # var out-addr/edx: (addr tree type-id) = lookup(*out)
 4345     8b/-> *(ebp+0x10) 2/r32/edx
 4346     (lookup *edx *(edx+4))  # => eax
 4347     89/<- %edx 0/r32/eax
 4348     {
 4349       # if (s != "(") break
 4350       (slice-equal? %ecx "(")  # => eax
 4351       3d/compare-eax-and 0/imm32/false
 4352       75/jump-if-!= break/disp8
 4353       # EGREGIOUS HACK for static array sizes: if s is a number, parse it
 4354       {
 4355 $parse-type:check-for-int:
 4356         (is-hex-int? %ecx)  # => eax
 4357         3d/compare-eax-and 0/imm32/false
 4358         74/jump-if-= break/disp8
 4359 $parse-type:int:
 4360         (parse-hex-int-from-slice %ecx)  # => eax
 4361         89/<- *(edx+4) 0/r32/eax  # Tree-value
 4362         e9/jump $parse-type:end/disp32
 4363       }
 4364 $parse-type:atom:
 4365       # out->left-is-atom? = true
 4366       c7 0/subop/copy *edx 1/imm32/true  # Tree-is-atom
 4367       # out->value = pos-or-insert-slice(Type-id, s)
 4368       (pos-or-insert-slice Type-id %ecx)  # => eax
 4369       89/<- *(edx+4) 0/r32/eax  # Tree-value
 4370       e9/jump $parse-type:end/disp32
 4371     }
 4372 $parse-type:non-atom:
 4373     # otherwise s == "("
 4374     # out->left = parse-type(ad, in)
 4375     8d/copy-address *(edx+4) 0/r32/eax  # Tree-left
 4376     (parse-type *(ebp+8) *(ebp+0xc) %eax)
 4377     # out->right = parse-type-tree(ad, in)
 4378     8d/copy-address *(edx+0xc) 0/r32/eax  # Tree-right
 4379     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax)
 4380 $parse-type:end:
 4381     # . reclaim locals
 4382     81 0/subop/add %esp 8/imm32
 4383     # . restore registers
 4384     5a/pop-to-edx
 4385     59/pop-to-ecx
 4386     58/pop-to-eax
 4387     # . epilogue
 4388     89/<- %esp 5/r32/ebp
 4389     5d/pop-to-ebp
 4390     c3/return
 4391 
 4392 $parse-type:abort:
 4393     # error("unexpected token when parsing type: '" s "'\n")
 4394     (write-buffered Stderr "unexpected token when parsing type: '")
 4395     (write-slice-buffered Stderr %ecx)
 4396     (write-buffered Stderr "'\n")
 4397     (flush Stderr)
 4398     # . syscall(exit, 1)
 4399     bb/copy-to-ebx  1/imm32
 4400     b8/copy-to-eax  1/imm32/exit
 4401     cd/syscall  0x80/imm8
 4402     # never gets here
 4403 
 4404 parse-type-tree:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle tree type-id)
 4405     # pseudocode:
 4406     #   var tmp: (handle tree type-id) = parse-type(ad, in)
 4407     #   if tmp == 0
 4408     #     return 0
 4409     #   out = allocate(Tree)
 4410     #   out->left = tmp
 4411     #   out->right = parse-type-tree(ad, in)
 4412     #
 4413     # . prologue
 4414     55/push-ebp
 4415     89/<- %ebp 4/r32/esp
 4416     # . save registers
 4417     50/push-eax
 4418     51/push-ecx
 4419     52/push-edx
 4420     #
 4421     (zero-out *(ebp+0x10) *Handle-size)
 4422     # var tmp/ecx: (handle tree type-id)
 4423     68/push 0/imm32
 4424     68/push 0/imm32
 4425     89/<- %ecx 4/r32/esp
 4426     # tmp = parse-type(ad, in)
 4427     (parse-type *(ebp+8) *(ebp+0xc) %ecx)
 4428     # if (tmp == 0) return
 4429     81 7/subop/compare *ecx 0/imm32
 4430     74/jump-if-= $parse-type-tree:end/disp8
 4431     # out = new tree
 4432     (allocate *(ebp+8) *Tree-size *(ebp+0x10))
 4433     # var out-addr/edx: (addr tree) = lookup(*out)
 4434     8b/-> *(ebp+0x10) 2/r32/edx
 4435     (lookup *edx *(edx+4))  # => eax
 4436     89/<- %edx 0/r32/eax
 4437     # out->left = tmp
 4438     8b/-> *ecx 0/r32/eax
 4439     89/<- *(edx+4) 0/r32/eax  # Tree-left
 4440     8b/-> *(ecx+4) 0/r32/eax
 4441     89/<- *(edx+8) 0/r32/eax  # Tree-left
 4442     # out->right = parse-type-tree(ad, in)
 4443     8d/copy-address *(edx+0xc) 0/r32/eax  # Tree-right
 4444     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax)
 4445 $parse-type-tree:end:
 4446     # . reclaim locals
 4447     81 0/subop/add %esp 8/imm32
 4448     # . restore registers
 4449     5a/pop-to-edx
 4450     59/pop-to-ecx
 4451     58/pop-to-eax
 4452     # . epilogue
 4453     89/<- %esp 5/r32/ebp
 4454     5d/pop-to-ebp
 4455     c3/return
 4456 
 4457 next-mu-token:  # in: (addr stream byte), out: (addr slice)
 4458     # pseudocode:
 4459     # start:
 4460     #   skip-chars-matching-whitespace(in)
 4461     #   if in->read >= in->write              # end of in
 4462     #     out = {0, 0}
 4463     #     return
 4464     #   out->start = &in->data[in->read]
 4465     #   var curr-byte/eax: byte = in->data[in->read]
 4466     #   if curr->byte == ','                  # comment token
 4467     #     ++in->read
 4468     #     goto start
 4469     #   if curr-byte == '#'                   # comment
 4470     #     goto done                             # treat as eof
 4471     #   if curr-byte == '"'                   # string literal
 4472     #     skip-string(in)
 4473     #     goto done                           # no metadata
 4474     #   if curr-byte == '('
 4475     #     ++in->read
 4476     #     goto done
 4477     #   if curr-byte == ')'
 4478     #     ++in->read
 4479     #     goto done
 4480     #   # read a word
 4481     #   while true
 4482     #     if in->read >= in->write
 4483     #       break
 4484     #     curr-byte = in->data[in->read]
 4485     #     if curr-byte == ' '
 4486     #       break
 4487     #     if curr-byte == '\r'
 4488     #       break
 4489     #     if curr-byte == '\n'
 4490     #       break
 4491     #     if curr-byte == '('
 4492     #       break
 4493     #     if curr-byte == ')'
 4494     #       break
 4495     #     if curr-byte == ','
 4496     #       break
 4497     #     ++in->read
 4498     # done:
 4499     #   out->end = &in->data[in->read]
 4500     #
 4501     # . prologue
 4502     55/push-ebp
 4503     89/<- %ebp 4/r32/esp
 4504     # . save registers
 4505     50/push-eax
 4506     51/push-ecx
 4507     56/push-esi
 4508     57/push-edi
 4509     # esi = in
 4510     8b/-> *(ebp+8) 6/r32/esi
 4511     # edi = out
 4512     8b/-> *(ebp+0xc) 7/r32/edi
 4513 $next-mu-token:start:
 4514     (skip-chars-matching-whitespace %esi)
 4515 $next-mu-token:check0:
 4516     # if (in->read >= in->write) return out = {0, 0}
 4517     # . ecx = in->read
 4518     8b/-> *(esi+4) 1/r32/ecx
 4519     # . if (ecx >= in->write) return out = {0, 0}
 4520     3b/compare<- *esi 1/r32/ecx
 4521     c7 0/subop/copy *edi 0/imm32
 4522     c7 0/subop/copy *(edi+4) 0/imm32
 4523     0f 8d/jump-if->= $next-mu-token:end/disp32
 4524     # out->start = &in->data[in->read]
 4525     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 4526     89/<- *edi 0/r32/eax
 4527     # var curr-byte/eax: byte = in->data[in->read]
 4528     31/xor-with %eax 0/r32/eax
 4529     8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 4530     {
 4531 $next-mu-token:check-for-comma:
 4532       # if (curr-byte != ',') break
 4533       3d/compare-eax-and 0x2c/imm32/comma
 4534       75/jump-if-!= break/disp8
 4535       # ++in->read
 4536       ff 0/subop/increment *(esi+4)
 4537       # restart
 4538       e9/jump $next-mu-token:start/disp32
 4539     }
 4540     {
 4541 $next-mu-token:check-for-comment:
 4542       # if (curr-byte != '#') break
 4543       3d/compare-eax-and 0x23/imm32/pound
 4544       75/jump-if-!= break/disp8
 4545       # return eof
 4546       e9/jump $next-mu-token:done/disp32
 4547     }
 4548     {
 4549 $next-mu-token:check-for-string-literal:
 4550       # if (curr-byte != '"') break
 4551       3d/compare-eax-and 0x22/imm32/dquote
 4552       75/jump-if-!= break/disp8
 4553       (skip-string %esi)
 4554       # return
 4555       e9/jump $next-mu-token:done/disp32
 4556     }
 4557     {
 4558 $next-mu-token:check-for-open-paren:
 4559       # if (curr-byte != '(') break
 4560       3d/compare-eax-and 0x28/imm32/open-paren
 4561       75/jump-if-!= break/disp8
 4562       # ++in->read
 4563       ff 0/subop/increment *(esi+4)
 4564       # return
 4565       e9/jump $next-mu-token:done/disp32
 4566     }
 4567     {
 4568 $next-mu-token:check-for-close-paren:
 4569       # if (curr-byte != ')') break
 4570       3d/compare-eax-and 0x29/imm32/close-paren
 4571       75/jump-if-!= break/disp8
 4572       # ++in->read
 4573       ff 0/subop/increment *(esi+4)
 4574       # return
 4575       e9/jump $next-mu-token:done/disp32
 4576     }
 4577     {
 4578 $next-mu-token:regular-word-without-metadata:
 4579       # if (in->read >= in->write) break
 4580       # . ecx = in->read
 4581       8b/-> *(esi+4) 1/r32/ecx
 4582       # . if (ecx >= in->write) break
 4583       3b/compare<- *esi 1/r32/ecx
 4584       7d/jump-if->= break/disp8
 4585       # var c/eax: byte = in->data[in->read]
 4586       31/xor-with %eax 0/r32/eax
 4587       8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 4588       # if (c == ' ') break
 4589       3d/compare-eax-and 0x20/imm32/space
 4590       74/jump-if-= break/disp8
 4591       # if (c == '\r') break
 4592       3d/compare-eax-and 0xd/imm32/carriage-return
 4593       74/jump-if-= break/disp8
 4594       # if (c == '\n') break
 4595       3d/compare-eax-and 0xa/imm32/newline
 4596       74/jump-if-= break/disp8
 4597       # if (c == '(') break
 4598       3d/compare-eax-and 0x28/imm32/open-paren
 4599       0f 84/jump-if-= break/disp32
 4600       # if (c == ')') break
 4601       3d/compare-eax-and 0x29/imm32/close-paren
 4602       0f 84/jump-if-= break/disp32
 4603       # if (c == ',') break
 4604       3d/compare-eax-and 0x2c/imm32/comma
 4605       0f 84/jump-if-= break/disp32
 4606       # ++in->read
 4607       ff 0/subop/increment *(esi+4)
 4608       #
 4609       e9/jump loop/disp32
 4610     }
 4611 $next-mu-token:done:
 4612     # out->end = &in->data[in->read]
 4613     8b/-> *(esi+4) 1/r32/ecx
 4614     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 4615     89/<- *(edi+4) 0/r32/eax
 4616 $next-mu-token:end:
 4617     # . restore registers
 4618     5f/pop-to-edi
 4619     5e/pop-to-esi
 4620     59/pop-to-ecx
 4621     58/pop-to-eax
 4622     # . epilogue
 4623     89/<- %esp 5/r32/ebp
 4624     5d/pop-to-ebp
 4625     c3/return
 4626 
 4627 pos-or-insert-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 4628     # . prologue
 4629     55/push-ebp
 4630     89/<- %ebp 4/r32/esp
 4631     # if (pos-slice(arr, s) != -1) return it
 4632     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 4633     3d/compare-eax-and -1/imm32
 4634     75/jump-if-!= $pos-or-insert-slice:end/disp8
 4635 $pos-or-insert-slice:insert:
 4636     # var s2/eax: (handle array byte)
 4637     68/push 0/imm32
 4638     68/push 0/imm32
 4639     89/<- %eax 4/r32/esp
 4640     (slice-to-string Heap *(ebp+0xc) %eax)
 4641     # throw away alloc-id
 4642     (lookup *eax *(eax+4))  # => eax
 4643     (write-int *(ebp+8) %eax)
 4644     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 4645 $pos-or-insert-slice:end:
 4646     # . reclaim locals
 4647     81 0/subop/add %esp 8/imm32
 4648     # . epilogue
 4649     89/<- %esp 5/r32/ebp
 4650     5d/pop-to-ebp
 4651     c3/return
 4652 
 4653 # return the index in an array of strings matching 's', -1 if not found
 4654 # index is denominated in elements, not bytes
 4655 pos-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 4656     # . prologue
 4657     55/push-ebp
 4658     89/<- %ebp 4/r32/esp
 4659     # . save registers
 4660     51/push-ecx
 4661     52/push-edx
 4662     53/push-ebx
 4663     56/push-esi
 4664 #?     (write-buffered Stderr "pos-slice: ")
 4665 #?     (write-slice-buffered Stderr *(ebp+0xc))
 4666 #?     (write-buffered Stderr "\n")
 4667 #?     (flush Stderr)
 4668     # esi = arr
 4669     8b/-> *(ebp+8) 6/r32/esi
 4670     # var index/ecx: int = 0
 4671     b9/copy-to-ecx 0/imm32
 4672     # var curr/edx: (addr (addr array byte)) = arr->data
 4673     8d/copy-address *(esi+0xc) 2/r32/edx
 4674     # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write]
 4675     8b/-> *esi 3/r32/ebx
 4676     8d/copy-address *(esi+ebx+0xc) 3/r32/ebx
 4677     {
 4678 #?       (write-buffered Stderr "  ")
 4679 #?       (print-int32-buffered Stderr %ecx)
 4680 #?       (write-buffered Stderr "\n")
 4681 #?       (flush Stderr)
 4682       # if (curr >= max) return -1
 4683       39/compare %edx 3/r32/ebx
 4684       b8/copy-to-eax -1/imm32
 4685       73/jump-if-addr>= $pos-slice:end/disp8
 4686       # if (slice-equal?(s, *curr)) break
 4687       (slice-equal? *(ebp+0xc) *edx)  # => eax
 4688       3d/compare-eax-and 0/imm32/false
 4689       75/jump-if-!= break/disp8
 4690       # ++index
 4691       41/increment-ecx
 4692       # curr += 4
 4693       81 0/subop/add %edx 4/imm32
 4694       #
 4695       eb/jump loop/disp8
 4696     }
 4697     # return index
 4698     89/<- %eax 1/r32/ecx
 4699 $pos-slice:end:
 4700 #?     (write-buffered Stderr "=> ")
 4701 #?     (print-int32-buffered Stderr %eax)
 4702 #?     (write-buffered Stderr "\n")
 4703     # . restore registers
 4704     5e/pop-to-esi
 4705     5b/pop-to-ebx
 4706     5a/pop-to-edx
 4707     59/pop-to-ecx
 4708     # . epilogue
 4709     89/<- %esp 5/r32/ebp
 4710     5d/pop-to-ebp
 4711     c3/return
 4712 
 4713 test-parse-var-with-type:
 4714     # . prologue
 4715     55/push-ebp
 4716     89/<- %ebp 4/r32/esp
 4717     # (eax..ecx) = "x:"
 4718     b8/copy-to-eax "x:"/imm32
 4719     8b/-> *eax 1/r32/ecx
 4720     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 4721     05/add-to-eax 4/imm32
 4722     # var slice/ecx: slice = {eax, ecx}
 4723     51/push-ecx
 4724     50/push-eax
 4725     89/<- %ecx 4/r32/esp
 4726     # _test-input-stream contains "int"
 4727     (clear-stream _test-input-stream)
 4728     (write _test-input-stream "int")
 4729     # var v/edx: (handle var)
 4730     68/push 0/imm32
 4731     68/push 0/imm32
 4732     89/<- %edx 4/r32/esp
 4733     #
 4734     (parse-var-with-type %ecx _test-input-stream %edx)
 4735     # var v-addr/edx: (addr var) = lookup(v)
 4736     (lookup *edx *(edx+4))  # => eax
 4737     89/<- %edx 0/r32/eax
 4738     # check v-addr->name
 4739     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 4740     (check-strings-equal %eax "x" "F - test-parse-var-with-type/name")
 4741     # check v-addr->type
 4742     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 4743     (check-ints-equal *eax 1 "F - test-parse-var-with-type/type:0")  # Tree-is-atom
 4744     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type/type:1")  # Tree-value
 4745     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type/type:2")  # Tree-right
 4746     # . epilogue
 4747     89/<- %esp 5/r32/ebp
 4748     5d/pop-to-ebp
 4749     c3/return
 4750 
 4751 test-parse-var-with-type-and-register:
 4752     # . prologue
 4753     55/push-ebp
 4754     89/<- %ebp 4/r32/esp
 4755     # (eax..ecx) = "x/eax:"
 4756     b8/copy-to-eax "x/eax:"/imm32
 4757     8b/-> *eax 1/r32/ecx
 4758     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 4759     05/add-to-eax 4/imm32
 4760     # var slice/ecx: slice = {eax, ecx}
 4761     51/push-ecx
 4762     50/push-eax
 4763     89/<- %ecx 4/r32/esp
 4764     # _test-input-stream contains "int"
 4765     (clear-stream _test-input-stream)
 4766     (write _test-input-stream "int")
 4767     # var v/edx: (handle var)
 4768     68/push 0/imm32
 4769     68/push 0/imm32
 4770     89/<- %edx 4/r32/esp
 4771     #
 4772     (parse-var-with-type %ecx _test-input-stream %edx)
 4773     # var v-addr/edx: (addr var) = lookup(v)
 4774     (lookup *edx *(edx+4))  # => eax
 4775     89/<- %edx 0/r32/eax
 4776     # check v-addr->name
 4777     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 4778     (check-strings-equal %eax "x" "F - test-parse-var-with-type-and-register/name")
 4779     # check v-addr->register
 4780     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 4781     (check-strings-equal %eax "eax" "F - test-parse-var-with-type-and-register/register")
 4782     # check v-addr->type
 4783     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 4784     (check-ints-equal *eax 1 "F - test-parse-var-with-type-and-register/type:0")  # Tree-is-atom
 4785     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type-and-register/type:1")  # Tree-left
 4786     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type-and-register/type:2")  # Tree-right
 4787     # . epilogue
 4788     89/<- %esp 5/r32/ebp
 4789     5d/pop-to-ebp
 4790     c3/return
 4791 
 4792 test-parse-var-with-trailing-characters:
 4793     # . prologue
 4794     55/push-ebp
 4795     89/<- %ebp 4/r32/esp
 4796     # (eax..ecx) = "x:"
 4797     b8/copy-to-eax "x:"/imm32
 4798     8b/-> *eax 1/r32/ecx
 4799     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 4800     05/add-to-eax 4/imm32
 4801     # var slice/ecx: slice = {eax, ecx}
 4802     51/push-ecx
 4803     50/push-eax
 4804     89/<- %ecx 4/r32/esp
 4805     # _test-input-stream contains "int,"
 4806     (clear-stream _test-input-stream)
 4807     (write _test-input-stream "int,")
 4808     # var v/edx: (handle var)
 4809     68/push 0/imm32
 4810     68/push 0/imm32
 4811     89/<- %edx 4/r32/esp
 4812     #
 4813     (parse-var-with-type %ecx _test-input-stream %edx)
 4814     # var v-addr/edx: (addr var) = lookup(v)
 4815     (lookup *edx *(edx+4))  # => eax
 4816     89/<- %edx 0/r32/eax
 4817     # check v-addr->name
 4818     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 4819     (check-strings-equal %eax "x" "F - test-parse-var-with-trailing-characters/name")
 4820     # check v-addr->register
 4821     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-trailing-characters/register")  # Var-register
 4822     # check v-addr->type
 4823     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 4824     (check-ints-equal *eax 1 "F - test-parse-var-with-trailing-characters/type:0")  # Tree-is-atom
 4825     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-trailing-characters/type:1")  # Tree-left
 4826     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-trailing-characters/type:1")  # Tree-right
 4827     # . epilogue
 4828     89/<- %esp 5/r32/ebp
 4829     5d/pop-to-ebp
 4830     c3/return
 4831 
 4832 test-parse-var-with-register-and-trailing-characters:
 4833     # . prologue
 4834     55/push-ebp
 4835     89/<- %ebp 4/r32/esp
 4836     # (eax..ecx) = "x/eax:"
 4837     b8/copy-to-eax "x/eax:"/imm32
 4838     8b/-> *eax 1/r32/ecx
 4839     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 4840     05/add-to-eax 4/imm32
 4841     # var slice/ecx: slice = {eax, ecx}
 4842     51/push-ecx
 4843     50/push-eax
 4844     89/<- %ecx 4/r32/esp
 4845     # _test-input-stream contains "int,"
 4846     (clear-stream _test-input-stream)
 4847     (write _test-input-stream "int,")
 4848     # var v/edx: (handle var)
 4849     68/push 0/imm32
 4850     68/push 0/imm32
 4851     89/<- %edx 4/r32/esp
 4852     #
 4853     (parse-var-with-type %ecx _test-input-stream %edx)
 4854     # var v-addr/edx: (addr var) = lookup(v)
 4855     (lookup *edx *(edx+4))  # => eax
 4856     89/<- %edx 0/r32/eax
 4857     # check v-addr->name
 4858     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 4859     (check-strings-equal %eax "x" "F - test-parse-var-with-register-and-trailing-characters/name")
 4860     # check v-addr->register
 4861     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 4862     (check-strings-equal %eax "eax" "F - test-parse-var-with-register-and-trailing-characters/register")
 4863     # check v-addr->type
 4864     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 4865     (check-ints-equal *eax 1 "F - test-parse-var-with-register-and-trailing-characters/type:0")  # Tree-is-atom
 4866     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-register-and-trailing-characters/type:1")  # Tree-left
 4867     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-register-and-trailing-characters/type:2")  # Tree-right
 4868     # . epilogue
 4869     89/<- %esp 5/r32/ebp
 4870     5d/pop-to-ebp
 4871     c3/return
 4872 
 4873 test-parse-var-with-compound-type:
 4874     # . prologue
 4875     55/push-ebp
 4876     89/<- %ebp 4/r32/esp
 4877     # (eax..ecx) = "x:"
 4878     b8/copy-to-eax "x:"/imm32
 4879     8b/-> *eax 1/r32/ecx
 4880     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 4881     05/add-to-eax 4/imm32
 4882     # var slice/ecx: slice = {eax, ecx}
 4883     51/push-ecx
 4884     50/push-eax
 4885     89/<- %ecx 4/r32/esp
 4886     # _test-input-stream contains "(addr int)"
 4887     (clear-stream _test-input-stream)
 4888     (write _test-input-stream "(addr int)")
 4889     # var v/edx: (handle var)
 4890     68/push 0/imm32
 4891     68/push 0/imm32
 4892     89/<- %edx 4/r32/esp
 4893     #
 4894     (parse-var-with-type %ecx _test-input-stream %edx)
 4895     # var v-addr/edx: (addr var) = lookup(v)
 4896     (lookup *edx *(edx+4))  # => eax
 4897     89/<- %edx 0/r32/eax
 4898     # check v-addr->name
 4899     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 4900     (check-strings-equal %eax "x" "F - test-parse-var-with-compound-type/name")
 4901     # check v-addr->register
 4902     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-compound-type/register")  # Var-register
 4903     # - check v-addr->type
 4904     # var type/edx: (addr tree type-id) = var->type
 4905     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 4906     89/<- %edx 0/r32/eax
 4907     # type is a non-atom
 4908     (check-ints-equal *edx 0 "F - test-parse-var-with-compound-type/type:0")  # Tree-is-atom
 4909     # type->left == atom(addr)
 4910     (lookup *(edx+4) *(edx+8))  # Tree-left Tree-left => eax
 4911     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:1")  # Tree-is-atom
 4912     (check-ints-equal *(eax+4) 2 "F - test-parse-var-with-compound-type/type:2")  # Tree-value
 4913     # type->right->left == atom(int)
 4914     (lookup *(edx+0xc) *(edx+0x10))  # Tree-right Tree-right => eax
 4915     (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 4916     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:3")  # Tree-is-atom
 4917     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-compound-type/type:4")  # Tree-value
 4918     # type->right->right == null
 4919     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-compound-type/type:5")  # Tree-right
 4920     # . epilogue
 4921     89/<- %esp 5/r32/ebp
 4922     5d/pop-to-ebp
 4923     c3/return
 4924 
 4925 # identifier starts with a letter or '$' or '_'
 4926 # no constraints at the moment on later letters
 4927 # all we really want to do so far is exclude '{', '}' and '->'
 4928 is-identifier?:  # in: (addr slice) -> result/eax: boolean
 4929     # . prologue
 4930     55/push-ebp
 4931     89/<- %ebp 4/r32/esp
 4932     # if (slice-empty?(in)) return false
 4933     (slice-empty? *(ebp+8))  # => eax
 4934     3d/compare-eax-and 0/imm32/false
 4935     75/jump-if-!= $is-identifier?:false/disp8
 4936     # var c/eax: byte = *in->start
 4937     8b/-> *(ebp+8) 0/r32/eax
 4938     8b/-> *eax 0/r32/eax
 4939     8a/copy-byte *eax 0/r32/AL
 4940     81 4/subop/and %eax 0xff/imm32
 4941     # if (c == '$') return true
 4942     3d/compare-eax-and 0x24/imm32/$
 4943     74/jump-if-= $is-identifier?:true/disp8
 4944     # if (c == '_') return true
 4945     3d/compare-eax-and 0x5f/imm32/_
 4946     74/jump-if-= $is-identifier?:true/disp8
 4947     # drop case
 4948     25/and-eax-with 0x5f/imm32
 4949     # if (c < 'A') return false
 4950     3d/compare-eax-and 0x41/imm32/A
 4951     7c/jump-if-< $is-identifier?:false/disp8
 4952     # if (c > 'Z') return false
 4953     3d/compare-eax-and 0x5a/imm32/Z
 4954     7f/jump-if-> $is-identifier?:false/disp8
 4955     # otherwise return true
 4956 $is-identifier?:true:
 4957     b8/copy-to-eax 1/imm32/true
 4958     eb/jump $is-identifier?:end/disp8
 4959 $is-identifier?:false:
 4960     b8/copy-to-eax 0/imm32/false
 4961 $is-identifier?:end:
 4962     # . epilogue
 4963     89/<- %esp 5/r32/ebp
 4964     5d/pop-to-ebp
 4965     c3/return
 4966 
 4967 test-is-identifier-dollar:
 4968     # . prologue
 4969     55/push-ebp
 4970     89/<- %ebp 4/r32/esp
 4971     # (eax..ecx) = "$a"
 4972     b8/copy-to-eax "$a"/imm32
 4973     8b/-> *eax 1/r32/ecx
 4974     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 4975     05/add-to-eax 4/imm32
 4976     # var slice/ecx: slice = {eax, ecx}
 4977     51/push-ecx
 4978     50/push-eax
 4979     89/<- %ecx 4/r32/esp
 4980     #
 4981     (is-identifier? %ecx)
 4982     (check-ints-equal %eax 1 "F - test-is-identifier-dollar")
 4983     # . epilogue
 4984     89/<- %esp 5/r32/ebp
 4985     5d/pop-to-ebp
 4986     c3/return
 4987 
 4988 test-is-identifier-underscore:
 4989     # . prologue
 4990     55/push-ebp
 4991     89/<- %ebp 4/r32/esp
 4992     # (eax..ecx) = "_a"
 4993     b8/copy-to-eax "_a"/imm32
 4994     8b/-> *eax 1/r32/ecx
 4995     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 4996     05/add-to-eax 4/imm32
 4997     # var slice/ecx: slice = {eax, ecx}
 4998     51/push-ecx
 4999     50/push-eax
 5000     89/<- %ecx 4/r32/esp
 5001     #
 5002     (is-identifier? %ecx)
 5003     (check-ints-equal %eax 1 "F - test-is-identifier-underscore")
 5004     # . epilogue
 5005     89/<- %esp 5/r32/ebp
 5006     5d/pop-to-ebp
 5007     c3/return
 5008 
 5009 test-is-identifier-a:
 5010     # . prologue
 5011     55/push-ebp
 5012     89/<- %ebp 4/r32/esp
 5013     # (eax..ecx) = "a$"
 5014     b8/copy-to-eax "a$"/imm32
 5015     8b/-> *eax 1/r32/ecx
 5016     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5017     05/add-to-eax 4/imm32
 5018     # var slice/ecx: slice = {eax, ecx}
 5019     51/push-ecx
 5020     50/push-eax
 5021     89/<- %ecx 4/r32/esp
 5022     #
 5023     (is-identifier? %ecx)
 5024     (check-ints-equal %eax 1 "F - test-is-identifier-a")
 5025     # . epilogue
 5026     89/<- %esp 5/r32/ebp
 5027     5d/pop-to-ebp
 5028     c3/return
 5029 
 5030 test-is-identifier-z:
 5031     # . prologue
 5032     55/push-ebp
 5033     89/<- %ebp 4/r32/esp
 5034     # (eax..ecx) = "z$"
 5035     b8/copy-to-eax "z$"/imm32
 5036     8b/-> *eax 1/r32/ecx
 5037     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5038     05/add-to-eax 4/imm32
 5039     # var slice/ecx: slice = {eax, ecx}
 5040     51/push-ecx
 5041     50/push-eax
 5042     89/<- %ecx 4/r32/esp
 5043     #
 5044     (is-identifier? %ecx)
 5045     (check-ints-equal %eax 1 "F - test-is-identifier-z")
 5046     # . epilogue
 5047     89/<- %esp 5/r32/ebp
 5048     5d/pop-to-ebp
 5049     c3/return
 5050 
 5051 test-is-identifier-A:
 5052     # . prologue
 5053     55/push-ebp
 5054     89/<- %ebp 4/r32/esp
 5055     # (eax..ecx) = "A$"
 5056     b8/copy-to-eax "A$"/imm32
 5057     8b/-> *eax 1/r32/ecx
 5058     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5059     05/add-to-eax 4/imm32
 5060     # var slice/ecx: slice = {eax, ecx}
 5061     51/push-ecx
 5062     50/push-eax
 5063     89/<- %ecx 4/r32/esp
 5064     #
 5065     (is-identifier? %ecx)
 5066     (check-ints-equal %eax 1 "F - test-is-identifier-A")
 5067     # . epilogue
 5068     89/<- %esp 5/r32/ebp
 5069     5d/pop-to-ebp
 5070     c3/return
 5071 
 5072 test-is-identifier-Z:
 5073     # . prologue
 5074     55/push-ebp
 5075     89/<- %ebp 4/r32/esp
 5076     # (eax..ecx) = "Z$"
 5077     b8/copy-to-eax "Z$"/imm32
 5078     8b/-> *eax 1/r32/ecx
 5079     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5080     05/add-to-eax 4/imm32
 5081     # var slice/ecx: slice = {eax, ecx}
 5082     51/push-ecx
 5083     50/push-eax
 5084     89/<- %ecx 4/r32/esp
 5085     #
 5086     (is-identifier? %ecx)
 5087     (check-ints-equal %eax 1 "F - test-is-identifier-Z")
 5088     # . epilogue
 5089     89/<- %esp 5/r32/ebp
 5090     5d/pop-to-ebp
 5091     c3/return
 5092 
 5093 test-is-identifier-at:
 5094     # character before 'A' is invalid
 5095     # . prologue
 5096     55/push-ebp
 5097     89/<- %ebp 4/r32/esp
 5098     # (eax..ecx) = "@a"
 5099     b8/copy-to-eax "@a"/imm32
 5100     8b/-> *eax 1/r32/ecx
 5101     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5102     05/add-to-eax 4/imm32
 5103     # var slice/ecx: slice = {eax, ecx}
 5104     51/push-ecx
 5105     50/push-eax
 5106     89/<- %ecx 4/r32/esp
 5107     #
 5108     (is-identifier? %ecx)
 5109     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 5110     # . epilogue
 5111     89/<- %esp 5/r32/ebp
 5112     5d/pop-to-ebp
 5113     c3/return
 5114 
 5115 test-is-identifier-square-bracket:
 5116     # character after 'Z' is invalid
 5117     # . prologue
 5118     55/push-ebp
 5119     89/<- %ebp 4/r32/esp
 5120     # (eax..ecx) = "[a"
 5121     b8/copy-to-eax "[a"/imm32
 5122     8b/-> *eax 1/r32/ecx
 5123     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5124     05/add-to-eax 4/imm32
 5125     # var slice/ecx: slice = {eax, ecx}
 5126     51/push-ecx
 5127     50/push-eax
 5128     89/<- %ecx 4/r32/esp
 5129     #
 5130     (is-identifier? %ecx)
 5131     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 5132     # . epilogue
 5133     89/<- %esp 5/r32/ebp
 5134     5d/pop-to-ebp
 5135     c3/return
 5136 
 5137 test-is-identifier-backtick:
 5138     # character before 'a' is invalid
 5139     # . prologue
 5140     55/push-ebp
 5141     89/<- %ebp 4/r32/esp
 5142     # (eax..ecx) = "`a"
 5143     b8/copy-to-eax "`a"/imm32
 5144     8b/-> *eax 1/r32/ecx
 5145     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5146     05/add-to-eax 4/imm32
 5147     # var slice/ecx: slice = {eax, ecx}
 5148     51/push-ecx
 5149     50/push-eax
 5150     89/<- %ecx 4/r32/esp
 5151     #
 5152     (is-identifier? %ecx)
 5153     (check-ints-equal %eax 0 "F - test-is-identifier-backtick")
 5154     # . epilogue
 5155     89/<- %esp 5/r32/ebp
 5156     5d/pop-to-ebp
 5157     c3/return
 5158 
 5159 test-is-identifier-curly-brace-open:
 5160     # character after 'z' is invalid; also used for blocks
 5161     # . prologue
 5162     55/push-ebp
 5163     89/<- %ebp 4/r32/esp
 5164     # (eax..ecx) = "{a"
 5165     b8/copy-to-eax "{a"/imm32
 5166     8b/-> *eax 1/r32/ecx
 5167     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5168     05/add-to-eax 4/imm32
 5169     # var slice/ecx: slice = {eax, ecx}
 5170     51/push-ecx
 5171     50/push-eax
 5172     89/<- %ecx 4/r32/esp
 5173     #
 5174     (is-identifier? %ecx)
 5175     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open")
 5176     # . epilogue
 5177     89/<- %esp 5/r32/ebp
 5178     5d/pop-to-ebp
 5179     c3/return
 5180 
 5181 test-is-identifier-curly-brace-close:
 5182     # . prologue
 5183     55/push-ebp
 5184     89/<- %ebp 4/r32/esp
 5185     # (eax..ecx) = "}a"
 5186     b8/copy-to-eax "}a"/imm32
 5187     8b/-> *eax 1/r32/ecx
 5188     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5189     05/add-to-eax 4/imm32
 5190     # var slice/ecx: slice = {eax, ecx}
 5191     51/push-ecx
 5192     50/push-eax
 5193     89/<- %ecx 4/r32/esp
 5194     #
 5195     (is-identifier? %ecx)
 5196     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close")
 5197     # . epilogue
 5198     89/<- %esp 5/r32/ebp
 5199     5d/pop-to-ebp
 5200     c3/return
 5201 
 5202 test-is-identifier-hyphen:
 5203     # disallow leading '-' since '->' has special meaning
 5204     # . prologue
 5205     55/push-ebp
 5206     89/<- %ebp 4/r32/esp
 5207     # (eax..ecx) = "-a"
 5208     b8/copy-to-eax "-a"/imm32
 5209     8b/-> *eax 1/r32/ecx
 5210     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5211     05/add-to-eax 4/imm32
 5212     # var slice/ecx: slice = {eax, ecx}
 5213     51/push-ecx
 5214     50/push-eax
 5215     89/<- %ecx 4/r32/esp
 5216     #
 5217     (is-identifier? %ecx)
 5218     (check-ints-equal %eax 0 "F - test-is-identifier-hyphen")
 5219     # . epilogue
 5220     89/<- %esp 5/r32/ebp
 5221     5d/pop-to-ebp
 5222     c3/return
 5223 
 5224 populate-mu-function-body:  # in: (addr buffered-file), out: (addr function), vars: (addr stack (handle var))
 5225     # . prologue
 5226     55/push-ebp
 5227     89/<- %ebp 4/r32/esp
 5228     # . save registers
 5229     50/push-eax
 5230     56/push-esi
 5231     57/push-edi
 5232     # esi = in
 5233     8b/-> *(ebp+8) 6/r32/esi
 5234     # edi = out
 5235     8b/-> *(ebp+0xc) 7/r32/edi
 5236     # parse-mu-block(in, vars, out, out->body)
 5237     8d/copy-address *(edi+0x18) 0/r32/eax  # Function-body
 5238     (parse-mu-block %esi *(ebp+0x10) %edi %eax)
 5239 $populate-mu-function-body:end:
 5240     # . restore registers
 5241     5f/pop-to-edi
 5242     5e/pop-to-esi
 5243     58/pop-to-eax
 5244     # . epilogue
 5245     89/<- %esp 5/r32/ebp
 5246     5d/pop-to-ebp
 5247     c3/return
 5248 
 5249 # parses a block, assuming that the leading '{' has already been read by the caller
 5250 parse-mu-block:  # in: (addr buffered-file), vars: (addr stack (handle var)), fn: (addr function), out: (addr handle block)
 5251     # pseudocode:
 5252     #   var line: (stream byte 512)
 5253     #   var word-slice: slice
 5254     #   allocate(Heap, Stmt-size, out)
 5255     #   var out-addr: (addr block) = lookup(*out)
 5256     #   out-addr->tag = 0/block
 5257     #   out-addr->var = some unique name
 5258     #   push(vars, out-addr->var)
 5259     #   while true                                  # line loop
 5260     #     clear-stream(line)
 5261     #     read-line-buffered(in, line)
 5262     #     if (line->write == 0) break               # end of file
 5263     #     word-slice = next-mu-token(line)
 5264     #     if slice-empty?(word-slice)               # end of line
 5265     #       continue
 5266     #     else if slice-starts-with?(word-slice, "#")
 5267     #       continue
 5268     #     else if slice-equal?(word-slice, "{")
 5269     #       assert(no-tokens-in(line))
 5270     #       block = parse-mu-block(in, vars, fn)
 5271     #       append-to-block(out-addr, block)
 5272     #     else if slice-equal?(word-slice, "}")
 5273     #       break
 5274     #     else if slice-ends-with?(word-slice, ":")
 5275     #       # TODO: error-check the rest of 'line'
 5276     #       --word-slice->end to skip ':'
 5277     #       named-block = parse-mu-named-block(word-slice, in, vars, fn)
 5278     #       append-to-block(out-addr, named-block)
 5279     #     else if slice-equal?(word-slice, "var")
 5280     #       var-def = parse-mu-var-def(line, vars)
 5281     #       append-to-block(out-addr, var-def)
 5282     #     else
 5283     #       stmt = parse-mu-stmt(line, vars, fn)
 5284     #       append-to-block(out-addr, stmt)
 5285     #   pop(vars)
 5286     #
 5287     # . prologue
 5288     55/push-ebp
 5289     89/<- %ebp 4/r32/esp
 5290     # . save registers
 5291     50/push-eax
 5292     51/push-ecx
 5293     52/push-edx
 5294     53/push-ebx
 5295     57/push-edi
 5296     # var line/ecx: (stream byte 512)
 5297     81 5/subop/subtract %esp 0x200/imm32
 5298     68/push 0x200/imm32/size
 5299     68/push 0/imm32/read
 5300     68/push 0/imm32/write
 5301     89/<- %ecx 4/r32/esp
 5302     # var word-slice/edx: slice
 5303     68/push 0/imm32/end
 5304     68/push 0/imm32/start
 5305     89/<- %edx 4/r32/esp
 5306     # allocate into out
 5307     (allocate Heap *Stmt-size *(ebp+0x14))
 5308     # var out-addr/edi: (addr block) = lookup(*out)
 5309     8b/-> *(ebp+0x14) 7/r32/edi
 5310     (lookup *edi *(edi+4))  # => eax
 5311     89/<- %edi 0/r32/eax
 5312     # out-addr->tag is 0 (block) by default
 5313     # set out-addr->var
 5314     8d/copy-address *(edi+0xc) 0/r32/eax  # Block-var
 5315     (new-block-name *(ebp+0x10) %eax)
 5316     # push(vars, out-addr->var)
 5317     (push *(ebp+0xc) *(edi+0xc))  # Block-var
 5318     (push *(ebp+0xc) *(edi+0x10))  # Block-var
 5319     {
 5320 $parse-mu-block:line-loop:
 5321       # line = read-line-buffered(in)
 5322       (clear-stream %ecx)
 5323       (read-line-buffered *(ebp+8) %ecx)
 5324 #?       (write-buffered Stderr "line: ")
 5325 #?       (write-stream-data Stderr %ecx)
 5326 #?       (write-buffered Stderr Newline)
 5327 #?       (flush Stderr)
 5328       # if (line->write == 0) break
 5329       81 7/subop/compare *ecx 0/imm32
 5330       0f 84/jump-if-= break/disp32
 5331       # word-slice = next-mu-token(line)
 5332       (next-mu-token %ecx %edx)
 5333 #?       (write-buffered Stderr "word: ")
 5334 #?       (write-slice-buffered Stderr %edx)
 5335 #?       (write-buffered Stderr Newline)
 5336 #?       (flush Stderr)
 5337       # if slice-empty?(word-slice) continue
 5338       (slice-empty? %edx)
 5339       3d/compare-eax-and 0/imm32/false
 5340       0f 85/jump-if-!= loop/disp32
 5341       # if (slice-starts-with?(word-slice, '#') continue
 5342       # . eax = *word-slice->start
 5343       8b/-> *edx 0/r32/eax
 5344       8a/copy-byte *eax 0/r32/AL
 5345       81 4/subop/and %eax 0xff/imm32
 5346       # . if (eax == '#') continue
 5347       3d/compare-eax-and 0x23/imm32/hash
 5348       0f 84/jump-if-= loop/disp32
 5349       # if slice-equal?(word-slice, "{")
 5350       {
 5351 $parse-mu-block:check-for-block:
 5352         (slice-equal? %edx "{")
 5353         3d/compare-eax-and 0/imm32/false
 5354         74/jump-if-= break/disp8
 5355         (check-no-tokens-left %ecx)
 5356         # parse new block and append
 5357         # . var tmp/eax: (handle block)
 5358         68/push 0/imm32
 5359         68/push 0/imm32
 5360         89/<- %eax 4/r32/esp
 5361         # .
 5362         (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax)
 5363         (append-to-block Heap %edi  *eax *(eax+4))
 5364         # . reclaim tmp
 5365         81 0/subop/add %esp 8/imm32
 5366         # .
 5367         e9/jump $parse-mu-block:line-loop/disp32
 5368       }
 5369       # if slice-equal?(word-slice, "}") break
 5370 $parse-mu-block:check-for-end:
 5371       (slice-equal? %edx "}")
 5372       3d/compare-eax-and 0/imm32/false
 5373       0f 85/jump-if-!= break/disp32
 5374       # if slice-ends-with?(word-slice, ":") parse named block and append
 5375       {
 5376 $parse-mu-block:check-for-named-block:
 5377         # . eax = *(word-slice->end-1)
 5378         8b/-> *(edx+4) 0/r32/eax
 5379         48/decrement-eax
 5380         8a/copy-byte *eax 0/r32/AL
 5381         81 4/subop/and %eax 0xff/imm32
 5382         # . if (eax != ':') break
 5383         3d/compare-eax-and 0x3a/imm32/colon
 5384         0f 85/jump-if-!= break/disp32
 5385         # TODO: error-check the rest of 'line'
 5386         #
 5387         # skip ':'
 5388         ff 1/subop/decrement *(edx+4)  # Slice-end
 5389         # var tmp/eax: (handle block)
 5390         68/push 0/imm32
 5391         68/push 0/imm32
 5392         89/<- %eax 4/r32/esp
 5393         #
 5394         (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax)
 5395         (append-to-block Heap %edi  *eax *(eax+4))
 5396         # reclaim tmp
 5397         81 0/subop/add %esp 8/imm32
 5398         #
 5399         e9/jump $parse-mu-block:line-loop/disp32
 5400       }
 5401       # if slice-equal?(word-slice, "var")
 5402       {
 5403 $parse-mu-block:check-for-var:
 5404         (slice-equal? %edx "var")
 5405         3d/compare-eax-and 0/imm32/false
 5406         74/jump-if-= break/disp8
 5407         # var tmp/eax: (handle block)
 5408         68/push 0/imm32
 5409         68/push 0/imm32
 5410         89/<- %eax 4/r32/esp
 5411         #
 5412         (parse-mu-var-def %ecx *(ebp+0xc) %eax)
 5413         (append-to-block Heap %edi  *eax *(eax+4))
 5414         # reclaim tmp
 5415         81 0/subop/add %esp 8/imm32
 5416         #
 5417         e9/jump $parse-mu-block:line-loop/disp32
 5418       }
 5419 $parse-mu-block:regular-stmt:
 5420       # otherwise
 5421       # var tmp/eax: (handle block)
 5422       68/push 0/imm32
 5423       68/push 0/imm32
 5424       89/<- %eax 4/r32/esp
 5425       #
 5426       (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10) %eax)
 5427       (append-to-block Heap %edi  *eax *(eax+4))
 5428       # reclaim tmp
 5429       81 0/subop/add %esp 8/imm32
 5430       #
 5431       e9/jump loop/disp32
 5432     } # end line loop
 5433     # pop(vars)
 5434     (pop *(ebp+0xc))  # => eax
 5435     (pop *(ebp+0xc))  # => eax
 5436 $parse-mu-block:end:
 5437     # . reclaim locals
 5438     81 0/subop/add %esp 0x214/imm32
 5439     # . restore registers
 5440     5f/pop-to-edi
 5441     5b/pop-to-ebx
 5442     5a/pop-to-edx
 5443     59/pop-to-ecx
 5444     58/pop-to-eax
 5445     # . epilogue
 5446     89/<- %esp 5/r32/ebp
 5447     5d/pop-to-ebp
 5448     c3/return
 5449 
 5450 $parse-mu-block:abort:
 5451     # error("'{' or '}' should be on its own line, but got '")
 5452     (write-buffered Stderr "'{' or '}' should be on its own line, but got '")
 5453     (rewind-stream %ecx)
 5454     (write-stream 2 %ecx)
 5455     (write-buffered Stderr "'\n")
 5456     (flush Stderr)
 5457     # . syscall(exit, 1)
 5458     bb/copy-to-ebx  1/imm32
 5459     b8/copy-to-eax  1/imm32/exit
 5460     cd/syscall  0x80/imm8
 5461     # never gets here
 5462 
 5463 new-block-name:  # fn: (addr function), out: (addr handle var)
 5464     # . prologue
 5465     55/push-ebp
 5466     89/<- %ebp 4/r32/esp
 5467     # . save registers
 5468     50/push-eax
 5469     51/push-ecx
 5470     52/push-edx
 5471     # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:'
 5472     8b/-> *(ebp+8) 0/r32/eax
 5473     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 5474     8b/-> *eax 0/r32/eax  # String-size
 5475     05/add-to-eax 0xd/imm32  # 10 + 2 for '$:'
 5476     89/<- %ecx 0/r32/eax
 5477     # var name/edx: (stream byte n)
 5478     29/subtract-from %esp 1/r32/ecx
 5479     ff 6/subop/push %ecx
 5480     68/push 0/imm32/read
 5481     68/push 0/imm32/write
 5482     89/<- %edx 4/r32/esp
 5483     (clear-stream %edx)
 5484     # eax = fn->name
 5485     8b/-> *(ebp+8) 0/r32/eax
 5486     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 5487     # construct result using Next-block-index (and increment it)
 5488     (write %edx "$")
 5489     (write %edx %eax)
 5490     (write %edx ":")
 5491     (print-int32 %edx *Next-block-index)
 5492     ff 0/subop/increment *Next-block-index
 5493     # var s/eax: slice = {name->data, name->data + name->write}  (clobbering edx)
 5494     # . eax = name->write
 5495     8b/-> *edx 0/r32/eax
 5496     # . edx = name->data
 5497     8d/copy-address *(edx+0xc) 2/r32/edx
 5498     # . eax = name->write + name->data
 5499     01/add-to %eax 2/r32/edx
 5500     # . push {edx, eax}
 5501     ff 6/subop/push %eax
 5502     ff 6/subop/push %edx
 5503     89/<- %eax 4/r32/esp
 5504     # out = new literal(s)
 5505     (new-literal Heap %eax *(ebp+0xc))
 5506 #?     8b/-> *(ebp+0xc) 0/r32/eax
 5507 #?     (write-buffered Stderr "type allocid in caller after new-literal: ")
 5508 #?     (print-int32-buffered Stderr *(eax+8))
 5509 #?     (write-buffered Stderr " for var ")
 5510 #?     (print-int32-buffered Stderr %eax)
 5511 #?     (write-buffered Stderr Newline)
 5512 #?     (flush Stderr)
 5513 $new-block-name:end:
 5514     # . reclaim locals
 5515     81 0/subop/add %ecx 0xc/imm32  # name.{read/write/len}
 5516     81 0/subop/add %ecx 8/imm32  # slice
 5517     01/add-to %esp 1/r32/ecx
 5518     # . restore registers
 5519     5a/pop-to-edx
 5520     59/pop-to-ecx
 5521     58/pop-to-eax
 5522     # . epilogue
 5523     89/<- %esp 5/r32/ebp
 5524     5d/pop-to-ebp
 5525     c3/return
 5526 
 5527 == data
 5528 
 5529 # Global state added to each var record when parsing a function
 5530 Next-block-index:  # (addr int)
 5531     1/imm32
 5532 
 5533 == code
 5534 
 5535 check-no-tokens-left:  # line: (addr stream byte)
 5536     # . prologue
 5537     55/push-ebp
 5538     89/<- %ebp 4/r32/esp
 5539     # . save registers
 5540     50/push-eax
 5541     51/push-ecx
 5542     # var s/ecx: slice
 5543     68/push 0/imm32/end
 5544     68/push 0/imm32/start
 5545     89/<- %ecx 4/r32/esp
 5546     #
 5547     (next-mu-token *(ebp+8) %ecx)
 5548     # if slice-empty?(s) return
 5549     (slice-empty? %ecx)
 5550     3d/compare-eax-and 0/imm32/false
 5551     75/jump-if-!= $check-no-tokens-left:end/disp8
 5552     # if (slice-starts-with?(s, '#') return
 5553     # . eax = *s->start
 5554     8b/-> *edx 0/r32/eax
 5555     8a/copy-byte *eax 0/r32/AL
 5556     81 4/subop/and %eax 0xff/imm32
 5557     # . if (eax == '#') continue
 5558     3d/compare-eax-and 0x23/imm32/hash
 5559     74/jump-if-= $check-no-tokens-left:end/disp8
 5560     # abort
 5561     (write-buffered Stderr "'{' or '}' should be on its own line, but got '")
 5562     (rewind-stream %ecx)
 5563     (write-stream 2 %ecx)
 5564     (write-buffered Stderr "'\n")
 5565     (flush Stderr)
 5566     # . syscall(exit, 1)
 5567     bb/copy-to-ebx  1/imm32
 5568     b8/copy-to-eax  1/imm32/exit
 5569     cd/syscall  0x80/imm8
 5570     # never gets here
 5571 $check-no-tokens-left:end:
 5572     # . reclaim locals
 5573     81 0/subop/add %esp 8/imm32
 5574     # . restore registers
 5575     59/pop-to-ecx
 5576     58/pop-to-eax
 5577     # . epilogue
 5578     89/<- %esp 5/r32/ebp
 5579     5d/pop-to-ebp
 5580     c3/return
 5581 
 5582 parse-mu-named-block:  # name: (addr slice), in: (addr buffered-file), vars: (addr stack (handle var)), fn: (addr function), out: (addr handle stmt)
 5583     # pseudocode:
 5584     #   var v: (handle var)
 5585     #   new-literal(name, v)
 5586     #   push(vars, v)
 5587     #   parse-mu-block(in, vars, fn, out)
 5588     #   pop(vars)
 5589     #   out->tag = block
 5590     #   out->var = v
 5591     #
 5592     # . prologue
 5593     55/push-ebp
 5594     89/<- %ebp 4/r32/esp
 5595     # . save registers
 5596     50/push-eax
 5597     51/push-ecx
 5598     57/push-edi
 5599     # var v/ecx: (handle var)
 5600     68/push 0/imm32
 5601     68/push 0/imm32
 5602     89/<- %ecx 4/r32/esp
 5603     #
 5604     (new-literal Heap *(ebp+8) %ecx)
 5605     # push(vars, v)
 5606     (push *(ebp+0x10) *ecx)
 5607     (push *(ebp+0x10) *(ecx+4))
 5608     #
 5609     (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
 5610     # pop v off vars
 5611     (pop *(ebp+0x10))  # => eax
 5612     (pop *(ebp+0x10))  # => eax
 5613     # var out-addr/edi: (addr stmt) = lookup(*out)
 5614     8b/-> *(ebp+0x18) 7/r32/edi
 5615     (lookup *edi *(edi+4))  # => eax
 5616     89/<- %edi 0/r32/eax
 5617     # out-addr->tag = named-block
 5618     c7 0/subop/copy *edi 0/imm32/block  # Stmt-tag
 5619     # out-addr->var = v
 5620     8b/-> *ecx 0/r32/eax
 5621     89/<- *(edi+0xc) 0/r32/eax  # Block-var
 5622     8b/-> *(ecx+4) 0/r32/eax
 5623     89/<- *(edi+0x10) 0/r32/eax  # Block-var
 5624 $parse-mu-named-block:end:
 5625     # . reclaim locals
 5626     81 0/subop/add %esp 8/imm32
 5627     # . restore registers
 5628     5f/pop-to-edi
 5629     59/pop-to-ecx
 5630     58/pop-to-eax
 5631     # . epilogue
 5632     89/<- %esp 5/r32/ebp
 5633     5d/pop-to-ebp
 5634     c3/return
 5635 
 5636 parse-mu-var-def:  # line: (addr stream byte), vars: (addr stack (handle var)), out: (addr handle stmt)
 5637     # . prologue
 5638     55/push-ebp
 5639     89/<- %ebp 4/r32/esp
 5640     # . save registers
 5641     50/push-eax
 5642     51/push-ecx
 5643     52/push-edx
 5644     57/push-edi
 5645     # edi = out
 5646     8b/-> *(ebp+0x10) 7/r32/edi
 5647     # var word-slice/ecx: slice
 5648     68/push 0/imm32/end
 5649     68/push 0/imm32/start
 5650     89/<- %ecx 4/r32/esp
 5651     # var v/edx: (handle var)
 5652     68/push 0/imm32
 5653     68/push 0/imm32
 5654     89/<- %edx 4/r32/esp
 5655     # v = parse-var-with-type(next-mu-token(line))
 5656     (next-mu-token *(ebp+8) %ecx)
 5657     (parse-var-with-type %ecx *(ebp+8) %edx)
 5658     #
 5659     (push *(ebp+0xc) *edx)
 5660     (push *(ebp+0xc) *(edx+4))
 5661     # either v has no register and there's no more to this line
 5662     (lookup *edx *(edx+4))  # => eax
 5663     8b/-> *(eax+0x18) 0/r32/eax  # Var-register
 5664     3d/compare-eax-and 0/imm32
 5665     {
 5666       75/jump-if-!= break/disp8
 5667       # TODO: ensure that there's nothing else on this line
 5668       (new-var-def Heap  *edx *(edx+4)  %edi)
 5669       eb/jump $parse-mu-var-def:end/disp8
 5670     }
 5671     # or v has a register and there's more to this line
 5672     {
 5673       74/jump-if-= break/disp8
 5674       # ensure that the next word is '<-'
 5675       (next-mu-token *(ebp+8) %ecx)
 5676       (slice-equal? %ecx "<-")  # => eax
 5677       3d/compare-eax-and 0/imm32/false
 5678       74/jump-if-= $parse-mu-var-def:abort/disp8
 5679       #
 5680       (new-reg-var-def Heap  *edx *(edx+4)  %edi)
 5681       (lookup *edi *(edi+4))  # => eax
 5682       (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc))
 5683     }
 5684 $parse-mu-var-def:end:
 5685     # . reclaim locals
 5686     81 0/subop/add %esp 0x10/imm32
 5687     # . restore registers
 5688     5f/pop-to-edi
 5689     5a/pop-to-edx
 5690     59/pop-to-ecx
 5691     58/pop-to-eax
 5692     # . epilogue
 5693     89/<- %esp 5/r32/ebp
 5694     5d/pop-to-ebp
 5695     c3/return
 5696 
 5697 $parse-mu-var-def:abort:
 5698     (rewind-stream *(ebp+8))
 5699     # error("register variable requires a valid instruction to initialize but got '" line "'\n")
 5700     (write-buffered Stderr "register variable requires a valid instruction to initialize but got '")
 5701     (flush Stderr)
 5702     (write-stream 2 *(ebp+8))
 5703     (write-buffered Stderr "'\n")
 5704     (flush Stderr)
 5705     # . syscall(exit, 1)
 5706     bb/copy-to-ebx  1/imm32
 5707     b8/copy-to-eax  1/imm32/exit
 5708     cd/syscall  0x80/imm8
 5709     # never gets here
 5710 
 5711 test-parse-mu-var-def:
 5712     # 'var n: int'
 5713     # . prologue
 5714     55/push-ebp
 5715     89/<- %ebp 4/r32/esp
 5716     # setup
 5717     (clear-stream _test-input-stream)
 5718     (write _test-input-stream "n: int\n")  # caller has consumed the 'var'
 5719     # var out/esi: (handle stmt)
 5720     68/push 0/imm32
 5721     68/push 0/imm32
 5722     89/<- %esi 4/r32/esp
 5723     # var vars/ecx: (stack (addr var) 16)
 5724     81 5/subop/subtract %esp 0x80/imm32
 5725     68/push 0x80/imm32/size
 5726     68/push 0/imm32/top
 5727     89/<- %ecx 4/r32/esp
 5728     (clear-stack %ecx)
 5729     # convert
 5730     (parse-mu-var-def _test-input-stream %ecx %esi)
 5731     # var out-addr/esi: (addr stmt)
 5732     (lookup *esi *(esi+4))  # => eax
 5733     89/<- %esi 0/r32/eax
 5734     #
 5735     (check-ints-equal *esi 2 "F - test-parse-mu-var-def/tag")  # Stmt-tag is var-def
 5736     # var v/ecx: (addr var) = lookup(out->var)
 5737     (lookup *(esi+4) *(esi+8))  # Vardef-var Vardef-var => eax
 5738     89/<- %ecx 0/r32/eax
 5739     # v->name
 5740     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 5741     (check-strings-equal %eax "n" "F - test-parse-mu-var-def/var-name")
 5742     # v->register
 5743     (check-ints-equal *(ecx+0x18) 0 "F - test-parse-mu-var-def/var-register")  # Var-register
 5744     # v->type == int
 5745     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 5746     (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0")  # Tree-is-atom
 5747     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-var-def/var-type:1")  # Tree-value
 5748     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-var-def/var-type:2")  # Tree-right
 5749     # . epilogue
 5750     89/<- %esp 5/r32/ebp
 5751     5d/pop-to-ebp
 5752     c3/return
 5753 
 5754 test-parse-mu-reg-var-def:
 5755     # 'var n/eax: int <- copy 0'
 5756     # . prologue
 5757     55/push-ebp
 5758     89/<- %ebp 4/r32/esp
 5759     # setup
 5760     (clear-stream _test-input-stream)
 5761     (write _test-input-stream "n/eax: int <- copy 0\n")  # caller has consumed the 'var'
 5762     # var out/esi: (handle stmt)
 5763     68/push 0/imm32
 5764     68/push 0/imm32
 5765     89/<- %esi 4/r32/esp
 5766     # var vars/ecx: (stack (addr var) 16)
 5767     81 5/subop/subtract %esp 0x80/imm32
 5768     68/push 0x80/imm32/size
 5769     68/push 0/imm32/top
 5770     89/<- %ecx 4/r32/esp
 5771     (clear-stack %ecx)
 5772     # convert
 5773     (parse-mu-var-def _test-input-stream %ecx %esi)
 5774     # var out-addr/esi: (addr stmt)
 5775     (lookup *esi *(esi+4))  # => eax
 5776     89/<- %esi 0/r32/eax
 5777     #
 5778     (check-ints-equal *esi 3 "F - test-parse-mu-reg-var-def/tag")  # Stmt-tag is reg-var-def
 5779     # var v/ecx: (addr var) = lookup(out->outputs->value)
 5780     # . eax: (addr stmt-var) = lookup(out->outputs)
 5781     (lookup *(esi+0x14) *(esi+0x18))  # Regvardef-outputs Regvardef-outputs => eax
 5782     # .
 5783     (check-ints-equal *(eax+8) 0 "F - test-parse-mu-reg-var-def/single-output")  # Stmt-var-next
 5784     # . eax: (addr var) = lookup(eax->value)
 5785     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 5786     # . ecx = eax
 5787     89/<- %ecx 0/r32/eax
 5788     # v->name
 5789     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 5790     (check-strings-equal %eax "n" "F - test-parse-mu-reg-var-def/output-name")  # Var-name
 5791     # v->register
 5792     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 5793     (check-strings-equal %eax "eax" "F - test-parse-mu-reg-var-def/output-register")
 5794     # v->type == int
 5795     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 5796     (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0")  # Tree-is-atom
 5797     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-reg-var-def/output-type:1")  # Tree-value
 5798     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-type:2")  # Tree-right
 5799     # . epilogue
 5800     89/<- %esp 5/r32/ebp
 5801     5d/pop-to-ebp
 5802     c3/return
 5803 
 5804 parse-mu-stmt:  # line: (addr stream byte), vars: (addr stack (handle var)), fn: (addr function), out: (addr handle stmt)
 5805     # pseudocode:
 5806     #   var name: slice
 5807     #   allocate(Heap, Stmt-size, out)
 5808     #   var out-addr: (addr stmt) = lookup(*out)
 5809     #   out-addr->tag = stmt
 5810     #   if stmt-has-outputs?(line)
 5811     #     while true
 5812     #       name = next-mu-token(line)
 5813     #       if (name == '<-') break
 5814     #       assert(is-identifier?(name))
 5815     #       var v: (handle var) = lookup-or-define-var(name, vars, fn)  # regular stmts may define vars in fn outputs
 5816     #       out-addr->outputs = append(v, out-addr->outputs)
 5817     #   add-operation-and-inputs-to-stmt(out-addr, line, vars)
 5818     #
 5819     # . prologue
 5820     55/push-ebp
 5821     89/<- %ebp 4/r32/esp
 5822     # . save registers
 5823     50/push-eax
 5824     51/push-ecx
 5825     52/push-edx
 5826     53/push-ebx
 5827     57/push-edi
 5828     # var name/ecx: slice
 5829     68/push 0/imm32/end
 5830     68/push 0/imm32/start
 5831     89/<- %ecx 4/r32/esp
 5832     # var is-deref?/edx: boolean = false
 5833     ba/copy-to-edx 0/imm32/false
 5834     # var v: (handle var)
 5835     68/push 0/imm32
 5836     68/push 0/imm32
 5837     89/<- %ebx 4/r32/esp
 5838     #
 5839     (allocate Heap *Stmt-size *(ebp+0x14))
 5840     # var out-addr/edi: (addr stmt) = lookup(*out)
 5841     8b/-> *(ebp+0x14) 7/r32/edi
 5842     (lookup *edi *(edi+4))  # => eax
 5843     89/<- %edi 0/r32/eax
 5844     # out-addr->tag = 1/stmt
 5845     c7 0/subop/copy *edi 1/imm32/stmt1  # Stmt-tag
 5846     {
 5847       (stmt-has-outputs? *(ebp+8))
 5848       3d/compare-eax-and 0/imm32/false
 5849       0f 84/jump-if-= break/disp32
 5850       {
 5851 $parse-mu-stmt:read-outputs:
 5852         # name = next-mu-token(line)
 5853         (next-mu-token *(ebp+8) %ecx)
 5854         # if slice-empty?(word-slice) break
 5855         (slice-empty? %ecx)  # => eax
 5856         3d/compare-eax-and 0/imm32/false
 5857         0f 85/jump-if-!= break/disp32
 5858         # if (name == "<-") break
 5859         (slice-equal? %ecx "<-")  # => eax
 5860         3d/compare-eax-and 0/imm32/false
 5861         0f 85/jump-if-!= break/disp32
 5862         # is-deref? = false
 5863         ba/copy-to-edx 0/imm32/false
 5864         # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 5865         8b/-> *ecx 0/r32/eax  # Slice-start
 5866         8a/copy-byte *eax 0/r32/AL
 5867         81 4/subop/and %eax 0xff/imm32
 5868         3d/compare-eax-and 0x2a/imm32/asterisk
 5869         {
 5870           75/jump-if-!= break/disp8
 5871           ff 0/subop/increment *ecx
 5872           ba/copy-to-edx 1/imm32/true
 5873         }
 5874         # assert(is-identifier?(name))
 5875         (is-identifier? %ecx)  # => eax
 5876         3d/compare-eax-and 0/imm32/false
 5877         0f 84/jump-if-= $parse-mu-stmt:abort/disp32
 5878         #
 5879         (lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10) %ebx)
 5880         8d/copy-address *(edi+0x14) 0/r32/eax  # Stmt1-outputs
 5881         (append-stmt-var Heap  *ebx *(ebx+4)  *(edi+0x14) *(edi+0x18)  %edx  %eax)  # Stmt1-outputs
 5882         #
 5883         e9/jump loop/disp32
 5884       }
 5885     }
 5886     (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc))
 5887 $parse-mu-stmt:end:
 5888     # . reclaim locals
 5889     81 0/subop/add %esp 0x10/imm32
 5890     # . restore registers
 5891     5f/pop-to-edi
 5892     5b/pop-to-ebx
 5893     5a/pop-to-edx
 5894     59/pop-to-ecx
 5895     58/pop-to-eax
 5896     # . epilogue
 5897     89/<- %esp 5/r32/ebp
 5898     5d/pop-to-ebp
 5899     c3/return
 5900 
 5901 $parse-mu-stmt:abort:
 5902     # error("invalid identifier '" name "'\n")
 5903     (write-buffered Stderr "invalid identifier '")
 5904     (write-slice-buffered Stderr %ecx)
 5905     (write-buffered Stderr "'\n")
 5906     (flush Stderr)
 5907     # . syscall(exit, 1)
 5908     bb/copy-to-ebx  1/imm32
 5909     b8/copy-to-eax  1/imm32/exit
 5910     cd/syscall  0x80/imm8
 5911     # never gets here
 5912 
 5913 add-operation-and-inputs-to-stmt:  # stmt: (addr stmt), line: (addr stream byte), vars: (addr stack (handle var))
 5914     # pseudocode:
 5915     #   stmt->name = slice-to-string(next-mu-token(line))
 5916     #   while true
 5917     #     name = next-mu-token(line)
 5918     #     v = lookup-var-or-literal(name)
 5919     #     stmt->inouts = append(v, stmt->inouts)
 5920     #
 5921     # . prologue
 5922     55/push-ebp
 5923     89/<- %ebp 4/r32/esp
 5924     # . save registers
 5925     50/push-eax
 5926     51/push-ecx
 5927     52/push-edx
 5928     53/push-ebx
 5929     56/push-esi
 5930     57/push-edi
 5931     # edi = stmt
 5932     8b/-> *(ebp+8) 7/r32/edi
 5933     # var name/ecx: slice
 5934     68/push 0/imm32/end
 5935     68/push 0/imm32/start
 5936     89/<- %ecx 4/r32/esp
 5937     # var is-deref?/edx: boolean = false
 5938     ba/copy-to-edx 0/imm32/false
 5939     # var v/esi: (handle var)
 5940     68/push 0/imm32
 5941     68/push 0/imm32
 5942     89/<- %esi 4/r32/esp
 5943 $add-operation-and-inputs-to-stmt:read-operation:
 5944     (next-mu-token *(ebp+0xc) %ecx)
 5945     8d/copy-address *(edi+4) 0/r32/eax  # Stmt1-operation or Regvardef-operationStmt1-operation or Regvardef-operation
 5946     (slice-to-string Heap %ecx %eax)
 5947     # var is-get?/ebx: boolean = (name == "get")
 5948     (slice-equal? %ecx "get")  # => eax
 5949     89/<- %ebx 0/r32/eax
 5950     {
 5951 $add-operation-and-inputs-to-stmt:read-inouts:
 5952       # name = next-mu-token(line)
 5953       (next-mu-token *(ebp+0xc) %ecx)
 5954       # if slice-empty?(word-slice) break
 5955       (slice-empty? %ecx)  # => eax
 5956       3d/compare-eax-and 0/imm32/false
 5957       0f 85/jump-if-!= break/disp32
 5958       # if (name == "<-") abort
 5959       (slice-equal? %ecx "<-")
 5960       3d/compare-eax-and 0/imm32/false
 5961       0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32
 5962       # if (is-get? && second operand) lookup or create offset
 5963       {
 5964         81 7/subop/compare %ebx 0/imm32/false
 5965         74/jump-if-= break/disp8
 5966         (lookup *(edi+0xc) *(edi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 5967         3d/compare-eax-and 0/imm32
 5968         74/jump-if-= break/disp8
 5969         (lookup-or-create-constant %eax %ecx %esi)
 5970 #?         (lookup *esi *(esi+4))
 5971 #?         (write-buffered Stderr "creating new output var ")
 5972 #?         (print-int32-buffered Stderr %eax)
 5973 #?         (write-buffered Stderr " for field called ")
 5974 #?         (write-slice-buffered Stderr %ecx)
 5975 #?         (write-buffered Stderr "; var name ")
 5976 #?         (lookup *eax *(eax+4))  # Var-name
 5977 #?         (write-buffered Stderr %eax)
 5978 #?         (write-buffered Stderr Newline)
 5979 #?         (flush Stderr)
 5980         e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32
 5981       }
 5982       # is-deref? = false
 5983       ba/copy-to-edx 0/imm32/false
 5984       # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 5985       8b/-> *ecx 0/r32/eax  # Slice-start
 5986       8a/copy-byte *eax 0/r32/AL
 5987       81 4/subop/and %eax 0xff/imm32
 5988       3d/compare-eax-and 0x2a/imm32/asterisk
 5989       {
 5990         75/jump-if-!= break/disp8
 5991 $add-operation-and-inputs-to-stmt:inout-is-deref:
 5992         ff 0/subop/increment *ecx
 5993         ba/copy-to-edx 1/imm32/true
 5994       }
 5995       (lookup-var-or-literal %ecx *(ebp+0x10) %esi)
 5996 $add-operation-and-inputs-to-stmt:save-var:
 5997       8d/copy-address *(edi+0xc) 0/r32/eax
 5998       (append-stmt-var Heap  *esi *(esi+4)  *(edi+0xc) *(edi+0x10)  %edx  %eax)  # Stmt1-inouts or Regvardef-inouts
 5999       #
 6000       e9/jump loop/disp32
 6001     }
 6002 $add-operation-and-inputs-to-stmt:end:
 6003     # . reclaim locals
 6004     81 0/subop/add %esp 0x10/imm32
 6005     # . restore registers
 6006     5f/pop-to-edi
 6007     5e/pop-to-esi
 6008     5b/pop-to-ebx
 6009     5a/pop-to-edx
 6010     59/pop-to-ecx
 6011     58/pop-to-eax
 6012     # . epilogue
 6013     89/<- %esp 5/r32/ebp
 6014     5d/pop-to-ebp
 6015     c3/return
 6016 
 6017 $add-operation-and-inputs-to-stmt:abort:
 6018     # error("invalid statement '" line "'\n")
 6019     (rewind-stream *(ebp+8))
 6020     (write-buffered Stderr "invalid identifier '")
 6021     (flush Stderr)
 6022     (write-stream 2 *(ebp+8))
 6023     (write-buffered Stderr "'\n")
 6024     (flush Stderr)
 6025     # . syscall(exit, 1)
 6026     bb/copy-to-ebx  1/imm32
 6027     b8/copy-to-eax  1/imm32/exit
 6028     cd/syscall  0x80/imm8
 6029     # never gets here
 6030 
 6031 stmt-has-outputs?:  # line: (addr stream byte) -> result/eax: boolean
 6032     # . prologue
 6033     55/push-ebp
 6034     89/<- %ebp 4/r32/esp
 6035     # . save registers
 6036     51/push-ecx
 6037     # var word-slice/ecx: slice
 6038     68/push 0/imm32/end
 6039     68/push 0/imm32/start
 6040     89/<- %ecx 4/r32/esp
 6041     # result = false
 6042     b8/copy-to-eax 0/imm32/false
 6043     (rewind-stream *(ebp+8))
 6044     {
 6045       (next-mu-token *(ebp+8) %ecx)
 6046       # if slice-empty?(word-slice) break
 6047       (slice-empty? %ecx)
 6048       3d/compare-eax-and 0/imm32/false
 6049       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 6050       0f 85/jump-if-!= break/disp32
 6051       # if slice-starts-with?(word-slice, '#') break
 6052       # . eax = *word-slice->start
 6053       8b/-> *ecx 0/r32/eax
 6054       8a/copy-byte *eax 0/r32/AL
 6055       81 4/subop/and %eax 0xff/imm32
 6056       # . if (eax == '#') break
 6057       3d/compare-eax-and 0x23/imm32/hash
 6058       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 6059       0f 84/jump-if-= break/disp32
 6060       # if slice-equal?(word-slice, '<-') return true
 6061       (slice-equal? %ecx "<-")
 6062       3d/compare-eax-and 0/imm32/false
 6063       74/jump-if-= loop/disp8
 6064       b8/copy-to-eax 1/imm32/true
 6065     }
 6066 $stmt-has-outputs:end:
 6067     (rewind-stream *(ebp+8))
 6068     # . reclaim locals
 6069     81 0/subop/add %esp 8/imm32
 6070     # . restore registers
 6071     59/pop-to-ecx
 6072     # . epilogue
 6073     89/<- %esp 5/r32/ebp
 6074     5d/pop-to-ebp
 6075     c3/return
 6076 
 6077 # if 'name' starts with a digit, create a new literal var for it
 6078 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found
 6079 lookup-var-or-literal:  # name: (addr slice), vars: (addr stack (handle var)), out: (addr handle var)
 6080     # . prologue
 6081     55/push-ebp
 6082     89/<- %ebp 4/r32/esp
 6083     # . save registers
 6084     50/push-eax
 6085     51/push-ecx
 6086     56/push-esi
 6087     # esi = name
 6088     8b/-> *(ebp+8) 6/r32/esi
 6089     # if slice-empty?(name) abort
 6090     (slice-empty? %esi)  # => eax
 6091     3d/compare-eax-and 0/imm32/false
 6092     0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32
 6093     # var c/ecx: byte = *name->start
 6094     8b/-> *esi 1/r32/ecx
 6095     8a/copy-byte *ecx 1/r32/CL
 6096     81 4/subop/and %ecx 0xff/imm32
 6097     # if is-decimal-digit?(c) return new var(name)
 6098     {
 6099       (is-decimal-digit? %ecx)  # => eax
 6100       3d/compare-eax-and 0/imm32/false
 6101       74/jump-if-= break/disp8
 6102       (new-literal-integer Heap %esi *(ebp+0x10))
 6103       eb/jump $lookup-var-or-literal:end/disp8
 6104     }
 6105     # else if (c == '"') return new var(name)
 6106     {
 6107       81 7/subop/compare %ecx 0x22/imm32/dquote
 6108       75/jump-if-!= break/disp8
 6109       (new-literal Heap %esi *(ebp+0x10))
 6110       eb/jump $lookup-var-or-literal:end/disp8
 6111     }
 6112     # otherwise return lookup-var(name, vars)
 6113     {
 6114       (lookup-var %esi *(ebp+0xc))  # => eax
 6115     }
 6116 $lookup-var-or-literal:end:
 6117     # . restore registers
 6118     5e/pop-to-esi
 6119     59/pop-to-ecx
 6120     58/pop-to-eax
 6121     # . epilogue
 6122     89/<- %esp 5/r32/ebp
 6123     5d/pop-to-ebp
 6124     c3/return
 6125 
 6126 $lookup-var-or-literal:abort:
 6127     (write-buffered Stderr "empty variable!")
 6128     (flush Stderr)
 6129     # . syscall(exit, 1)
 6130     bb/copy-to-ebx  1/imm32
 6131     b8/copy-to-eax  1/imm32/exit
 6132     cd/syscall  0x80/imm8
 6133     # never gets here
 6134 
 6135 # return first 'name' from the top (back) of 'vars' and abort if not found
 6136 lookup-var:  # name: (addr slice), vars: (addr stack (handle var)), out: (addr handle var)
 6137     # . prologue
 6138     55/push-ebp
 6139     89/<- %ebp 4/r32/esp
 6140     # . save registers
 6141     50/push-eax
 6142     #
 6143     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x10))
 6144     # if (*out == 0) abort
 6145     8b/-> *(ebp+0x10) 0/r32/eax
 6146     81 7/subop/compare *eax 0/imm32
 6147     74/jump-if-= $lookup-var:abort/disp8
 6148 $lookup-var:end:
 6149     # . restore registers
 6150     58/pop-to-eax
 6151     # . epilogue
 6152     89/<- %esp 5/r32/ebp
 6153     5d/pop-to-ebp
 6154     c3/return
 6155 
 6156 $lookup-var:abort:
 6157     (write-buffered Stderr "unknown variable '")
 6158     (write-slice-buffered Stderr *(ebp+8))
 6159     (write-buffered Stderr "'\n")
 6160     (flush Stderr)
 6161     # . syscall(exit, 1)
 6162     bb/copy-to-ebx  1/imm32
 6163     b8/copy-to-eax  1/imm32/exit
 6164     cd/syscall  0x80/imm8
 6165     # never gets here
 6166 
 6167 # return first 'name' from the top (back) of 'vars', and 0/null if not found
 6168 lookup-var-helper:  # name: (addr slice), vars: (addr stack (handle var)), out: (addr handle var)
 6169     # pseudocode:
 6170     #   var curr: (addr handle var) = &vars->data[vars->top - 8]
 6171     #   var min = vars->data
 6172     #   while curr >= min
 6173     #     var v: (handle var) = *curr
 6174     #     if v->name == name
 6175     #       return
 6176     #     curr -= 8
 6177     #
 6178     # . prologue
 6179     55/push-ebp
 6180     89/<- %ebp 4/r32/esp
 6181     # . save registers
 6182     50/push-eax
 6183     51/push-ecx
 6184     52/push-edx
 6185     53/push-ebx
 6186     56/push-esi
 6187     # clear out
 6188     (zero-out *(ebp+0x10) *Handle-size)
 6189     # esi = vars
 6190     8b/-> *(ebp+0xc) 6/r32/esi
 6191     # ebx = vars->top
 6192     8b/-> *esi 3/r32/ebx
 6193     # if (vars->top > vars->size) abort
 6194     3b/compare<- *(esi+4) 0/r32/eax
 6195     0f 8f/jump-if-> $lookup-var-helper:error1/disp32
 6196     # var min/edx: (addr handle var) = vars->data
 6197     8d/copy-address *(esi+8) 2/r32/edx
 6198     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 8]
 6199     8d/copy-address *(esi+ebx) 3/r32/ebx
 6200     {
 6201       # if (curr < min) return
 6202       39/compare %ebx 2/r32/edx
 6203       0f 82/jump-if-addr< break/disp32
 6204       # var v/ecx: (addr var) = lookup(*curr)
 6205       (lookup *ebx *(ebx+4))  # => eax
 6206       89/<- %ecx 0/r32/eax
 6207       # var vn/eax: (addr array byte) = lookup(v->name)
 6208       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 6209       # if (vn == name) return curr
 6210       (slice-equal? *(ebp+8) %eax)  # => eax
 6211       3d/compare-eax-and 0/imm32/false
 6212       {
 6213         74/jump-if-= break/disp8
 6214         # esi = out
 6215         8b/-> *(ebp+0x10) 6/r32/esi
 6216         # *out = *curr
 6217         8b/-> *ebx 0/r32/eax
 6218         89/<- *esi 0/r32/eax
 6219         8b/-> *(ebx+4) 0/r32/eax
 6220         89/<- *(esi+4) 0/r32/eax
 6221         # return
 6222         eb/jump $lookup-var-helper:end/disp8
 6223       }
 6224       # curr -= 8
 6225       81 5/subop/subtract %ebx 8/imm32
 6226       e9/jump loop/disp32
 6227     }
 6228 $lookup-var-helper:end:
 6229     # . restore registers
 6230     5e/pop-to-esi
 6231     5b/pop-to-ebx
 6232     5a/pop-to-edx
 6233     59/pop-to-ecx
 6234     58/pop-to-eax
 6235     # . epilogue
 6236     89/<- %esp 5/r32/ebp
 6237     5d/pop-to-ebp
 6238     c3/return
 6239 
 6240 $lookup-var-helper:error1:
 6241     (write-buffered Stderr "malformed stack when looking up '")
 6242     (write-slice-buffered Stderr *(ebp+8))
 6243     (write-buffered Stderr "'\n")
 6244     (flush Stderr)
 6245     # . syscall(exit, 1)
 6246     bb/copy-to-ebx  1/imm32
 6247     b8/copy-to-eax  1/imm32/exit
 6248     cd/syscall  0x80/imm8
 6249     # never gets here
 6250 
 6251 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found
 6252 lookup-or-define-var:  # name: (addr slice), vars: (addr stack (handle var)), fn: (addr function), out: (addr handle var)
 6253     # . prologue
 6254     55/push-ebp
 6255     89/<- %ebp 4/r32/esp
 6256     # . save registers
 6257     50/push-eax
 6258     #
 6259     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x14))
 6260     {
 6261       # if (out != 0) return
 6262       8b/-> *(ebp+0x14) 0/r32/eax
 6263       81 7/subop/compare *eax 0/imm32
 6264       75/jump-if-!= break/disp8
 6265       # if name is one of fn's outputs, return it
 6266       {
 6267         (find-in-function-outputs *(ebp+0x10) *(ebp+8) *(ebp+0x14))
 6268         8b/-> *(ebp+0x14) 0/r32/eax
 6269         81 7/subop/compare *eax 0/imm32
 6270         # otherwise abort
 6271         0f 84/jump-if-= $lookup-var:abort/disp32
 6272       }
 6273     }
 6274 $lookup-or-define-var:end:
 6275     # . restore registers
 6276     58/pop-to-eax
 6277     # . epilogue
 6278     89/<- %esp 5/r32/ebp
 6279     5d/pop-to-ebp
 6280     c3/return
 6281 
 6282 find-in-function-outputs:  # fn: (addr function), name: (addr slice), out: (addr handle var)
 6283     # . prologue
 6284     55/push-ebp
 6285     89/<- %ebp 4/r32/esp
 6286     # . save registers
 6287     50/push-eax
 6288     51/push-ecx
 6289     # var curr/ecx: (addr list var) = lookup(fn->outputs)
 6290     8b/-> *(ebp+8) 1/r32/ecx
 6291     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 6292     89/<- %ecx 0/r32/eax
 6293     # while curr != null
 6294     {
 6295       81 7/subop/compare %ecx 0/imm32
 6296       74/jump-if-= break/disp8
 6297       # var v/eax: (addr var) = lookup(curr->value)
 6298       (lookup *ecx *(ecx+4))  # List-value List-value => eax
 6299       # var s/eax: (addr array byte) = lookup(v->name)
 6300       (lookup *eax *(eax+4))  # Var-name Var-name => eax
 6301       # if (s == name) return curr->value
 6302       (slice-equal? *(ebp+0xc) %eax)  # => eax
 6303       3d/compare-eax-and 0/imm32/false
 6304       {
 6305         74/jump-if-= break/disp8
 6306         # var edi = out
 6307         57/push-edi
 6308         8b/-> *(ebp+0x10) 7/r32/edi
 6309         # *out = curr->value
 6310         8b/-> *ecx 0/r32/eax
 6311         89/<- *edi 0/r32/eax
 6312         8b/-> *(ecx+4) 0/r32/eax
 6313         89/<- *(edi+4) 0/r32/eax
 6314         #
 6315         5f/pop-to-edi
 6316         eb/jump $find-in-function-outputs:end/disp8
 6317       }
 6318       # curr = curr->next
 6319       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
 6320       89/<- %ecx 0/r32/eax
 6321       #
 6322       eb/jump loop/disp8
 6323     }
 6324     b8/copy-to-eax 0/imm32
 6325 $find-in-function-outputs:end:
 6326     # . restore registers
 6327     59/pop-to-ecx
 6328     58/pop-to-eax
 6329     # . epilogue
 6330     89/<- %esp 5/r32/ebp
 6331     5d/pop-to-ebp
 6332     c3/return
 6333 
 6334 test-parse-mu-stmt:
 6335     # . prologue
 6336     55/push-ebp
 6337     89/<- %ebp 4/r32/esp
 6338     # setup
 6339     (clear-stream _test-input-stream)
 6340     (write _test-input-stream "increment n\n")
 6341     # var vars/ecx: (stack (addr var) 16)
 6342     81 5/subop/subtract %esp 0x80/imm32
 6343     68/push 0x80/imm32/size
 6344     68/push 0/imm32/top
 6345     89/<- %ecx 4/r32/esp
 6346     (clear-stack %ecx)
 6347     # var v/edx: (handle var)
 6348     68/push 0/imm32
 6349     68/push 0/imm32
 6350     89/<- %edx 4/r32/esp
 6351     # var s/eax: (handle array byte)
 6352     68/push 0/imm32
 6353     68/push 0/imm32
 6354     89/<- %eax 4/r32/esp
 6355     # v = new var("n")
 6356     (copy-array Heap "n" %eax)
 6357     (new-var Heap *eax *(eax+4) %edx)
 6358     #
 6359     (push %ecx *edx)
 6360     (push %ecx *(edx+4))
 6361     # var out/eax: (handle stmt)
 6362     68/push 0/imm32
 6363     68/push 0/imm32
 6364     89/<- %eax 4/r32/esp
 6365     # convert
 6366     (parse-mu-stmt _test-input-stream %ecx 0 %eax)
 6367     # var out-addr/edx: (addr stmt) = lookup(*out)
 6368     (lookup *eax *(eax+4))  # => eax
 6369     89/<- %edx 0/r32/eax
 6370     # out->tag
 6371     (check-ints-equal *edx 1 "F - test-parse-mu-stmt/tag")  # Stmt-tag is Stmt1
 6372     # out->operation
 6373     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
 6374     (check-strings-equal %eax "increment" "F - test-parse-mu-stmt/name")  # Stmt1-operation
 6375     # out->inouts->value->name
 6376     # . eax = out->inouts
 6377     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 6378     # . eax = out->inouts->value
 6379     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 6380     # . eax = out->inouts->value->name
 6381     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 6382     # .
 6383     (check-strings-equal %eax "n" "F - test-parse-mu-stmt/inout:0")
 6384     # . epilogue
 6385     89/<- %esp 5/r32/ebp
 6386     5d/pop-to-ebp
 6387     c3/return
 6388 
 6389 test-parse-mu-stmt-with-comma:
 6390     # . prologue
 6391     55/push-ebp
 6392     89/<- %ebp 4/r32/esp
 6393     # setup
 6394     (clear-stream _test-input-stream)
 6395     (write _test-input-stream "copy-to n, 3\n")
 6396     # var vars/ecx: (stack (addr var) 16)
 6397     81 5/subop/subtract %esp 0x80/imm32
 6398     68/push 0x80/imm32/size
 6399     68/push 0/imm32/top
 6400     89/<- %ecx 4/r32/esp
 6401     (clear-stack %ecx)
 6402     # var v/edx: (handle var)
 6403     68/push 0/imm32
 6404     68/push 0/imm32
 6405     89/<- %edx 4/r32/esp
 6406     # var s/eax: (handle array byte)
 6407     68/push 0/imm32
 6408     68/push 0/imm32
 6409     89/<- %eax 4/r32/esp
 6410     # v = new var("n")
 6411     (copy-array Heap "n" %eax)
 6412     (new-var Heap *eax *(eax+4) %edx)
 6413     #
 6414     (push %ecx *edx)
 6415     (push %ecx *(edx+4))
 6416     # var out/eax: (handle stmt)
 6417     68/push 0/imm32
 6418     68/push 0/imm32
 6419     89/<- %eax 4/r32/esp
 6420     # convert
 6421     (parse-mu-stmt _test-input-stream %ecx 0 %eax)
 6422     # var out-addr/edx: (addr stmt) = lookup(*out)
 6423     (lookup *eax *(eax+4))  # => eax
 6424     89/<- %edx 0/r32/eax
 6425     # out->tag
 6426     (check-ints-equal *edx 1 "F - test-parse-mu-stmt-with-comma/tag")  # Stmt-tag is Stmt1
 6427     # out->operation
 6428     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
 6429     (check-strings-equal %eax "copy-to" "F - test-parse-mu-stmt-with-comma/name")  # Stmt1-operation
 6430     # out->inouts->value->name
 6431     # . eax = out->inouts
 6432     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 6433     # . eax = out->inouts->value
 6434     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 6435     # . eax = out->inouts->value->name
 6436     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 6437     # .
 6438     (check-strings-equal %eax "n" "F - test-parse-mu-stmt-with-comma/inout:0")
 6439     # . epilogue
 6440     89/<- %esp 5/r32/ebp
 6441     5d/pop-to-ebp
 6442     c3/return
 6443 
 6444 new-var:  # ad: (addr allocation-descriptor), name: (handle array byte), out: (addr handle var)
 6445     # . prologue
 6446     55/push-ebp
 6447     89/<- %ebp 4/r32/esp
 6448     # . save registers
 6449     50/push-eax
 6450     51/push-ecx
 6451     # ecx = out
 6452     8b/-> *(ebp+0x14) 1/r32/ecx
 6453     #
 6454     (allocate *(ebp+8) *Var-size %ecx)
 6455     # var out-addr/eax: (addr var)
 6456     (lookup *ecx *(ecx+4))  # => eax
 6457     # out-addr->name = name
 6458     8b/-> *(ebp+0xc) 1/r32/ecx
 6459     89/<- *eax 1/r32/ecx  # Var-name
 6460     8b/-> *(ebp+0x10) 1/r32/ecx
 6461     89/<- *(eax+4) 1/r32/ecx  # Var-name
 6462 #?     (write-buffered Stderr "var ")
 6463 #?     (lookup *(ebp+0xc) *(ebp+0x10))
 6464 #?     (write-buffered Stderr %eax)
 6465 #?     (write-buffered Stderr " at ")
 6466 #?     8b/-> *(ebp+0x14) 1/r32/ecx
 6467 #?     (lookup *ecx *(ecx+4))  # => eax
 6468 #?     (print-int32-buffered Stderr %eax)
 6469 #?     (write-buffered Stderr Newline)
 6470 #?     (flush Stderr)
 6471 $new-var:end:
 6472     # . restore registers
 6473     59/pop-to-ecx
 6474     58/pop-to-eax
 6475     # . epilogue
 6476     89/<- %esp 5/r32/ebp
 6477     5d/pop-to-ebp
 6478     c3/return
 6479 
 6480 new-literal-integer:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
 6481     # . prologue
 6482     55/push-ebp
 6483     89/<- %ebp 4/r32/esp
 6484     # . save registers
 6485     50/push-eax
 6486     51/push-ecx
 6487     # if (!is-hex-int?(name)) abort
 6488     (is-hex-int? *(ebp+0xc))  # => eax
 6489     3d/compare-eax-and 0/imm32/false
 6490     0f 84/jump-if-= $new-literal-integer:abort/disp32
 6491     # out = new var(s)
 6492     (new-var-from-slice *(ebp+8) *(ebp+0xc) *(ebp+0x10))
 6493     # var out-addr/ecx: (addr var) = lookup(*out)
 6494     8b/-> *(ebp+0x10) 0/r32/eax
 6495     (lookup *eax *(eax+4))  # => eax
 6496     89/<- %ecx 0/r32/eax
 6497     # out-addr->type = new tree()
 6498     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
 6499     (allocate *(ebp+8) *Tree-size %eax)
 6500     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 6501     c7 0/subop/copy *eax 1/imm32/true  # Tree-is-atom
 6502     # nothing else to do; default type is 'literal'
 6503 $new-literal-integer:end:
 6504     # . reclaim locals
 6505     81 0/subop/add %esp 8/imm32
 6506     # . restore registers
 6507     59/pop-to-ecx
 6508     58/pop-to-eax
 6509     # . epilogue
 6510     89/<- %esp 5/r32/ebp
 6511     5d/pop-to-ebp
 6512     c3/return
 6513 
 6514 $new-literal-integer:abort:
 6515     (write-buffered Stderr "variable cannot begin with a digit '")
 6516     (write-slice-buffered Stderr *(ebp+0xc))
 6517     (write-buffered Stderr "'\n")
 6518     (flush Stderr)
 6519     # . syscall(exit, 1)
 6520     bb/copy-to-ebx  1/imm32
 6521     b8/copy-to-eax  1/imm32/exit
 6522     cd/syscall  0x80/imm8
 6523     # never gets here
 6524 
 6525 new-literal:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
 6526     # . prologue
 6527     55/push-ebp
 6528     89/<- %ebp 4/r32/esp
 6529     # . save registers
 6530     50/push-eax
 6531     51/push-ecx
 6532     # var s/ecx: (handle array byte)
 6533     68/push 0/imm32
 6534     68/push 0/imm32
 6535     89/<- %ecx 4/r32/esp
 6536     # s = slice-to-string(name)
 6537     (slice-to-string Heap *(ebp+0xc) %ecx)
 6538     # allocate to out
 6539     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
 6540     # var out-addr/ecx: (addr var) = lookup(*out)
 6541     8b/-> *(ebp+0x10) 1/r32/ecx
 6542     (lookup *ecx *(ecx+4))  # => eax
 6543     89/<- %ecx 0/r32/eax
 6544     # out-addr->type/eax = new type
 6545     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
 6546     (allocate *(ebp+8) *Tree-size %eax)
 6547     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 6548     # nothing else to do; default type is 'literal'
 6549     c7 0/subop/copy *eax 1/imm32/true  # Tree-is-atom
 6550 $new-literal:end:
 6551     # . reclaim locals
 6552     81 0/subop/add %esp 8/imm32
 6553     # . restore registers
 6554     59/pop-to-ecx
 6555     58/pop-to-eax
 6556     # . epilogue
 6557     89/<- %esp 5/r32/ebp
 6558     5d/pop-to-ebp
 6559     c3/return
 6560 
 6561 new-var-from-slice:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
 6562     # . prologue
 6563     55/push-ebp
 6564     89/<- %ebp 4/r32/esp
 6565     # . save registers
 6566     51/push-ecx
 6567     # var tmp/ecx: (handle array byte)
 6568     68/push 0/imm32
 6569     68/push 0/imm32
 6570     89/<- %ecx 4/r32/esp
 6571     # tmp = slice-to-string(name)
 6572     (slice-to-string Heap *(ebp+0xc) %ecx)
 6573     # out = new-var(tmp)
 6574     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
 6575 $new-var-from-slice:end:
 6576     # . reclaim locals
 6577     81 0/subop/add %esp 8/imm32
 6578     # . restore registers
 6579     59/pop-to-ecx
 6580     # . epilogue
 6581     89/<- %esp 5/r32/ebp
 6582     5d/pop-to-ebp
 6583     c3/return
 6584 
 6585 new-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
 6586     # . prologue
 6587     55/push-ebp
 6588     89/<- %ebp 4/r32/esp
 6589     # . save registers
 6590     50/push-eax
 6591     51/push-ecx
 6592     #
 6593     (allocate *(ebp+8) *Stmt-size *(ebp+0x14))
 6594     # var out-addr/eax: (addr stmt) = lookup(*out)
 6595     8b/-> *(ebp+0x14) 0/r32/eax
 6596     (lookup *eax *(eax+4))  # => eax
 6597     # out-addr->tag = stmt
 6598     c7 0/subop/copy *eax 2/imm32/tag/var-on-stack  # Stmt-tag
 6599     # result->var = var
 6600     8b/-> *(ebp+0xc) 1/r32/ecx
 6601     89/<- *(eax+4) 1/r32/ecx  # Vardef-var
 6602     8b/-> *(ebp+0x10) 1/r32/ecx
 6603     89/<- *(eax+8) 1/r32/ecx  # Vardef-var
 6604 $new-var-def:end:
 6605     # . restore registers
 6606     59/pop-to-ecx
 6607     58/pop-to-eax
 6608     # . epilogue
 6609     89/<- %esp 5/r32/ebp
 6610     5d/pop-to-ebp
 6611     c3/return
 6612 
 6613 new-reg-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
 6614     # . prologue
 6615     55/push-ebp
 6616     89/<- %ebp 4/r32/esp
 6617     # . save registers
 6618     50/push-eax
 6619     # eax = out
 6620     8b/-> *(ebp+0x14) 0/r32/eax
 6621     #
 6622     (allocate *(ebp+8) *Stmt-size %eax)
 6623     # var out-addr/eax: (addr stmt) = lookup(*out)
 6624     (lookup *eax *(eax+4))  # => eax
 6625     # set tag
 6626     c7 0/subop/copy *eax 3/imm32/tag/var-in-register  # Stmt-tag
 6627     # set output
 6628     8d/copy-address *(eax+0x14) 0/r32/eax  # Regvardef-outputs
 6629     (append-stmt-var Heap  *(ebp+0xc) *(ebp+0x10)  0 0  0  %eax)
 6630 $new-reg-var-def:end:
 6631     # . restore registers
 6632     58/pop-to-eax
 6633     # . epilogue
 6634     89/<- %esp 5/r32/ebp
 6635     5d/pop-to-ebp
 6636     c3/return
 6637 
 6638 append-list:  # ad: (addr allocation-descriptor), value: (handle _type), list: (handle list _type), out: (addr handle list _type)
 6639     # . prologue
 6640     55/push-ebp
 6641     89/<- %ebp 4/r32/esp
 6642     # . save registers
 6643     50/push-eax
 6644     51/push-ecx
 6645     57/push-edi
 6646     # edi = out
 6647     8b/-> *(ebp+0x1c) 7/r32/edi
 6648     # *out = new list
 6649     (allocate *(ebp+8) *List-size %edi)
 6650     # var out-addr/edi: (addr list _type) = lookup(*out)
 6651     (lookup *edi *(edi+4))  # => eax
 6652     89/<- %edi 0/r32/eax
 6653     # out-addr->value = value
 6654     8b/-> *(ebp+0xc) 0/r32/eax
 6655     89/<- *edi 0/r32/eax  # List-value
 6656     8b/-> *(ebp+0x10) 0/r32/eax
 6657     89/<- *(edi+4) 0/r32/eax  # List-value
 6658     # if (list == null) return
 6659     81 7/subop/compare *(ebp+0x14) 0/imm32
 6660     74/jump-if-= $append-list:end/disp8
 6661     # otherwise append
 6662 $append-list:non-empty-list:
 6663     # var curr/eax: (addr list _type) = lookup(list)
 6664     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
 6665     # while (curr->next != null) curr = curr->next
 6666     {
 6667       81 7/subop/compare *(eax+8) 0/imm32  # List-next
 6668       74/jump-if-= break/disp8
 6669       # curr = lookup(curr->next)
 6670       (lookup *(eax+8) *(eax+0xc))  # List-next, List-next => eax
 6671       #
 6672       eb/jump loop/disp8
 6673     }
 6674     # edi = out
 6675     8b/-> *(ebp+0x1c) 7/r32/edi
 6676     # curr->next = out
 6677     8b/-> *edi 1/r32/ecx
 6678     89/<- *(eax+8) 1/r32/ecx  # List-next
 6679     8b/-> *(edi+4) 1/r32/ecx
 6680     89/<- *(eax+0xc) 1/r32/ecx  # List-next
 6681     # out = list
 6682     8b/-> *(ebp+0x14) 1/r32/ecx
 6683     89/<- *edi 1/r32/ecx
 6684     8b/-> *(ebp+0x18) 1/r32/ecx
 6685     89/<- *(edi+4) 1/r32/ecx
 6686 $append-list:end:
 6687     # . restore registers
 6688     5f/pop-to-edi
 6689     59/pop-to-ecx
 6690     58/pop-to-eax
 6691     # . epilogue
 6692     89/<- %esp 5/r32/ebp
 6693     5d/pop-to-ebp
 6694     c3/return
 6695 
 6696 append-stmt-var:  # ad: (addr allocation-descriptor), v: (handle var), vars: (handle stmt-var), is-deref?: boolean, out: (addr handle stmt-var)
 6697     # . prologue
 6698     55/push-ebp
 6699     89/<- %ebp 4/r32/esp
 6700     # . save registers
 6701     50/push-eax
 6702     51/push-ecx
 6703     57/push-edi
 6704     # edi = out
 6705     8b/-> *(ebp+0x20) 7/r32/edi
 6706     # out = new stmt-var
 6707     (allocate *(ebp+8) *Stmt-var-size %edi)
 6708     # var out-addr/ecx: (addr stmt-var) = lookup(*out)
 6709     (lookup *edi *(edi+4))  # => eax
 6710     89/<- %ecx 0/r32/eax
 6711     # out-addr->value = v
 6712     8b/-> *(ebp+0xc) 0/r32/eax
 6713     89/<- *ecx 0/r32/eax  # Stmt-var-value
 6714     8b/-> *(ebp+0x10) 0/r32/eax
 6715     89/<- *(ecx+4) 0/r32/eax  # Stmt-var-value
 6716     # out-addr->is-deref? = is-deref?
 6717     8b/-> *(ebp+0x1c) 0/r32/eax
 6718     89/<- *(ecx+0x10) 0/r32/eax  # Stmt-var-is-deref
 6719     # if (vars == null) return result
 6720     81 7/subop/compare *(ebp+0x14) 0/imm32/null
 6721     74/jump-if-= $append-stmt-var:end/disp8
 6722     # otherwise append
 6723     # var curr/eax: (addr stmt-var) = lookup(vars)
 6724     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
 6725     # while (curr->next != null) curr = curr->next
 6726     {
 6727       81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
 6728       74/jump-if-= break/disp8
 6729       # curr = lookup(curr->next)
 6730       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next, Stmt-var-next => eax
 6731       #
 6732       eb/jump loop/disp8
 6733     }
 6734     # curr->next = out
 6735     8b/-> *edi 1/r32/ecx
 6736     89/<- *(eax+8) 1/r32/ecx  # Stmt-var-next
 6737     8b/-> *(edi+4) 1/r32/ecx
 6738     89/<- *(eax+0xc) 1/r32/ecx  # Stmt-var-next
 6739     # out = vars
 6740     8b/-> *(ebp+0x14) 1/r32/ecx
 6741     89/<- *edi 1/r32/ecx
 6742     8b/-> *(ebp+0x18) 1/r32/ecx
 6743     89/<- *(edi+4) 1/r32/ecx
 6744 $append-stmt-var:end:
 6745     # . restore registers
 6746     5f/pop-to-edi
 6747     59/pop-to-ecx
 6748     58/pop-to-eax
 6749     # . epilogue
 6750     89/<- %esp 5/r32/ebp
 6751     5d/pop-to-ebp
 6752     c3/return
 6753 
 6754 append-to-block:  # ad: (addr allocation-descriptor), block: (addr block), x: (handle stmt)
 6755     # . prologue
 6756     55/push-ebp
 6757     89/<- %ebp 4/r32/esp
 6758     # . save registers
 6759     50/push-eax
 6760     56/push-esi
 6761     # esi = block
 6762     8b/-> *(ebp+0xc) 6/r32/esi
 6763     # block->stmts = append(x, block->stmts)
 6764     8d/copy-address *(esi+4) 0/r32/eax  # Block-stmts
 6765     (append-list *(ebp+8)  *(ebp+0x10) *(ebp+0x14)  *(esi+4) *(esi+8)  %eax)  # ad, x, x, Block-stmts, Block-stmts
 6766 $append-to-block:end:
 6767     # . restore registers
 6768     5e/pop-to-esi
 6769     58/pop-to-eax
 6770     # . epilogue
 6771     89/<- %esp 5/r32/ebp
 6772     5d/pop-to-ebp
 6773     c3/return
 6774 
 6775 ## Parsing types
 6776 # We need to create metadata on user-defined types, and we need to use this
 6777 # metadata as we parse instructions.
 6778 # However, we also want to allow types to be used before their definitions.
 6779 # This means we can't ever assume any type data structures exist.
 6780 
 6781 lookup-or-create-constant:  # container: (addr stmt-var), field-name: (addr slice), out: (addr handle var)
 6782     # . prologue
 6783     55/push-ebp
 6784     89/<- %ebp 4/r32/esp
 6785     # . save registers
 6786     50/push-eax
 6787     56/push-esi
 6788     # var container-type/esi: type-id
 6789     (container-type *(ebp+8))  # => eax
 6790     89/<- %esi 0/r32/eax
 6791     # var tmp/eax: (handle typeinfo) = find-or-create-typeinfo(container-type)
 6792     68/push 0/imm32
 6793     68/push 0/imm32
 6794     89/<- %eax 4/r32/esp
 6795     (find-or-create-typeinfo %esi %eax)
 6796     # var tmp-addr/eax: (addr typeinfo) = lookup(tmp)
 6797     (lookup *eax *(eax+4))  # => eax
 6798     # result = find-or-create-typeinfo-output-var(typeinfo, field-name)
 6799 #?     (write-buffered Stderr "constant: ")
 6800 #?     (write-slice-buffered Stderr *(ebp+0xc))
 6801 #?     (write-buffered Stderr Newline)
 6802 #?     (flush Stderr)
 6803     (find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10))
 6804 #?     8b/-> *(ebp+0x10) 0/r32/eax
 6805 #?     (write-buffered Stderr "@")
 6806 #?     (lookup *eax *(eax+4))
 6807 #?     (print-int32-buffered Stderr %eax)
 6808 #?     (lookup *eax *(eax+4))
 6809 #?     (write-buffered Stderr %eax)
 6810 #?     (write-buffered Stderr Newline)
 6811 #?     (flush Stderr)
 6812 #?     (write-buffered Stderr "offset: ")
 6813 #?     8b/-> *(eax+0x14) 0/r32/eax
 6814 #?     (print-int32-buffered Stderr %eax)
 6815 #?     (write-buffered Stderr Newline)
 6816 #?     (flush Stderr)
 6817 $lookup-or-create-constant:end:
 6818     # . reclaim locals
 6819     81 0/subop/add %esp 8/imm32
 6820     # . restore registers
 6821     5e/pop-to-esi
 6822     58/pop-to-eax
 6823     # . epilogue
 6824     89/<- %esp 5/r32/ebp
 6825     5d/pop-to-ebp
 6826     c3/return
 6827 
 6828 # if addr var:
 6829 #   container->var->type->right->left->value
 6830 # otherwise
 6831 #   container->var->type->value
 6832 container-type:  # container: (addr stmt-var) -> result/eax: type-id
 6833     # . prologue
 6834     55/push-ebp
 6835     89/<- %ebp 4/r32/esp
 6836     #
 6837     8b/-> *(ebp+8) 0/r32/eax
 6838     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 6839     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
 6840     {
 6841       81 7/subop/compare *(eax+8) 0/imm32  # Tree-right
 6842       74/jump-if-= break/disp8
 6843       (lookup *(eax+0xc) *(eax+0x10))  # Tree-right Tree-right => eax
 6844       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 6845     }
 6846     8b/-> *(eax+4) 0/r32/eax  # Tree-value
 6847 $container-type:end:
 6848     # . epilogue
 6849     89/<- %esp 5/r32/ebp
 6850     5d/pop-to-ebp
 6851     c3/return
 6852 
 6853 find-or-create-typeinfo:  # t: type-id, out: (addr handle typeinfo)
 6854     # . prologue
 6855     55/push-ebp
 6856     89/<- %ebp 4/r32/esp
 6857     # . save registers
 6858     50/push-eax
 6859     51/push-ecx
 6860     52/push-edx
 6861     57/push-edi
 6862     # edi = out
 6863     8b/-> *(ebp+0xc) 7/r32/edi
 6864     # var fields/ecx: (handle table (handle array byte) (handle typeinfo-entry))
 6865     68/push 0/imm32
 6866     68/push 0/imm32
 6867     89/<- %ecx 4/r32/esp
 6868     # find-typeinfo(t, out)
 6869     (find-typeinfo *(ebp+8) %edi)
 6870     {
 6871       # if (*out != 0) break
 6872       81 7/subop/compare *edi 0/imm32
 6873       0f 85/jump-if-!= break/disp32
 6874 $find-or-create-typeinfo:create:
 6875       # *out = allocate
 6876       (allocate Heap *Typeinfo-size %edi)
 6877       # var tmp/eax: (addr typeinfo) = lookup(*out)
 6878       (lookup *edi *(edi+4))  # => eax
 6879 #?     (write-buffered Stderr "created typeinfo at ")
 6880 #?     (print-int32-buffered Stderr %eax)
 6881 #?     (write-buffered Stderr " for type-id ")
 6882 #?     (print-int32-buffered Stderr *(ebp+8))
 6883 #?     (write-buffered Stderr Newline)
 6884 #?     (flush Stderr)
 6885       # tmp->id = t
 6886       8b/-> *(ebp+8) 2/r32/edx
 6887       89/<- *eax 2/r32/edx  # Typeinfo-id
 6888       # tmp->fields = new table
 6889       # . fields = new table
 6890       (new-stream Heap 0x40 *Typeinfo-fields-row-size %ecx)
 6891       # . tmp->fields = fields
 6892       8b/-> *ecx 2/r32/edx
 6893       89/<- *(eax+4) 2/r32/edx  # Typeinfo-fields
 6894       8b/-> *(ecx+4) 2/r32/edx
 6895       89/<- *(eax+8) 2/r32/edx  # Typeinfo-fields
 6896       # tmp->next = Program->types
 6897       8b/-> *_Program-types 1/r32/ecx
 6898       89/<- *(eax+0x10) 1/r32/ecx  # Typeinfo-next
 6899       8b/-> *_Program-types->payload 1/r32/ecx
 6900       89/<- *(eax+0x14) 1/r32/ecx  # Typeinfo-next
 6901       # Program->types = out
 6902       8b/-> *edi 1/r32/ecx
 6903       89/<- *_Program-types 1/r32/ecx
 6904       8b/-> *(edi+4) 1/r32/ecx
 6905       89/<- *_Program-types->payload 1/r32/ecx
 6906     }
 6907 $find-or-create-typeinfo:end:
 6908     # . reclaim locals
 6909     81 0/subop/add %esp 8/imm32
 6910     # . restore registers
 6911     5f/pop-to-edi
 6912     5a/pop-to-edx
 6913     59/pop-to-ecx
 6914     58/pop-to-eax
 6915     # . epilogue
 6916     89/<- %esp 5/r32/ebp
 6917     5d/pop-to-ebp
 6918     c3/return
 6919 
 6920 find-typeinfo:  # t: type-id, out: (addr handle typeinfo)
 6921     # . prologue
 6922     55/push-ebp
 6923     89/<- %ebp 4/r32/esp
 6924     # . save registers
 6925     50/push-eax
 6926     51/push-ecx
 6927     52/push-edx
 6928     57/push-edi
 6929     # ecx = t
 6930     8b/-> *(ebp+8) 1/r32/ecx
 6931     # edi = out
 6932     8b/-> *(ebp+0xc) 7/r32/edi
 6933     # *out = Program->types
 6934     8b/-> *_Program-types 0/r32/eax
 6935     89/<- *edi 0/r32/eax
 6936     8b/-> *_Program-types->payload 0/r32/eax
 6937     89/<- *(edi+4) 0/r32/eax
 6938     {
 6939       # if (*out == 0) break
 6940       81 7/subop/compare *edi 0/imm32
 6941       74/jump-if-= break/disp8
 6942       # var tmp/eax: (addr typeinfo) = lookup(*out)
 6943       (lookup *edi *(edi+4))  # => eax
 6944       # if (tmp->id == t) break
 6945       39/compare *eax 1/r32/ecx  # Typeinfo-id
 6946       74/jump-if-= break/disp8
 6947       # *out = tmp->next
 6948       8b/-> *(eax+0x10) 2/r32/edx  # Typeinfo-next
 6949       89/<- *edi 2/r32/edx
 6950       8b/-> *(eax+0x14) 2/r32/edx  # Typeinfo-next
 6951       89/<- *(edi+4) 2/r32/edx
 6952       #
 6953       eb/jump loop/disp8
 6954     }
 6955 $find-typeinfo:end:
 6956     # . restore registers
 6957     5f/pop-to-edi
 6958     5a/pop-to-edx
 6959     59/pop-to-ecx
 6960     58/pop-to-eax
 6961     # . epilogue
 6962     89/<- %esp 5/r32/ebp
 6963     5d/pop-to-ebp
 6964     c3/return
 6965 
 6966 find-or-create-typeinfo-output-var:  # T: (addr typeinfo), f: (addr slice), out: (addr handle var)
 6967     # . prologue
 6968     55/push-ebp
 6969     89/<- %ebp 4/r32/esp
 6970     # . save registers
 6971     50/push-eax
 6972     52/push-edx
 6973     57/push-edi
 6974     # var dest/edi: (handle typeinfo-entry)
 6975     68/push 0/imm32
 6976     68/push 0/imm32
 6977     89/<- %edi 4/r32/esp
 6978     # find-or-create-typeinfo-fields(T, f, dest)
 6979     (find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi)
 6980     # var dest-addr/edi: (addr typeinfo-entry) = lookup(dest)
 6981     (lookup *edi *(edi+4))  # => eax
 6982     89/<- %edi 0/r32/eax
 6983     # if dest-addr->output-var doesn't exist, create it
 6984     {
 6985       81 7/subop/compare *(edi+0xc) 0/imm32  # Typeinfo-entry-output-var
 6986       0f 85/jump-if-!= break/disp32
 6987       # dest-addr->output-var = new var(dummy name, type, -1 offset)
 6988       # . var name/eax: (handle array byte) = "field"
 6989       68/push 0/imm32
 6990       68/push 0/imm32
 6991       89/<- %eax 4/r32/esp
 6992       (copy-array Heap "field" %eax)
 6993       # . new var
 6994       8d/copy-address *(edi+0xc) 2/r32/edx
 6995       (new-var Heap  *eax *(eax+4)  %edx)
 6996       # . reclaim name
 6997       81 0/subop/add %esp 8/imm32
 6998       # var result/edx: (addr var) = lookup(dest-addr->output-var)
 6999       (lookup *(edi+0xc) *(edi+0x10))  # => eax
 7000       89/<- %edx 0/r32/eax
 7001       # result->type = new constant type
 7002       8d/copy-address *(edx+8) 0/r32/eax  # Var-type
 7003       (allocate Heap *Tree-size %eax)
 7004       (lookup *(edx+8) *(edx+0xc))  # => eax
 7005       c7 0/subop/copy *eax 1/imm32/true  # Tree-is-atom
 7006       c7 0/subop/copy *(eax+4) 6/imm32/constant  # Tree-value
 7007       c7 0/subop/copy *(eax+8) 0/imm32  # Tree-left
 7008       c7 0/subop/copy *(eax+0xc) 0/imm32  # Tree-right
 7009       c7 0/subop/copy *(eax+0x10) 0/imm32  # Tree-right
 7010       # result->offset isn't filled out yet
 7011       c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized  # Var-offset
 7012     }
 7013     # out = dest-addr->output-var
 7014     8b/-> *(ebp+0x10) 2/r32/edx
 7015     8b/-> *(edi+0xc) 0/r32/eax  # Typeinfo-entry-output-var
 7016     89/<- *edx 0/r32/eax
 7017     8b/-> *(edi+0x10) 0/r32/eax  # Typeinfo-entry-output-var
 7018     89/<- *(edx+4) 0/r32/eax
 7019 $find-or-create-typeinfo-output-var:end:
 7020     # . reclaim locals
 7021     81 0/subop/add %esp 8/imm32
 7022     # . restore registers
 7023     5f/pop-to-edi
 7024     5a/pop-to-edx
 7025     58/pop-to-eax
 7026     # . epilogue
 7027     89/<- %esp 5/r32/ebp
 7028     5d/pop-to-ebp
 7029     c3/return
 7030 
 7031 find-or-create-typeinfo-fields:  # T: (addr typeinfo), f: (addr slice), out: (addr handle typeinfo-entry)
 7032     # . prologue
 7033     55/push-ebp
 7034     89/<- %ebp 4/r32/esp
 7035     # . save registers
 7036     50/push-eax
 7037     56/push-esi
 7038     57/push-edi
 7039     # eax = lookup(T->fields)
 7040     8b/-> *(ebp+8) 0/r32/eax
 7041     (lookup *(eax+4) *(eax+8))  # Typeinfo-fields Typeinfo-fields => eax
 7042     # edi = out
 7043     8b/-> *(ebp+0x10) 7/r32/edi
 7044     # var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f)
 7045     (get-or-insert-slice %eax *(ebp+0xc) *Typeinfo-fields-row-size Heap)  # => eax
 7046     89/<- %esi 0/r32/eax
 7047     # if src doesn't exist, allocate it
 7048     {
 7049       81 7/subop/compare *esi 0/imm32
 7050       75/jump-if-!= break/disp8
 7051       (allocate Heap *Typeinfo-entry-size %esi)
 7052 #?       (write-buffered Stderr "handle at ")
 7053 #?       (print-int32-buffered Stderr %esi)
 7054 #?       (write-buffered Stderr ": ")
 7055 #?       (print-int32-buffered Stderr *esi)
 7056 #?       (write-buffered Stderr " ")
 7057 #?       (print-int32-buffered Stderr *(esi+4))
 7058 #?       (write-buffered Stderr Newline)
 7059 #?       (flush Stderr)
 7060 #?       (lookup *esi *(esi+4))
 7061 #?       (write-buffered Stderr "created typeinfo fields at ")
 7062 #?       (print-int32-buffered Stderr %esi)
 7063 #?       (write-buffered Stderr " for ")
 7064 #?       (print-int32-buffered Stderr *(ebp+8))
 7065 #?       (write-buffered Stderr Newline)
 7066 #?       (flush Stderr)
 7067     }
 7068     # *out = src
 7069     # . *edi = *src
 7070     8b/-> *esi 0/r32/eax
 7071     89/<- *edi 0/r32/eax
 7072     8b/-> *(esi+4) 0/r32/eax
 7073     89/<- *(edi+4) 0/r32/eax
 7074 $find-or-create-typeinfo-fields:end:
 7075     # . restore registers
 7076     5f/pop-to-edi
 7077     5e/pop-to-esi
 7078     58/pop-to-eax
 7079     # . epilogue
 7080     89/<- %esp 5/r32/ebp
 7081     5d/pop-to-ebp
 7082     c3/return
 7083 
 7084 populate-mu-type:  # in: (addr stream byte), t: (addr typeinfo)
 7085     # pseudocode:
 7086     #   var line: (stream byte 512)
 7087     #   curr-index = 0
 7088     #   while true
 7089     #     clear-stream(line)
 7090     #     read-line-buffered(in, line)
 7091     #     if line->write == 0
 7092     #       abort
 7093     #     word-slice = next-mu-token(line)
 7094     #     if slice-empty?(word-slice)               # end of line
 7095     #       continue
 7096     #     if slice-equal?(word-slice, "}")
 7097     #       break
 7098     #     var v: (handle var) = parse-var-with-type(word-slice, line)
 7099     #     var r: (handle typeinfo-fields) = find-or-create-typeinfo-fields(t, word-slice/v->name)
 7100     #     TODO: ensure that r->first is null
 7101     #     r->index = curr-index
 7102     #     curr-index++
 7103     #     r->input-var = v
 7104     #     if r->output-var == 0
 7105     #       r->output-var = new literal
 7106     #     TODO: ensure nothing else in line
 7107     # t->total-size-in-bytes = -2 (not yet initialized)
 7108     #
 7109     # . prologue
 7110     55/push-ebp
 7111     89/<- %ebp 4/r32/esp
 7112     # var curr-index: int at *(ebp-4)
 7113     68/push 0/imm32
 7114     # . save registers
 7115     50/push-eax
 7116     51/push-ecx
 7117     52/push-edx
 7118     53/push-ebx
 7119     56/push-esi
 7120     57/push-edi
 7121     # edi = t
 7122     8b/-> *(ebp+0xc) 7/r32/edi
 7123     # var line/ecx: (stream byte 512)
 7124     81 5/subop/subtract %esp 0x200/imm32
 7125     68/push 0x200/imm32/size
 7126     68/push 0/imm32/read
 7127     68/push 0/imm32/write
 7128     89/<- %ecx 4/r32/esp
 7129     # var word-slice/edx: slice
 7130     68/push 0/imm32/end
 7131     68/push 0/imm32/start
 7132     89/<- %edx 4/r32/esp
 7133     # var v/esi: (handle var)
 7134     68/push 0/imm32
 7135     68/push 0/imm32
 7136     89/<- %esi 4/r32/esp
 7137     # var r/ebx: (handle typeinfo-entry)
 7138     68/push 0/imm32
 7139     68/push 0/imm32
 7140     89/<- %ebx 4/r32/esp
 7141     {
 7142 $populate-mu-type:line-loop:
 7143       (clear-stream %ecx)
 7144       (read-line-buffered *(ebp+8) %ecx)
 7145       # if (line->write == 0) abort
 7146       81 7/subop/compare *ecx 0/imm32
 7147       0f 84/jump-if-= $populate-mu-type:abort/disp32
 7148 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
 7154       (next-mu-token %ecx %edx)
 7155       # if slice-empty?(word-slice) continue
 7156       (slice-empty? %edx)  # => eax
 7157       3d/compare-eax-and 0/imm32
 7158       0f 85/jump-if-!= loop/disp32
 7159       # if slice-equal?(word-slice, "}") break
 7160       (slice-equal? %edx "}")
 7161       3d/compare-eax-and 0/imm32
 7162       0f 85/jump-if-!= break/disp32
 7163 $populate-mu-type:parse-element:
 7164       # v = parse-var-with-type(word-slice, first-line)
 7165       # must do this first to strip the trailing ':' from word-slice before
 7166       # using it in find-or-create-typeinfo-fields below
 7167       # TODO: clean up that mutation in parse-var-with-type
 7168       (parse-var-with-type %edx %ecx %esi)  # => eax
 7169       # var tmp/ecx
 7170       51/push-ecx
 7171 $populate-mu-type:create-typeinfo-fields:
 7172       # var r/ebx: (handle typeinfo-entry)
 7173       (find-or-create-typeinfo-fields %edi %edx %ebx)
 7174       # r->index = curr-index
 7175       (lookup *ebx *(ebx+4))  # => eax
 7176       8b/-> *(ebp-4) 1/r32/ecx
 7177 #?       (write-buffered Stderr "saving index ")
 7178 #?       (print-int32-buffered Stderr %ecx)
 7179 #?       (write-buffered Stderr " at ")
 7180 #?       (print-int32-buffered Stderr %edi)
 7181 #?       (write-buffered Stderr Newline)
 7182 #?       (flush Stderr)
 7183       89/<- *(eax+8) 1/r32/ecx  # Typeinfo-entry-index
 7184       # ++curr-index
 7185       ff 0/subop/increment *(ebp-4)
 7186 $populate-mu-type:set-input-type:
 7187       # r->input-var = v
 7188       8b/-> *esi 1/r32/ecx
 7189       89/<- *eax 1/r32/ecx  # Typeinfo-entry-input-var
 7190       8b/-> *(esi+4) 1/r32/ecx
 7191       89/<- *(eax+4) 1/r32/ecx  # Typeinfo-entry-input-var
 7192       59/pop-to-ecx
 7193       {
 7194 $populate-mu-type:create-output-type:
 7195         # if (r->output-var == 0) create a new var with some placeholder data
 7196         81 7/subop/compare *(eax+0xc) 0/imm32  # Typeinfo-entry-output-var
 7197         75/jump-if-!= break/disp8
 7198         8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
 7199         (new-literal Heap %edx %eax)
 7200       }
 7201       e9/jump loop/disp32
 7202     }
 7203 $populate-mu-type:invalidate-total-size-in-bytes:
 7204     # Offsets and total size may not be accurate here since we may not yet
 7205     # have encountered the element types.
 7206     # We'll recompute them separately after parsing the entire program.
 7207     c7 0/subop/copy *(edi+0xc) -2/imm32/uninitialized  # Typeinfo-total-size-in-bytes
 7208 $populate-mu-type:end:
 7209     # . reclaim locals
 7210     81 0/subop/add %esp 0x224/imm32
 7211     # . restore registers
 7212     5f/pop-to-edi
 7213     5e/pop-to-esi
 7214     5b/pop-to-ebx
 7215     5a/pop-to-edx
 7216     59/pop-to-ecx
 7217     58/pop-to-eax
 7218     # reclaim curr-index
 7219     81 0/subop/add %esp 4/imm32
 7220     # . epilogue
 7221     89/<- %esp 5/r32/ebp
 7222     5d/pop-to-ebp
 7223     c3/return
 7224 
 7225 $populate-mu-type:abort:
 7226     # error("unexpected top-level command: " word-slice "\n")
 7227     (write-buffered Stderr "incomplete type definition '")
 7228     (type-name *edi)  # Typeinfo-id => eax
 7229     (write-buffered Stderr %eax)
 7230     (write-buffered Stderr "\n")
 7231     (flush Stderr)
 7232     # . syscall(exit, 1)
 7233     bb/copy-to-ebx  1/imm32
 7234     b8/copy-to-eax  1/imm32/exit
 7235     cd/syscall  0x80/imm8
 7236     # never gets here
 7237 
 7238 type-name:  # index: int -> result/eax: (addr array byte)
 7239     # . prologue
 7240     55/push-ebp
 7241     89/<- %ebp 4/r32/esp
 7242     #
 7243     (index Type-id *(ebp+8))
 7244 $type-name:end:
 7245     # . epilogue
 7246     89/<- %esp 5/r32/ebp
 7247     5d/pop-to-ebp
 7248     c3/return
 7249 
 7250 index:  # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte)
 7251     # . prologue
 7252     55/push-ebp
 7253     89/<- %ebp 4/r32/esp
 7254     # . save registers
 7255     56/push-esi
 7256     # TODO: bounds-check index
 7257     # esi = arr
 7258     8b/-> *(ebp+8) 6/r32/esi
 7259     # eax = index
 7260     8b/-> *(ebp+0xc) 0/r32/eax
 7261     # eax = *(arr + 12 + index)
 7262     8b/-> *(esi+eax+0xc) 0/r32/eax
 7263 $index:end:
 7264     # . restore registers
 7265     5e/pop-to-esi
 7266     # . epilogue
 7267     89/<- %esp 5/r32/ebp
 7268     5d/pop-to-ebp
 7269     c3/return
 7270 
 7271 #######################################################
 7272 # Compute type sizes
 7273 #######################################################
 7274 
 7275 # Compute the sizes of all user-defined types.
 7276 # We'll need the sizes of their elements, which may be other user-defined
 7277 # types, which we will compute as needed.
 7278 
 7279 # Initially, all user-defined types have their sizes set to -2 (invalid)
 7280 populate-mu-type-sizes:
 7281     # . prologue
 7282     55/push-ebp
 7283     89/<- %ebp 4/r32/esp
 7284 $populate-mu-type-sizes:total-sizes:
 7285     # var curr/eax: (addr typeinfo) = lookup(Program->types)
 7286     (lookup *_Program-types *_Program-types->payload)  # => eax
 7287     {
 7288       # if (curr == null) break
 7289       3d/compare-eax-and 0/imm32/null
 7290       74/jump-if-= break/disp8
 7291       (populate-mu-type-sizes-in-type %eax)
 7292       # curr = lookup(curr->next)
 7293       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
 7294       eb/jump loop/disp8
 7295     }
 7296 $populate-mu-type-sizes:offsets:
 7297     # curr = *Program->types
 7298     (lookup *_Program-types *_Program-types->payload)  # => eax
 7299     {
 7300       # if (curr == null) break
 7301       3d/compare-eax-and 0/imm32/null
 7302       74/jump-if-= break/disp8
 7303       (populate-mu-type-offsets %eax)
 7304       # curr = curr->next
 7305       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
 7306       eb/jump loop/disp8
 7307     }
 7308 $populate-mu-type-sizes:end:
 7309     # . epilogue
 7310     89/<- %esp 5/r32/ebp
 7311     5d/pop-to-ebp
 7312     c3/return
 7313 
 7314 # compute sizes of all fields, recursing as necessary
 7315 # sum up all their sizes to arrive at total size
 7316 # fields may be out of order, but that doesn't affect the answer
 7317 populate-mu-type-sizes-in-type:  # T: (addr typeinfo)
 7318     # . prologue
 7319     55/push-ebp
 7320     89/<- %ebp 4/r32/esp
 7321     # . save registers
 7322     50/push-eax
 7323     51/push-ecx
 7324     52/push-edx
 7325     56/push-esi
 7326     57/push-edi
 7327     # esi = T
 7328     8b/-> *(ebp+8) 6/r32/esi
 7329     # if T is already computed, return
 7330     81 7/subop/compare *(esi+0xc) 0/imm32  # Typeinfo-total-size-in-bytes
 7331     0f 8d/jump-if->= $populate-mu-type-sizes-in-type:end/disp32
 7332     # if T is being computed, abort
 7333     81 7/subop/compare *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
 7334     0f 84/jump-if-= $populate-mu-type-sizes-in-type:abort/disp32
 7335     # tag T (-2 to -1) to avoid infinite recursion
 7336     c7 0/subop/copy *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
 7337     # var total-size/edi: int = 0
 7338     bf/copy-to-edi 0/imm32
 7339     # - for every field, if it's a user-defined type, compute its size
 7340     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
 7341     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
 7342     89/<- %ecx 0/r32/eax
 7343     # var table-size/edx: int = table->write
 7344     8b/-> *ecx 2/r32/edx  # stream-write
 7345     # var curr/ecx: (addr table_row) = table->data
 7346     8d/copy-address *(ecx+0xc) 1/r32/ecx
 7347     # var max/edx: (addr table_row) = table->data + table->write
 7348     8d/copy-address *(ecx+edx) 2/r32/edx
 7349     {
 7350 $populate-mu-type-sizes-in-type:loop:
 7351       # if (curr >= max) break
 7352       39/compare %ecx 2/r32/edx
 7353       73/jump-if-addr>= break/disp8
 7354       # var t/eax: (addr typeinfo-entry) = lookup(curr->value)
 7355       (lookup *(ecx+8) *(ecx+0xc))  # => eax
 7356       # compute size of t->input-var
 7357       (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
 7358       (compute-size-of-var %eax)  # => eax
 7359       # result += eax
 7360       01/add-to %edi 0/r32/eax
 7361       # curr += row-size
 7362       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
 7363       #
 7364       eb/jump loop/disp8
 7365     }
 7366     # - save result
 7367     89/<- *(esi+0xc) 7/r32/edi  # Typeinfo-total-size-in-bytes
 7368 $populate-mu-type-sizes-in-type:end:
 7369     # . restore registers
 7370     5f/pop-to-edi
 7371     5e/pop-to-esi
 7372     5a/pop-to-edx
 7373     59/pop-to-ecx
 7374     58/pop-to-eax
 7375     # . epilogue
 7376     89/<- %esp 5/r32/ebp
 7377     5d/pop-to-ebp
 7378     c3/return
 7379 
 7380 $populate-mu-type-sizes-in-type:abort:
 7381     (write-buffered Stderr "cycle in type definitions\n")
 7382     (flush Stderr)
 7383     # . syscall(exit, 1)
 7384     bb/copy-to-ebx  1/imm32
 7385     b8/copy-to-eax  1/imm32/exit
 7386     cd/syscall  0x80/imm8
 7387     # never gets here
 7388 
 7389 # Analogous to size-of, except we need to compute what size-of can just read
 7390 # off the right data structures.
 7391 compute-size-of-var:  # in: (addr var) -> result/eax: int
 7392     # . prologue
 7393     55/push-ebp
 7394     89/<- %ebp 4/r32/esp
 7395     # . push registers
 7396     51/push-ecx
 7397     # var t/ecx: (addr tree type-id) = lookup(v->type)
 7398     8b/-> *(ebp+8) 1/r32/ecx
 7399     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 7400     89/<- %ecx 0/r32/eax
 7401     # if (t->is-atom == false) t = lookup(t->left)
 7402     {
 7403       81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
 7404       75/jump-if-!= break/disp8
 7405       (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 7406       89/<- %ecx 0/r32/eax
 7407     }
 7408     # TODO: ensure t is an atom
 7409     (compute-size-of-type-id *(ecx+4))  # Tree-value => eax
 7410 $compute-size-of-var:end:
 7411     # . restore registers
 7412     59/pop-to-ecx
 7413     # . epilogue
 7414     89/<- %esp 5/r32/ebp
 7415     5d/pop-to-ebp
 7416     c3/return
 7417 
 7418 compute-size-of-type-id:  # t: type-id -> result/eax: int
 7419     # . prologue
 7420     55/push-ebp
 7421     89/<- %ebp 4/r32/esp
 7422     # . save registers
 7423     51/push-ecx
 7424     # var out/ecx: (handle typeinfo)
 7425     68/push 0/imm32
 7426     68/push 0/imm32
 7427     89/<- %ecx 4/r32/esp
 7428     # eax = t
 7429     8b/-> *(ebp+8) 0/r32/eax
 7430     # if v is a literal, return 0
 7431     3d/compare-eax-and 0/imm32
 7432     74/jump-if-= $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
 7433     # if v has a user-defined type, compute its size
 7434     # TODO: support non-atom type
 7435     (find-typeinfo %eax %ecx)
 7436     {
 7437       81 7/subop/compare *ecx 0/imm32
 7438       74/jump-if-= break/disp8
 7439 $compute-size-of-type-id:user-defined:
 7440       (populate-mu-type-sizes %eax)
 7441       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
 7442       eb/jump $compute-size-of-type-id:end/disp8
 7443     }
 7444     # otherwise return the word size
 7445     b8/copy-to-eax 4/imm32
 7446 $compute-size-of-type-id:end:
 7447     # . reclaim locals
 7448     81 0/subop/add %esp 8/imm32
 7449     # . restore registers
 7450     59/pop-to-ecx
 7451     # . epilogue
 7452     89/<- %esp 5/r32/ebp
 7453     5d/pop-to-ebp
 7454     c3/return
 7455 
 7456 # at this point we have total sizes for all user-defined types
 7457 # compute offsets for each element
 7458 # complication: fields may be out of order
 7459 populate-mu-type-offsets:  # in: (addr typeinfo)
 7460     # . prologue
 7461     55/push-ebp
 7462     89/<- %ebp 4/r32/esp
 7463     # . save registers
 7464     50/push-eax
 7465     51/push-ecx
 7466     52/push-edx
 7467     53/push-ebx
 7468     56/push-esi
 7469     57/push-edi
 7470 #?     (dump-typeinfos "aaa\n")
 7471     # var curr-offset/edi: int = 0
 7472     bf/copy-to-edi 0/imm32
 7473     # var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(in->fields)
 7474     8b/-> *(ebp+8) 1/r32/ecx
 7475     (lookup *(ecx+4) *(ecx+8))  # Typeinfo-fields Typeinfo-fields => eax
 7476     89/<- %ecx 0/r32/eax
 7477     # var num-elems/edx: int = table->write / Typeinfo-fields-row-size
 7478     8b/-> *ecx 2/r32/edx  # stream-write
 7479     c1 5/subop/shift-right-logical  %edx 4/imm8
 7480     # var i/ebx: int = 0
 7481     bb/copy-to-ebx 0/imm32
 7482     {
 7483 $populate-mu-type-offsets:loop:
 7484       39/compare %ebx 2/r32/edx
 7485       7d/jump-if->= break/disp8
 7486 #?       (write-buffered Stderr "looking up index ")
 7487 #?       (print-int32-buffered Stderr %ebx)
 7488 #?       (write-buffered Stderr " in ")
 7489 #?       (print-int32-buffered Stderr *(ebp+8))
 7490 #?       (write-buffered Stderr Newline)
 7491 #?       (flush Stderr)
 7492       # var v/esi: (addr typeinfo-entry)
 7493       (locate-typeinfo-entry-with-index %ecx %ebx)  # => eax
 7494       89/<- %esi 0/r32/eax
 7495       # v->output-var->offset = curr-offset
 7496       # . eax: (addr var)
 7497       (lookup *(esi+0xc) *(esi+0x10))  # Typeinfo-entry-output-var Typeinfo-entry-output-var => eax
 7498       89/<- *(eax+0x14) 7/r32/edi  # Var-offset
 7499       # curr-offset += size-of(v->input-var)
 7500       (lookup *esi *(esi+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
 7501       (size-of %eax)  # => eax
 7502       01/add-to %edi 0/r32/eax
 7503       # ++i
 7504       43/increment-ebx
 7505       eb/jump loop/disp8
 7506     }
 7507 $populate-mu-type-offsets:end:
 7508     # . restore registers
 7509     5f/pop-to-edi
 7510     5e/pop-to-esi
 7511     5b/pop-to-ebx
 7512     5a/pop-to-edx
 7513     59/pop-to-ecx
 7514     58/pop-to-eax
 7515     # . epilogue
 7516     89/<- %esp 5/r32/ebp
 7517     5d/pop-to-ebp
 7518     c3/return
 7519 
 7520 locate-typeinfo-entry-with-index:  # table: (addr table (handle array byte) (handle typeinfo-entry)), idx: int -> result/eax: (addr typeinfo-entry)
 7521     # . prologue
 7522     55/push-ebp
 7523     89/<- %ebp 4/r32/esp
 7524     # . save registers
 7525     51/push-ecx
 7526     52/push-edx
 7527     53/push-ebx
 7528     56/push-esi
 7529     57/push-edi
 7530     # esi = table
 7531     8b/-> *(ebp+8) 6/r32/esi
 7532     # var curr/ecx: (addr row (handle array byte) (handle typeinfo-entry)) = table->data
 7533     8d/copy-address *(esi+0xc) 1/r32/ecx
 7534     # var max/edx: (addr byte) = &table->data[table->write]
 7535     8b/-> *esi 2/r32/edx
 7536     8d/copy-address *(ecx+edx) 2/r32/edx
 7537     {
 7538 $locate-typeinfo-entry-with-index:loop:
 7539       39/compare %ecx 2/r32/edx
 7540       73/jump-if-addr>= $locate-typeinfo-entry-with-index:abort/disp8
 7541       # var v/eax: (addr typeinfo-entry)
 7542       (lookup *(ecx+8) *(ecx+0xc))  # => eax
 7543       # if (v->index == idx) return v
 7544       8b/-> *(eax+8) 3/r32/ebx  # Typeinfo-entry-index
 7545 #?       (write-buffered Stderr "comparing ")
 7546 #?       (print-int32-buffered Stderr %ebx)
 7547 #?       (write-buffered Stderr " and ")
 7548 #?       (print-int32-buffered Stderr *(ebp+0xc))
 7549 #?       (write-buffered Stderr Newline)
 7550 #?       (flush Stderr)
 7551       39/compare *(ebp+0xc) 3/r32/ebx
 7552       74/jump-if-= $locate-typeinfo-entry-with-index:end/disp8
 7553       # curr += Typeinfo-entry-size
 7554       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-entry-size
 7555       #
 7556       eb/jump loop/disp8
 7557     }
 7558     # return 0
 7559     b8/copy-to-eax 0/imm32
 7560 $locate-typeinfo-entry-with-index:end:
 7561 #?     (write-buffered Stderr "returning ")
 7562 #?     (print-int32-buffered Stderr %eax)
 7563 #?     (write-buffered Stderr Newline)
 7564 #?     (flush Stderr)
 7565     # . restore registers
 7566     5f/pop-to-edi
 7567     5e/pop-to-esi
 7568     5b/pop-to-ebx
 7569     5a/pop-to-edx
 7570     59/pop-to-ecx
 7571     # . epilogue
 7572     89/<- %esp 5/r32/ebp
 7573     5d/pop-to-ebp
 7574     c3/return
 7575 
 7576 $locate-typeinfo-entry-with-index:abort:
 7577     (write-buffered Stderr "overflowing typeinfo-entry->index ")
 7578     (print-int32-buffered Stderr %ecx)
 7579     (write-buffered Stderr "\n")
 7580     (flush Stderr)
 7581     # . syscall(exit, 1)
 7582     bb/copy-to-ebx  1/imm32
 7583     b8/copy-to-eax  1/imm32/exit
 7584     cd/syscall  0x80/imm8
 7585     # never gets here
 7586 
 7587 dump-typeinfos:  # hdr: (addr array byte)
 7588     # . prologue
 7589     55/push-ebp
 7590     89/<- %ebp 4/r32/esp
 7591     # . save registers
 7592     50/push-eax
 7593     #
 7594     (write-buffered Stderr *(ebp+8))
 7595     (flush Stderr)
 7596     # var curr/eax: (addr typeinfo) = lookup(Program->types)
 7597     (lookup *_Program-types *_Program-types->payload)  # => eax
 7598     {
 7599       # if (curr == null) break
 7600       3d/compare-eax-and 0/imm32
 7601       74/jump-if-= break/disp8
 7602       (write-buffered Stderr "---\n")
 7603       (flush Stderr)
 7604       (dump-typeinfo %eax)
 7605       # curr = lookup(curr->next)
 7606       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
 7607       eb/jump loop/disp8
 7608     }
 7609 $dump-typeinfos:end:
 7610     # . restore registers
 7611     58/pop-to-eax
 7612     # . epilogue
 7613     89/<- %esp 5/r32/ebp
 7614     5d/pop-to-ebp
 7615     c3/return
 7616 
 7617 dump-typeinfo:  # in: (addr typeinfo)
 7618     # . prologue
 7619     55/push-ebp
 7620     89/<- %ebp 4/r32/esp
 7621     # . save registers
 7622     50/push-eax
 7623     51/push-ecx
 7624     52/push-edx
 7625     53/push-ebx
 7626     56/push-esi
 7627     57/push-edi
 7628     # esi = in
 7629     8b/-> *(ebp+8) 6/r32/esi
 7630     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
 7631     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
 7632     89/<- %ecx 0/r32/eax
 7633     (write-buffered Stderr "id:")
 7634     (print-int32-buffered Stderr *esi)
 7635     (write-buffered Stderr "\n")
 7636     (write-buffered Stderr "fields @ ")
 7637     (print-int32-buffered Stderr %ecx)
 7638     (write-buffered Stderr Newline)
 7639     (flush Stderr)
 7640     (write-buffered Stderr "  write: ")
 7641     (print-int32-buffered Stderr *ecx)
 7642     (write-buffered Stderr Newline)
 7643     (flush Stderr)
 7644     (write-buffered Stderr "  read: ")
 7645     (print-int32-buffered Stderr *(ecx+4))
 7646     (write-buffered Stderr Newline)
 7647     (flush Stderr)
 7648     (write-buffered Stderr "  size: ")
 7649     (print-int32-buffered Stderr *(ecx+8))
 7650     (write-buffered Stderr Newline)
 7651     (flush Stderr)
 7652     # var table-size/edx: int = table->write
 7653     8b/-> *ecx 2/r32/edx  # stream-write
 7654     # var curr/ecx: (addr table_row) = table->data
 7655     8d/copy-address *(ecx+0xc) 1/r32/ecx
 7656     # var max/edx: (addr table_row) = table->data + table->write
 7657     8d/copy-address *(ecx+edx) 2/r32/edx
 7658     {
 7659 $dump-typeinfo:loop:
 7660       # if (curr >= max) break
 7661       39/compare %ecx 2/r32/edx
 7662       0f 83/jump-if-addr>= break/disp32
 7663       (write-buffered Stderr "  row:\n")
 7664       (write-buffered Stderr "    key: ")
 7665       (print-int32-buffered Stderr *ecx)
 7666       (write-buffered Stderr ",")
 7667       (print-int32-buffered Stderr *(ecx+4))
 7668       (write-buffered Stderr " = '")
 7669       (lookup *ecx *(ecx+4))
 7670       (write-buffered Stderr %eax)
 7671       (write-buffered Stderr "' @ ")
 7672       (print-int32-buffered Stderr %eax)
 7673       (write-buffered Stderr Newline)
 7674       (flush Stderr)
 7675       (write-buffered Stderr "    value: ")
 7676       (print-int32-buffered Stderr *(ecx+8))
 7677       (write-buffered Stderr ",")
 7678       (print-int32-buffered Stderr *(ecx+0xc))
 7679       (write-buffered Stderr " = typeinfo-entry@")
 7680       (lookup *(ecx+8) *(ecx+0xc))
 7681       (print-int32-buffered Stderr %eax)
 7682       (write-buffered Stderr Newline)
 7683       (flush Stderr)
 7684       (write-buffered Stderr "        input var@")
 7685       (print-int32-buffered Stderr *eax)
 7686       (write-buffered Stderr ",")
 7687       (print-int32-buffered Stderr *(eax+4))
 7688       (write-buffered Stderr "->")
 7689       (lookup *eax *(eax+4))  # Typeinfo-entry-input-var
 7690       (print-int32-buffered Stderr %eax)
 7691       {
 7692         3d/compare-eax-and 0/imm32
 7693         74/jump-if-= break/disp8
 7694         (write-buffered Stderr " ")
 7695         # TODO
 7696       }
 7697       (write-buffered Stderr Newline)
 7698       (flush Stderr)
 7699       (lookup *(ecx+8) *(ecx+0xc))
 7700       (write-buffered Stderr "        index: ")
 7701       (print-int32-buffered Stderr *(eax+8))
 7702       (write-buffered Stderr Newline)
 7703       (flush Stderr)
 7704       (write-buffered Stderr "        output var@")
 7705       (print-int32-buffered Stderr *(eax+0xc))
 7706       (write-buffered Stderr ",")
 7707       (print-int32-buffered Stderr *(eax+0x10))
 7708       (write-buffered Stderr "->")
 7709       (lookup *(eax+0xc) *(eax+0x10))  # Typeinfo-entry-output-var
 7710       (print-int32-buffered Stderr %eax)
 7711       (write-buffered Stderr Newline)
 7712       (flush Stderr)
 7713       {
 7714         3d/compare-eax-and 0/imm32
 7715         0f 84/jump-if-= break/disp32
 7716         (write-buffered Stderr "          name: ")
 7717         89/<- %ebx 0/r32/eax
 7718         (print-int32-buffered Stderr *ebx)  # Var-name
 7719         (write-buffered Stderr ",")
 7720         (print-int32-buffered Stderr *(ebx+4))  # Var-name
 7721         (write-buffered Stderr "->")
 7722         (lookup *ebx *(ebx+4))  # Var-name
 7723         (print-int32-buffered Stderr %eax)
 7724         {
 7725           3d/compare-eax-and 0/imm32
 7726           74/jump-if-= break/disp8
 7727           (write-buffered Stderr Space)
 7728           (write-buffered Stderr %eax)
 7729         }
 7730         (write-buffered Stderr Newline)
 7731         (flush Stderr)
 7732         (write-buffered Stderr "          block depth: ")
 7733         (print-int32-buffered Stderr *(ebx+0x10))  # Var-block-depth
 7734         (write-buffered Stderr Newline)
 7735         (flush Stderr)
 7736         (write-buffered Stderr "          stack offset: ")
 7737         (print-int32-buffered Stderr *(ebx+0x14))  # Var-offset
 7738         (write-buffered Stderr Newline)
 7739         (flush Stderr)
 7740         (write-buffered Stderr "          reg: ")
 7741         (print-int32-buffered Stderr *(ebx+0x18))  # Var-register
 7742         (write-buffered Stderr ",")
 7743         (print-int32-buffered Stderr *(ebx+0x1c))  # Var-register
 7744         (write-buffered Stderr "->")
 7745         (flush Stderr)
 7746         (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register
 7747         (print-int32-buffered Stderr %eax)
 7748         {
 7749           3d/compare-eax-and 0/imm32
 7750           74/jump-if-= break/disp8
 7751           (write-buffered Stderr Space)
 7752           (write-buffered Stderr %eax)
 7753         }
 7754         (write-buffered Stderr Newline)
 7755         (flush Stderr)
 7756       }
 7757       (flush Stderr)
 7758       # curr += row-size
 7759       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
 7760       #
 7761       e9/jump loop/disp32
 7762     }
 7763 $dump-typeinfo:end:
 7764     # . restore registers
 7765     5f/pop-to-edi
 7766     5e/pop-to-esi
 7767     5b/pop-to-ebx
 7768     5a/pop-to-edx
 7769     59/pop-to-ecx
 7770     58/pop-to-eax
 7771     # . epilogue
 7772     89/<- %esp 5/r32/ebp
 7773     5d/pop-to-ebp
 7774     c3/return
 7775 
 7776 #######################################################
 7777 # Type-checking
 7778 #######################################################
 7779 
 7780 check-mu-types:
 7781     # . prologue
 7782     55/push-ebp
 7783     89/<- %ebp 4/r32/esp
 7784     #
 7785 $check-mu-types:end:
 7786     # . epilogue
 7787     89/<- %esp 5/r32/ebp
 7788     5d/pop-to-ebp
 7789     c3/return
 7790 
 7791 size-of:  # v: (addr var) -> result/eax: int
 7792     # . prologue
 7793     55/push-ebp
 7794     89/<- %ebp 4/r32/esp
 7795     # . save registers
 7796     51/push-ecx
 7797     # var t/ecx: (addr tree type-id) = lookup(v->type)
 7798     8b/-> *(ebp+8) 1/r32/ecx
 7799 #?     (write-buffered Stderr "size-of ")
 7800 #?     (print-int32-buffered Stderr %ecx)
 7801 #?     (write-buffered Stderr Newline)
 7802 #?     (write-buffered Stderr "type allocid: ")
 7803 #?     (print-int32-buffered Stderr *(ecx+8))
 7804 #?     (write-buffered Stderr Newline)
 7805 #?     (flush Stderr)
 7806     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 7807     89/<- %ecx 0/r32/eax
 7808     # if is-mu-array?(t) return size-of-array(t)
 7809     {
 7810       (is-mu-array? %ecx)  # => eax
 7811       3d/compare-eax-and 0/imm32/false
 7812       74/jump-if-= break/disp8
 7813       (size-of-array %ecx)  # => eax
 7814       eb/jump $size-of:end/disp8
 7815     }
 7816     # if (!t->is-atom?) t = lookup(t->left)
 7817     {
 7818       81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
 7819       75/jump-if-!= break/disp8
 7820       (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 7821       89/<- %ecx 0/r32/eax
 7822     }
 7823     # TODO: assert t->is-atom?
 7824     (size-of-type-id *(ecx+4))  # Tree-value => eax
 7825 $size-of:end:
 7826     # . restore registers
 7827     59/pop-to-ecx
 7828     # . epilogue
 7829     89/<- %esp 5/r32/ebp
 7830     5d/pop-to-ebp
 7831     c3/return
 7832 
 7833 size-of-deref:  # v: (addr var) -> result/eax: int
 7834     # . prologue
 7835     55/push-ebp
 7836     89/<- %ebp 4/r32/esp
 7837     # . save registers
 7838     51/push-ecx
 7839     # var t/ecx: (addr tree type-id) = lookup(v->type)
 7840     8b/-> *(ebp+8) 1/r32/ecx
 7841     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 7842     89/<- %ecx 0/r32/eax
 7843     # TODO: assert(t is an addr)
 7844     # t = lookup(t->right)
 7845     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
 7846     89/<- %ecx 0/r32/eax
 7847     # if is-mu-array?(t) return size-of-array(t)
 7848     {
 7849       (is-mu-array? %ecx)  # => eax
 7850       3d/compare-eax-and 0/imm32/false
 7851       74/jump-if-= break/disp8
 7852       (size-of-array %ecx)  # => eax
 7853       eb/jump $size-of:end/disp8
 7854     }
 7855     # if (!t->is-atom?) t = lookup(t->left)
 7856     {
 7857       81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
 7858       75/jump-if-!= break/disp8
 7859       (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 7860       89/<- %ecx 0/r32/eax
 7861     }
 7862     # TODO: assert t->is-atom?
 7863     (size-of-type-id *(ecx+4))  # Tree-value => eax
 7864 $size-of-deref:end:
 7865     # . restore registers
 7866     59/pop-to-ecx
 7867     # . epilogue
 7868     89/<- %esp 5/r32/ebp
 7869     5d/pop-to-ebp
 7870     c3/return
 7871 
 7872 is-mu-array?:  # t: (addr tree type-id) -> result/eax: boolean
 7873     # . prologue
 7874     55/push-ebp
 7875     89/<- %ebp 4/r32/esp
 7876     # . save registers
 7877     51/push-ecx
 7878     # ecx = t
 7879     8b/-> *(ebp+8) 1/r32/ecx
 7880     # if t->is-atom?, return false
 7881     81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
 7882     75/jump-if-!= $is-mu-array?:return-false/disp8
 7883     # if !t->left->is-atom?, return false
 7884     (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 7885     81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
 7886     74/jump-if-= $is-mu-array?:return-false/disp8
 7887     # return t->left->value == array
 7888     81 7/subop/compare *(eax+4) 3/imm32/array-type-id  # Tree-value
 7889     0f 94/set-if-= %al
 7890     81 4/subop/and %eax 0xff/imm32
 7891     eb/jump $is-mu-array?:end/disp8
 7892 $is-mu-array?:return-false:
 7893     b8/copy-to-eax 0/imm32/false
 7894 $is-mu-array?:end:
 7895     # . restore registers
 7896     59/pop-to-ecx
 7897     # . epilogue
 7898     89/<- %esp 5/r32/ebp
 7899     5d/pop-to-ebp
 7900     c3/return
 7901 
 7902 size-of-array:  # a: (addr tree type-id) -> result/eax: int
 7903     # . prologue
 7904     55/push-ebp
 7905     89/<- %ebp 4/r32/esp
 7906     # . save registers
 7907     51/push-ecx
 7908     52/push-edx
 7909     #
 7910     8b/-> *(ebp+8) 1/r32/ecx
 7911     # TODO: assert that a->left is 'array'
 7912     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
 7913     89/<- %ecx 0/r32/eax
 7914     # var elem-type/edx: type-id = a->right->left->value
 7915     (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 7916     8b/-> *(eax+4) 2/r32/edx  # Tree-value
 7917     # var array-size/ecx: int = a->right->right->left->value
 7918     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
 7919     (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 7920     8b/-> *(eax+4) 1/r32/ecx  # Tree-value
 7921     # return array-size * size-of(elem-type)
 7922     (size-of-type-id %edx)  # => eax
 7923     f7 4/subop/multiply-into-eax %ecx
 7924     05/add-to-eax 4/imm32  # for array size
 7925 $size-of-array:end:
 7926     # . restore registers
 7927     5a/pop-to-edx
 7928     59/pop-to-ecx
 7929     # . epilogue
 7930     89/<- %esp 5/r32/ebp
 7931     5d/pop-to-ebp
 7932     c3/return
 7933 
 7934 size-of-type-id:  # t: type-id -> result/eax: int
 7935     # . prologue
 7936     55/push-ebp
 7937     89/<- %ebp 4/r32/esp
 7938     # . save registers
 7939     51/push-ecx
 7940     # var out/ecx: (handle typeinfo)
 7941     68/push 0/imm32
 7942     68/push 0/imm32
 7943     89/<- %ecx 4/r32/esp
 7944     # eax = t
 7945     8b/-> *(ebp+8) 0/r32/eax
 7946     # if v is a literal, return 0
 7947     3d/compare-eax-and 0/imm32
 7948     74/jump-if-= $size-of-type-id:end/disp8  # eax changes type from type-id to int
 7949     # if v has a user-defined type, return its size
 7950     # TODO: support non-atom type
 7951     (find-typeinfo %eax %ecx)
 7952     {
 7953       81 7/subop/compare *ecx 0/imm32
 7954       74/jump-if-= break/disp8
 7955 $size-of-type-id:user-defined:
 7956       (lookup *ecx *(ecx+4))  # => eax
 7957       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
 7958       eb/jump $size-of-type-id:end/disp8
 7959     }
 7960     # otherwise return the word size
 7961     b8/copy-to-eax 4/imm32
 7962 $size-of-type-id:end:
 7963     # . reclaim locals
 7964     81 0/subop/add %esp 8/imm32
 7965     # . restore registers
 7966     59/pop-to-ecx
 7967     # . epilogue
 7968     89/<- %esp 5/r32/ebp
 7969     5d/pop-to-ebp
 7970     c3/return
 7971 
 7972 type-equal?:  # a: (addr tree type-id), b: (addr tree type-id) -> result/eax: boolean
 7973     # . prologue
 7974     55/push-ebp
 7975     89/<- %ebp 4/r32/esp
 7976     # . save registers
 7977     51/push-ecx
 7978     52/push-edx
 7979     # ecx = a
 7980     8b/-> *(ebp+8) 1/r32/ecx
 7981     # edx = b
 7982     8b/-> *(ebp+0xc) 2/r32/edx
 7983     # if (a == b) return true
 7984     8b/-> %ecx 0/r32/eax  # Var-type
 7985     39/compare %edx 0/r32/eax  # Var-type
 7986     b8/copy-to-eax 1/imm32/true
 7987     74/jump-if-= $type-equal?:end/disp8
 7988     # if (a < MAX_TYPE_ID) return false
 7989     81 7/subop/compare %ecx 0x10000/imm32
 7990     b8/copy-to-eax 0/imm32/false
 7991     72/jump-if-addr< $type-equal?:end/disp8
 7992     # if (b < MAX_TYPE_ID) return false
 7993     81 7/subop/compare %edx 0x10000/imm32
 7994     b8/copy-to-eax 0/imm32/false
 7995     72/jump-if-addr< $type-equal?:end/disp8
 7996     # if (!type-equal?(a->left, b->left)) return false
 7997     (type-equal? *(ecx+4) *(edx+4))  # Tree-left, Tree-left => eax
 7998     3d/compare-eax-and 0/imm32/false
 7999     74/jump-if-= $type-equal?:end/disp8
 8000     # return type-equal?(a->right, b->right)
 8001     (type-equal? *(ecx+8) *(edx+8))  # Tree-right, Tree-right => eax
 8002 $type-equal?:end:
 8003     # . restore registers
 8004     5a/pop-to-edx
 8005     59/pop-to-ecx
 8006     # . epilogue
 8007     89/<- %esp 5/r32/ebp
 8008     5d/pop-to-ebp
 8009     c3/return
 8010 
 8011 #######################################################
 8012 # Code-generation
 8013 #######################################################
 8014 
 8015 == data
 8016 
 8017 Curr-block-depth:  # (addr int)
 8018     0/imm32
 8019 Curr-local-stack-offset:  # (addr int)
 8020     0/imm32
 8021 
 8022 == code
 8023 
 8024 emit-subx:  # out: (addr buffered-file)
 8025     # . prologue
 8026     55/push-ebp
 8027     89/<- %ebp 4/r32/esp
 8028     # . save registers
 8029     50/push-eax
 8030     # var curr/eax: (addr function) = *Program->functions
 8031     (lookup *_Program-functions *_Program-functions->payload)  # => eax
 8032     {
 8033       # if (curr == null) break
 8034       3d/compare-eax-and 0/imm32
 8035       0f 84/jump-if-= break/disp32
 8036       (emit-subx-function *(ebp+8) %eax)
 8037       # curr = lookup(curr->next)
 8038       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
 8039       e9/jump loop/disp32
 8040     }
 8041 $emit-subx:end:
 8042     # . restore registers
 8043     58/pop-to-eax
 8044     # . epilogue
 8045     89/<- %esp 5/r32/ebp
 8046     5d/pop-to-ebp
 8047     c3/return
 8048 
 8049 emit-subx-function:  # out: (addr buffered-file), f: (addr function)
 8050     # . prologue
 8051     55/push-ebp
 8052     89/<- %ebp 4/r32/esp
 8053     # some preprocessing
 8054     (populate-mu-type-offsets-in-inouts *(ebp+0xc))
 8055     # . save registers
 8056     50/push-eax
 8057     51/push-ecx
 8058     52/push-edx
 8059     57/push-edi
 8060     # edi = out
 8061     8b/-> *(ebp+8) 7/r32/edi
 8062     # ecx = f
 8063     8b/-> *(ebp+0xc) 1/r32/ecx
 8064     # var vars/edx: (stack (addr var) 256)
 8065     81 5/subop/subtract %esp 0x800/imm32
 8066     68/push 0x800/imm32/size
 8067     68/push 0/imm32/top
 8068     89/<- %edx 4/r32/esp
 8069     #
 8070     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 8071     (write-buffered %edi %eax)
 8072     (write-buffered %edi ":\n")
 8073     # initialize some global state
 8074     c7 0/subop/copy *Curr-block-depth 1/imm32
 8075     c7 0/subop/copy *Curr-local-stack-offset 0/imm32
 8076     #
 8077     (emit-subx-prologue %edi)
 8078     (lookup *(ecx+0x18) *(ecx+0x1c))  # Function-body Function-body => eax
 8079     (emit-subx-block %edi %eax %edx)
 8080     (emit-subx-epilogue %edi)
 8081     # TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have
 8082     # been cleaned up
 8083 $emit-subx-function:end:
 8084     # . reclaim locals
 8085     81 0/subop/add %esp 808/imm32
 8086     # . restore registers
 8087     5f/pop-to-edi
 8088     5a/pop-to-edx
 8089     59/pop-to-ecx
 8090     58/pop-to-eax
 8091     # . epilogue
 8092     89/<- %esp 5/r32/ebp
 8093     5d/pop-to-ebp
 8094     c3/return
 8095 
 8096 populate-mu-type-offsets-in-inouts:  # f: (addr function)
 8097     # . prologue
 8098     55/push-ebp
 8099     89/<- %ebp 4/r32/esp
 8100     # . save registers
 8101     50/push-eax
 8102     51/push-ecx
 8103     52/push-edx
 8104     53/push-ebx
 8105     57/push-edi
 8106     # var next-offset/edx: int = 8
 8107     ba/copy-to-edx 8/imm32
 8108     # var curr/ecx: (addr list var) = lookup(f->inouts)
 8109     8b/-> *(ebp+8) 1/r32/ecx
 8110     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 8111     89/<- %ecx 0/r32/eax
 8112     {
 8113 $populate-mu-type-offsets-in-inouts:loop:
 8114       81 7/subop/compare %ecx 0/imm32
 8115       74/jump-if-= break/disp8
 8116       # var v/ebx: (addr var) = lookup(curr->value)
 8117       (lookup *ecx *(ecx+4))  # List-value List-value => eax
 8118       89/<- %ebx 0/r32/eax
 8119 #?       (lookup *ebx *(ebx+4))
 8120 #?       (write-buffered Stderr "setting offset of fn inout ")
 8121 #?       (write-buffered Stderr %eax)
 8122 #?       (write-buffered Stderr "@")
 8123 #?       (print-int32-buffered Stderr %ebx)
 8124 #?       (write-buffered Stderr " to ")
 8125 #?       (print-int32-buffered Stderr %edx)
 8126 #?       (write-buffered Stderr Newline)
 8127 #?       (flush Stderr)
 8128       # v->offset = next-offset
 8129       89/<- *(ebx+0x14) 2/r32/edx  # Var-offset
 8130       # next-offset += size-of(v)
 8131       (size-of %ebx)  # => eax
 8132       01/add-to %edx 0/r32/eax
 8133       # curr = lookup(curr->next)
 8134       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
 8135       89/<- %ecx 0/r32/eax
 8136       #
 8137       eb/jump loop/disp8
 8138     }
 8139 $populate-mu-type-offsets-in-inouts:end:
 8140     # . restore registers
 8141     5f/pop-to-edi
 8142     5b/pop-to-ebx
 8143     5a/pop-to-edx
 8144     59/pop-to-ecx
 8145     58/pop-to-eax
 8146     # . epilogue
 8147     89/<- %esp 5/r32/ebp
 8148     5d/pop-to-ebp
 8149     c3/return
 8150 
 8151 emit-subx-stmt-list:  # out: (addr buffered-file), stmts: (addr list stmt), vars: (addr stack (handle var))
 8152     # . prologue
 8153     55/push-ebp
 8154     89/<- %ebp 4/r32/esp
 8155     # . save registers
 8156     50/push-eax
 8157     51/push-ecx
 8158     52/push-edx
 8159     53/push-ebx
 8160     56/push-esi
 8161     # esi = stmts
 8162     8b/-> *(ebp+0xc) 6/r32/esi
 8163     # var var-seen?/edx: boolean <- copy false
 8164     ba/copy-to-edx 0/imm32/false
 8165     #
 8166     {
 8167 $emit-subx-stmt-list:loop:
 8168       81 7/subop/compare %esi 0/imm32
 8169       0f 84/jump-if-= break/disp32
 8170       # var curr-stmt/ecx: (addr stmt) = lookup(stmts->value)
 8171       (lookup *esi *(esi+4))  # List-value List-value => eax
 8172       89/<- %ecx 0/r32/eax
 8173       {
 8174 $emit-subx-stmt-list:check-for-block:
 8175         81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
 8176         75/jump-if-!= break/disp8
 8177 $emit-subx-stmt-list:block:
 8178         (emit-subx-block *(ebp+8) %ecx *(ebp+0x10))
 8179       }
 8180       {
 8181 $emit-subx-stmt-list:check-for-stmt:
 8182         81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
 8183         0f 85/jump-if-!= break/disp32
 8184 $emit-subx-stmt-list:stmt1:
 8185         {
 8186           (is-mu-branch? %ecx)  # => eax
 8187           3d/compare-eax-and 0/imm32/false
 8188           0f 84/jump-if-= break/disp32
 8189 $emit-subx-stmt-list:branch-stmt:
 8190           # if !var-seen? break
 8191           81 7/subop/compare %edx 0/imm32/false
 8192           0f 84/jump-if-= break/disp32
 8193 $emit-subx-stmt-list:branch-stmt-and-var-seen:
 8194 +-- 27 lines: # unconditional loops -----------------------------------------------------------------------------------------------------------------------------------------------------
 8221 +-- 16 lines: # unconditional breaks ----------------------------------------------------------------------------------------------------------------------------------------------------
 8237 +-- 38 lines: # simple conditional branches without a target ----------------------------------------------------------------------------------------------------------------------------
 8275 +-- 19 lines: # conditional branches with an explicit target ----------------------------------------------------------------------------------------------------------------------------
 8294         }
 8295 $emit-subx-stmt-list:1-to-1:
 8296         (emit-subx-stmt *(ebp+8) %ecx Primitives)
 8297         e9/jump $emit-subx-stmt-list:continue/disp32
 8298       }
 8299       {
 8300 $emit-subx-stmt-list:check-for-var-def:
 8301         81 7/subop/compare *ecx 2/imm32/var-def  # Stmt-tag
 8302         75/jump-if-!= break/disp8
 8303 $emit-subx-stmt-list:var-def:
 8304         (emit-subx-var-def *(ebp+8) %ecx)
 8305         (push *(ebp+0x10) *(ecx+4))  # Vardef-var
 8306         (push *(ebp+0x10) *(ecx+8))  # Vardef-var
 8307         # var-seen? = true
 8308         ba/copy-to-edx 1/imm32/true
 8309         eb/jump $emit-subx-stmt-list:continue/disp8
 8310       }
 8311       {
 8312 $emit-subx-stmt-list:check-for-reg-var-def:
 8313         81 7/subop/compare *ecx 3/imm32/reg-var-def  # Stmt-tag
 8314         0f 85/jump-if-!= break/disp32
 8315 $emit-subx-stmt-list:reg-var-def:
 8316         # TODO: ensure that there's exactly one output
 8317         (push-output-and-maybe-emit-spill *(ebp+8) %ecx *(ebp+0x10))
 8318         # emit the instruction as usual
 8319         (emit-subx-stmt *(ebp+8) %ecx Primitives)
 8320         # var-seen? = true
 8321         ba/copy-to-edx 1/imm32/true
 8322         eb/jump $emit-subx-stmt-list:continue/disp8
 8323       }
 8324 $emit-subx-stmt-list:continue:
 8325       # TODO: raise an error on unrecognized Stmt-tag
 8326       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
 8327       89/<- %esi 0/r32/eax
 8328       e9/jump loop/disp32
 8329     }
 8330 $emit-subx-stmt-list:emit-cleanup:
 8331     (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
 8332 $emit-subx-stmt-list:clean-up:
 8333     (clean-up-blocks *(ebp+0x10) *Curr-block-depth)
 8334 $emit-subx-stmt-list:end:
 8335     # . restore registers
 8336     5e/pop-to-esi
 8337     5b/pop-to-ebx
 8338     5a/pop-to-edx
 8339     59/pop-to-ecx
 8340     58/pop-to-eax
 8341     # . epilogue
 8342     89/<- %esp 5/r32/ebp
 8343     5d/pop-to-ebp
 8344     c3/return
 8345 
 8346 push-output-and-maybe-emit-spill:  # out: (addr buffered-file), stmt: (addr reg-var-def), vars: (addr stack (handle var))
 8347     # . prologue
 8348     55/push-ebp
 8349     89/<- %ebp 4/r32/esp
 8350     # . save registers
 8351     50/push-eax
 8352     51/push-ecx
 8353     # ecx = stmt
 8354     8b/-> *(ebp+0xc) 1/r32/ecx
 8355     # var sv/eax: (addr stmt-var) = lookup(curr-stmt->outputs)
 8356     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
 8357     # TODO: assert !sv->is-deref?
 8358     # var v/ecx: (addr var) = lookup(sv->value)
 8359     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 8360     89/<- %ecx 0/r32/eax
 8361     # v->block-depth = *Curr-block-depth
 8362     8b/-> *Curr-block-depth 0/r32/eax
 8363     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
 8364 #?     (write-buffered Stderr "var ")
 8365 #?     (lookup *ecx *(ecx+4))
 8366 #?     (write-buffered Stderr %eax)
 8367 #?     (write-buffered Stderr " at depth ")
 8368 #?     (print-int32-buffered Stderr *(ecx+0x10))
 8369 #?     (write-buffered Stderr Newline)
 8370 #?     (flush Stderr)
 8371     # ensure that v is in a register
 8372     81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
 8373     0f 84/jump-if-= $push-output-and-maybe-emit-spill:abort/disp32
 8374     # if !already-spilled-this-block?(reg, vars) emit code to spill reg
 8375     (already-spilled-this-block? %ecx *(ebp+0x10))  # => eax
 8376     3d/compare-eax-and 0/imm32/false
 8377     75/jump-if-!= $push-output-and-maybe-emit-spill:push/disp8
 8378     # TODO: assert(size-of(output) == 4)
 8379     # *Curr-local-stack-offset -= 4
 8380     81 5/subop/subtract *Curr-local-stack-offset 4/imm32
 8381     # emit spill
 8382     (emit-indent *(ebp+8) *Curr-block-depth)
 8383     (write-buffered *(ebp+8) "ff 6/subop/push %")
 8384     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 8385     (write-buffered *(ebp+8) %eax)
 8386     (write-buffered *(ebp+8) Newline)
 8387 $push-output-and-maybe-emit-spill:push:
 8388     8b/-> *(ebp+0xc) 1/r32/ecx
 8389     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
 8390     # push(vars, sv->value)
 8391     (push *(ebp+0x10) *eax)  # Stmt-var-value
 8392     (push *(ebp+0x10) *(eax+4))  # Stmt-var-value
 8393 $push-output-and-maybe-emit-spill:end:
 8394     # . restore registers
 8395     59/pop-to-ecx
 8396     58/pop-to-eax
 8397     # . epilogue
 8398     89/<- %esp 5/r32/ebp
 8399     5d/pop-to-ebp
 8400     c3/return
 8401 
 8402 $push-output-and-maybe-emit-spill:abort:
 8403     # error("var '" var->name "' initialized from an instruction must live in a register\n")
 8404     (write-buffered Stderr "var '")
 8405     (write-buffered Stderr *eax)  # Var-name
 8406     (write-buffered Stderr "' initialized from an instruction must live in a register\n")
 8407     (flush Stderr)
 8408     # . syscall(exit, 1)
 8409     bb/copy-to-ebx  1/imm32
 8410     b8/copy-to-eax  1/imm32/exit
 8411     cd/syscall  0x80/imm8
 8412     # never gets here
 8413 
 8414 emit-subx-cleanup-and-unconditional-nonlocal-branch:  # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack (handle var))
 8415     # . prologue
 8416     55/push-ebp
 8417     89/<- %ebp 4/r32/esp
 8418     # . save registers
 8419     50/push-eax
 8420     51/push-ecx
 8421     # ecx = stmt
 8422     8b/-> *(ebp+0xc) 1/r32/ecx
 8423     # var target/eax: (addr array byte) = curr-stmt->inouts->value->name
 8424     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 8425     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 8426     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8427     # clean up until target block
 8428     (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %eax)
 8429     # emit jump to target block
 8430     (emit-indent *(ebp+8) *Curr-block-depth)
 8431     (write-buffered *(ebp+8) "e9/jump ")
 8432     (write-buffered *(ebp+8) %eax)
 8433     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
 8434     (string-starts-with? %eax "break")
 8435     3d/compare-eax-and 0/imm32/false
 8436     {
 8437       74/jump-if-= break/disp8
 8438       (write-buffered *(ebp+8) ":break/disp32\n")
 8439     }
 8440     3d/compare-eax-and 0/imm32/false  # just in case the function call modified flags
 8441     {
 8442       75/jump-if-!= break/disp8
 8443       (write-buffered *(ebp+8) ":loop/disp32\n")
 8444     }
 8445 $emit-subx-cleanup-and-unconditional-nonlocal-branch:end:
 8446     # . restore registers
 8447     59/pop-to-ecx
 8448     58/pop-to-eax
 8449     # . epilogue
 8450     89/<- %esp 5/r32/ebp
 8451     5d/pop-to-ebp
 8452     c3/return
 8453 
 8454 is-mu-branch?:  # stmt: (addr stmt1) -> result/eax: boolean
 8455     # . prologue
 8456     55/push-ebp
 8457     89/<- %ebp 4/r32/esp
 8458     # . save registers
 8459     51/push-ecx
 8460     # ecx = lookup(stmt->operation)
 8461     8b/-> *(ebp+8) 1/r32/ecx
 8462     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
 8463     89/<- %ecx 0/r32/eax
 8464     # if (stmt->operation starts with "loop") return true
 8465     (string-starts-with? %ecx "loop")  # => eax
 8466     3d/compare-eax-and 0/imm32/false
 8467     75/jump-if-not-equal $is-mu-branch?:end/disp8
 8468     # otherwise return (stmt->operation starts with "break")
 8469     (string-starts-with? %ecx "break")  # => eax
 8470 $is-mu-branch?:end:
 8471     # . restore registers
 8472     59/pop-to-ecx
 8473     # . epilogue
 8474     89/<- %esp 5/r32/ebp
 8475     5d/pop-to-ebp
 8476     c3/return
 8477 
 8478 emit-reverse-break:  # out: (addr buffered-file), stmt: (addr stmt1)
 8479     # . prologue
 8480     55/push-ebp
 8481     89/<- %ebp 4/r32/esp
 8482     # . save registers
 8483     50/push-eax
 8484     # eax = stmt
 8485     8b/-> *(ebp+0xc) 0/r32/eax
 8486     #
 8487     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
 8488     (get Reverse-branch %eax 0x10 "reverse-branch: ")  # => eax: (addr handle array byte)
 8489     (emit-indent *(ebp+8) *Curr-block-depth)
 8490     (lookup *eax *(eax+4))  # => eax
 8491     (write-buffered *(ebp+8) %eax)
 8492     (write-buffered *(ebp+8) " break/disp32\n")
 8493 $emit-reverse-break:end:
 8494     # . restore registers
 8495     58/pop-to-eax
 8496     # . epilogue
 8497     89/<- %esp 5/r32/ebp
 8498     5d/pop-to-ebp
 8499     c3/return
 8500 
 8501 == data
 8502 
 8503 # Table from Mu branch instructions to the reverse SubX opcodes for them.
 8504 Reverse-branch:  # (table (handle array byte) (handle array byte))
 8505   # a table is a stream
 8506   0x140/imm32/write
 8507   0/imm32/read
 8508   0x140/imm32/size
 8509   # data
 8510   0x11/imm32/alloc-id   _string-break-if-=/imm32                0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
 8511   0x11/imm32/alloc-id   _string-loop-if-=/imm32                 0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
 8512   0x11/imm32/alloc-id   _string-break-if-!=/imm32               0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
 8513   0x11/imm32/alloc-id   _string-loop-if-!=/imm32                0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
 8514   0x11/imm32/alloc-id   _string-break-if-</imm32                0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
 8515   0x11/imm32/alloc-id   _string-loop-if-</imm32                 0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
 8516   0x11/imm32/alloc-id   _string-break-if->/imm32                0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
 8517   0x11/imm32/alloc-id   _string-loop-if->/imm32                 0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
 8518   0x11/imm32/alloc-id   _string-break-if-<=/imm32               0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
 8519   0x11/imm32/alloc-id   _string-loop-if-<=/imm32                0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
 8520   0x11/imm32/alloc-id   _string-break-if->=/imm32               0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
 8521   0x11/imm32/alloc-id   _string-loop-if->=/imm32                0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
 8522   0x11/imm32/alloc-id   _string-break-if-addr</imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
 8523   0x11/imm32/alloc-id   _string-loop-if-addr</imm32             0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
 8524   0x11/imm32/alloc-id   _string-break-if-addr>/imm32            0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
 8525   0x11/imm32/alloc-id   _string-loop-if-addr>/imm32             0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
 8526   0x11/imm32/alloc-id   _string-break-if-addr<=/imm32           0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
 8527   0x11/imm32/alloc-id   _string-loop-if-addr<=/imm32            0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
 8528   0x11/imm32/alloc-id   _string-break-if-addr>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
 8529   0x11/imm32/alloc-id   _string-loop-if-addr>=/imm32            0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
 8530 
 8531 == code
 8532 
 8533 emit-unconditional-jump-to-depth:  # out: (addr buffered-file), vars: (addr stack (handle var)), depth: int, label-suffix: (addr array byte)
 8534     # . prologue
 8535     55/push-ebp
 8536     89/<- %ebp 4/r32/esp
 8537     # . save registers
 8538     50/push-eax
 8539     51/push-ecx
 8540     52/push-edx
 8541     53/push-ebx
 8542     56/push-esi
 8543     # ecx = vars
 8544     8b/-> *(ebp+0xc) 1/r32/ecx
 8545     # var eax: int = vars->top
 8546     8b/-> *ecx 0/r32/eax
 8547     # var curr/esi: (addr handle var) = &vars->data[vars->top - 8]
 8548     8d/copy-address *(ecx+eax) 6/r32/esi  # vars + 8 + vars->top - 8
 8549     # var min/ecx: (addr handle var) = vars->data
 8550     81 0/subop/add %ecx 8/imm32
 8551     # edx = depth
 8552     8b/-> *(ebp+0x10) 2/r32/edx
 8553     {
 8554 $emit-unconditional-jump-to-depth:loop:
 8555       # if (curr < min) break
 8556       39/compare %esi 1/r32/ecx
 8557       0f 82/jump-if-addr< break/disp32
 8558       # var v/ebx: (addr var) = lookup(*curr)
 8559       (lookup *esi *(esi+4))  # => eax
 8560       89/<- %ebx 0/r32/eax
 8561       # if (v->block-depth < until-block-depth) break
 8562       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
 8563       0f 8c/jump-if-< break/disp32
 8564       {
 8565 $emit-unconditional-jump-to-depth:check:
 8566         # if v->block-depth != until-block-depth, continue
 8567         39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
 8568         0f 85/jump-if-!= break/disp32
 8569 $emit-unconditional-jump-to-depth:depth-found:
 8570         # if v is not a literal, continue
 8571         (size-of %ebx)  # => eax
 8572         3d/compare-eax-and 0/imm32
 8573         0f 85/jump-if-!= break/disp32
 8574 $emit-unconditional-jump-to-depth:label-found:
 8575         # emit unconditional jump, then return
 8576         (emit-indent *(ebp+8) *Curr-block-depth)
 8577         (write-buffered *(ebp+8) "e9/jump ")
 8578         (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8579         (write-buffered *(ebp+8) %eax)
 8580         (write-buffered *(ebp+8) ":")
 8581         (write-buffered *(ebp+8) *(ebp+0x14))
 8582         (write-buffered *(ebp+8) "/disp32\n")
 8583         eb/jump $emit-unconditional-jump-to-depth:end/disp8
 8584       }
 8585       # curr -= 8
 8586       81 5/subop/subtract %esi 8/imm32
 8587       e9/jump loop/disp32
 8588     }
 8589     # TODO: error if no label at 'depth' was found
 8590 $emit-unconditional-jump-to-depth:end:
 8591     # . restore registers
 8592     5e/pop-to-esi
 8593     5b/pop-to-ebx
 8594     5a/pop-to-edx
 8595     59/pop-to-ecx
 8596     58/pop-to-eax
 8597     # . epilogue
 8598     89/<- %esp 5/r32/ebp
 8599     5d/pop-to-ebp
 8600     c3/return
 8601 
 8602 # emit clean-up code for 'vars' until some block depth
 8603 # doesn't actually modify 'vars' so we need traverse manually inside the stack
 8604 emit-cleanup-code-until-depth:  # out: (addr buffered-file), vars: (addr stack (handle var)), until-block-depth: int
 8605     # . prologue
 8606     55/push-ebp
 8607     89/<- %ebp 4/r32/esp
 8608     # . save registers
 8609     50/push-eax
 8610     51/push-ecx
 8611     52/push-edx
 8612     53/push-ebx
 8613     56/push-esi
 8614 #?     (write-buffered Stderr "--- cleanup\n")
 8615 #?     (flush Stderr)
 8616     # ecx = vars
 8617     8b/-> *(ebp+0xc) 1/r32/ecx
 8618     # var esi: int = vars->top
 8619     8b/-> *ecx 6/r32/esi
 8620     # var curr/esi: (addr handle var) = &vars->data[vars->top - 8]
 8621     8d/copy-address *(ecx+esi) 6/r32/esi  # vars + 8 + vars->top - 8
 8622     # var min/ecx: (addr handle var) = vars->data
 8623     81 0/subop/add %ecx 8/imm32
 8624     # edx = until-block-depth
 8625     8b/-> *(ebp+0x10) 2/r32/edx
 8626     {
 8627 $emit-cleanup-code-until-depth:loop:
 8628       # if (curr < min) break
 8629       39/compare %esi 1/r32/ecx
 8630       0f 82/jump-if-addr< break/disp32
 8631       # var v/ebx: (addr var) = lookup(*curr)
 8632       (lookup *esi *(esi+4))  # => eax
 8633       89/<- %ebx 0/r32/eax
 8634 #?       (lookup *ebx *(ebx+4))  # Var-name
 8635 #?       (write-buffered Stderr "var ")
 8636 #?       (write-buffered Stderr %eax)
 8637 #?       (write-buffered Stderr Newline)
 8638 #?       (flush Stderr)
 8639       # if (v->block-depth < until-block-depth) break
 8640       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
 8641       0f 8c/jump-if-< break/disp32
 8642       # if v is in a register
 8643       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
 8644       {
 8645         0f 84/jump-if-= break/disp32
 8646         {
 8647 $emit-cleanup-code-until-depth:check-for-previous-spill:
 8648           (same-register-spilled-before? %ebx *(ebp+0xc) %esi)  # => eax
 8649           3d/compare-eax-and 0/imm32/false
 8650           0f 85/jump-if-!= break/disp32
 8651 $emit-cleanup-code-until-depth:reclaim-var-in-register:
 8652           (emit-indent *(ebp+8) *Curr-block-depth)
 8653           (write-buffered *(ebp+8) "8f 0/subop/pop %")
 8654           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 8655           (write-buffered *(ebp+8) %eax)
 8656           (write-buffered *(ebp+8) Newline)
 8657         }
 8658         eb/jump $emit-cleanup-code-until-depth:continue/disp8
 8659       }
 8660       # otherwise v is on the stack
 8661       {
 8662         75/jump-if-!= break/disp8
 8663 $emit-cleanup-code-until-depth:var-on-stack:
 8664         (size-of %ebx)  # => eax
 8665         # don't emit code for labels
 8666         3d/compare-eax-and 0/imm32
 8667         74/jump-if-= break/disp8
 8668 $emit-cleanup-code-until-depth:reclaim-var-on-stack:
 8669         (emit-indent *(ebp+8) *Curr-block-depth)
 8670         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
 8671         (print-int32-buffered *(ebp+8) %eax)
 8672         (write-buffered *(ebp+8) "/imm32\n")
 8673       }
 8674 $emit-cleanup-code-until-depth:continue:
 8675       # curr -= 8
 8676       81 5/subop/subtract %esi 8/imm32
 8677       e9/jump loop/disp32
 8678     }
 8679 $emit-cleanup-code-until-depth:end:
 8680     # . restore registers
 8681     5e/pop-to-esi
 8682     5b/pop-to-ebx
 8683     5a/pop-to-edx
 8684     59/pop-to-ecx
 8685     58/pop-to-eax
 8686     # . epilogue
 8687     89/<- %esp 5/r32/ebp
 8688     5d/pop-to-ebp
 8689     c3/return
 8690 
 8691 # emit clean-up code for 'vars' until a given label is encountered
 8692 # doesn't actually modify 'vars' so we need traverse manually inside the stack
 8693 emit-cleanup-code-until-target:  # out: (addr buffered-file), vars: (addr stack (handle var)), until-block-label: (addr array byte)
 8694     # . prologue
 8695     55/push-ebp
 8696     89/<- %ebp 4/r32/esp
 8697     # . save registers
 8698     50/push-eax
 8699     51/push-ecx
 8700     52/push-edx
 8701     53/push-ebx
 8702     # ecx = vars
 8703     8b/-> *(ebp+0xc) 1/r32/ecx
 8704     # var eax: int = vars->top
 8705     8b/-> *ecx 0/r32/eax
 8706     # var curr/edx: (addr handle var) = &vars->data[vars->top - 8]
 8707     8d/copy-address *(ecx+eax) 2/r32/edx  # vars + 8 + vars->top - 8
 8708     # var min/ecx: (addr handle var) = vars->data
 8709     81 0/subop/add %ecx 8/imm32
 8710     {
 8711 $emit-cleanup-code-until-target:loop:
 8712       # if (curr < min) break
 8713       39/compare %edx 1/r32/ecx
 8714       0f 82/jump-if-addr< break/disp32
 8715       # var v/ebx: (handle var) = lookup(*curr)
 8716       (lookup *edx *(edx+4))  # => eax
 8717       89/<- %ebx 0/r32/eax
 8718       # if (v->name == until-block-label) break
 8719       (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8720       (string-equal? %eax *(ebp+0x10))  # => eax
 8721       3d/compare-eax-and 0/imm32/false
 8722       0f 85/jump-if-!= break/disp32
 8723       # if v is in a register
 8724       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
 8725       {
 8726         0f 84/jump-if-= break/disp32
 8727         {
 8728 $emit-cleanup-code-until-target:check-for-previous-spill:
 8729           (same-register-spilled-before? %ebx *(ebp+0xc) %edx)  # => eax
 8730           3d/compare-eax-and 0/imm32/false
 8731           75/jump-if-!= break/disp8
 8732 $emit-cleanup-code-until-target:reclaim-var-in-register:
 8733           (emit-indent *(ebp+8) *Curr-block-depth)
 8734           (write-buffered *(ebp+8) "8f 0/subop/pop %")
 8735           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 8736           (write-buffered *(ebp+8) %eax)
 8737           (write-buffered *(ebp+8) Newline)
 8738         }
 8739         eb/jump $emit-cleanup-code-until-target:continue/disp8
 8740       }
 8741       # otherwise v is on the stack
 8742       {
 8743         75/jump-if-!= break/disp8
 8744 $emit-cleanup-code-until-target:reclaim-var-on-stack:
 8745         (size-of %ebx)  # => eax
 8746         # don't emit code for labels
 8747         3d/compare-eax-and 0/imm32
 8748         74/jump-if-= break/disp8
 8749         #
 8750         (emit-indent *(ebp+8) *Curr-block-depth)
 8751         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
 8752         (print-int32-buffered *(ebp+8) %eax)
 8753         (write-buffered *(ebp+8) "/imm32\n")
 8754       }
 8755 $emit-cleanup-code-until-target:continue:
 8756       # curr -= 8
 8757       81 5/subop/subtract %edx 8/imm32
 8758       e9/jump loop/disp32
 8759     }
 8760 $emit-cleanup-code-until-target:end:
 8761     # . restore registers
 8762     5b/pop-to-ebx
 8763     5a/pop-to-edx
 8764     59/pop-to-ecx
 8765     58/pop-to-eax
 8766     # . epilogue
 8767     89/<- %esp 5/r32/ebp
 8768     5d/pop-to-ebp
 8769     c3/return
 8770 
 8771 # is there already a var with the same block-depth and register as 'v' on the 'vars' stack?
 8772 # v is guaranteed not to be within vars
 8773 already-spilled-this-block?:  # v: (addr var), vars: (addr stack (handle var)) -> result/eax: boolean
 8774     # . prologue
 8775     55/push-ebp
 8776     89/<- %ebp 4/r32/esp
 8777     # . save registers
 8778     51/push-ecx
 8779     52/push-edx
 8780     53/push-ebx
 8781     56/push-esi
 8782     57/push-edi
 8783     # ecx = vars
 8784     8b/-> *(ebp+0xc) 1/r32/ecx
 8785     # var eax: int = vars->top
 8786     8b/-> *ecx 0/r32/eax
 8787     # var min/ecx: (addr handle var) = vars->data
 8788     81 0/subop/add %ecx 8/imm32
 8789     # var curr/edx: (addr handle var) = &vars->data[vars->top - 8]
 8790     81 5/subop/subtract %eax 8/imm32
 8791     8d/copy-address *(ecx+eax) 2/r32/edx
 8792     # var depth/ebx: int = v->block-depth
 8793     8b/-> *(ebp+8) 3/r32/ebx
 8794     8b/-> *(ebx+0x10) 3/r32/ebx  # Var-block-depth
 8795     # var needle/esi: (addr array byte) = v->register
 8796     8b/-> *(ebp+8) 6/r32/esi
 8797     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
 8798     89/<- %esi 0/r32/eax
 8799     {
 8800 $already-spilled-this-block?:loop:
 8801       # if (curr < min) break
 8802       39/compare %edx 1/r32/ecx
 8803       0f 82/jump-if-addr< break/disp32
 8804       # var cand/edi: (addr var) = lookup(*curr)
 8805       (lookup *edx *(edx+4))  # => eax
 8806       89/<- %edi 0/r32/eax
 8807       # if (cand->block-depth < depth) break
 8808       39/compare *(edi+0x10) 3/r32/ebx  # Var-block-depth
 8809       0f 8c/jump-if-< break/disp32
 8810       # var cand-reg/edi: (array array byte) = cand->reg
 8811       (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
 8812       89/<- %edi 0/r32/eax
 8813       # if (cand-reg == null) continue
 8814       {
 8815 $already-spilled-this-block?:check-reg:
 8816         81 7/subop/compare %edi 0/imm32
 8817         0f 84/jump-if-= break/disp32
 8818         # if (cand-reg == needle) return true
 8819         (string-equal? %esi %edi)  # => eax
 8820         3d/compare-eax-and 0/imm32/false
 8821         74/jump-if-= break/disp8
 8822 $already-spilled-this-block?:return-true:
 8823         b8/copy-to-eax 1/imm32/true
 8824         eb/jump $already-spilled-this-block?:end/disp8
 8825       }
 8826 $already-spilled-this-block?:continue:
 8827       # curr -= 8
 8828       81 5/subop/subtract %edx 8/imm32
 8829       e9/jump loop/disp32
 8830     }
 8831     # return false
 8832     b8/copy-to-eax 0/imm32/false
 8833 $already-spilled-this-block?:end:
 8834     # . restore registers
 8835     5f/pop-to-edi
 8836     5e/pop-to-esi
 8837     5b/pop-to-ebx
 8838     5a/pop-to-edx
 8839     59/pop-to-ecx
 8840     # . epilogue
 8841     89/<- %esp 5/r32/ebp
 8842     5d/pop-to-ebp
 8843     c3/return
 8844 
 8845 # is there a var before 'v' with the same block-depth and register on the 'vars' stack?
 8846 # v is guaranteed to be within vars
 8847 # 'start' is provided as an optimization, a pointer within vars
 8848 # *start == v
 8849 same-register-spilled-before?:  # v: (addr var), vars: (addr stack (handle var)), start: (addr var) -> result/eax: boolean
 8850     # . prologue
 8851     55/push-ebp
 8852     89/<- %ebp 4/r32/esp
 8853     # . save registers
 8854     51/push-ecx
 8855     52/push-edx
 8856     53/push-ebx
 8857     56/push-esi
 8858     57/push-edi
 8859     # ecx = v
 8860     8b/-> *(ebp+8) 1/r32/ecx
 8861     # var reg/edx: (addr array byte) = lookup(v->register)
 8862     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 8863     89/<- %edx 0/r32/eax
 8864     # var depth/ebx: int = v->block-depth
 8865     8b/-> *(ecx+0x10) 3/r32/ebx  # Var-block-depth
 8866     # var min/ecx: (addr handle var) = vars->data
 8867     8b/-> *(ebp+0xc) 1/r32/ecx
 8868     81 0/subop/add %ecx 8/imm32
 8869     # TODO: check that start >= min and start < &vars->data[top]
 8870     # TODO: check that *start == v
 8871     # var curr/esi: (addr handle var) = start
 8872     8b/-> *(ebp+0x10) 6/r32/esi
 8873     # curr -= 8
 8874     81 5/subop/subtract %esi 8/imm32
 8875     {
 8876 $same-register-spilled-before?:loop:
 8877       # if (curr < min) break
 8878       39/compare %esi 1/r32/ecx
 8879       0f 82/jump-if-addr< break/disp32
 8880       # var x/eax: (addr var) = lookup(*curr)
 8881       (lookup *esi *(esi+4))  # => eax
 8882       # if (x->block-depth < depth) break
 8883       39/compare *(eax+0x10) 3/r32/ebx  # Var-block-depth
 8884       0f 8c/jump-if-< break/disp32
 8885       # if (x->register == 0) continue
 8886       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 8887       74/jump-if-= $same-register-spilled-before?:continue/disp8
 8888       # if (x->register == reg) return true
 8889       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 8890       (string-equal? %eax %edx)  # => eax
 8891       3d/compare-eax-and 0/imm32/false
 8892       b8/copy-to-eax 1/imm32/true
 8893       75/jump-if-!= $same-register-spilled-before?:end/disp8
 8894 $same-register-spilled-before?:continue:
 8895       # curr -= 8
 8896       81 5/subop/subtract %esi 8/imm32
 8897       e9/jump loop/disp32
 8898     }
 8899 $same-register-spilled-before?:false:
 8900     b8/copy-to-eax 0/imm32/false
 8901 $same-register-spilled-before?:end:
 8902     # . restore registers
 8903     5f/pop-to-edi
 8904     5e/pop-to-esi
 8905     5b/pop-to-ebx
 8906     5a/pop-to-edx
 8907     59/pop-to-ecx
 8908     # . epilogue
 8909     89/<- %esp 5/r32/ebp
 8910     5d/pop-to-ebp
 8911     c3/return
 8912 
 8913 # clean up global state for 'vars' until some block depth
 8914 clean-up-blocks:  # vars: (addr stack (handle var)), until-block-depth: int
 8915     # . prologue
 8916     55/push-ebp
 8917     89/<- %ebp 4/r32/esp
 8918     # . save registers
 8919     50/push-eax
 8920     51/push-ecx
 8921     56/push-esi
 8922     # esi = vars
 8923     8b/-> *(ebp+8) 6/r32/esi
 8924     # ecx = until-block-depth
 8925     8b/-> *(ebp+0xc) 1/r32/ecx
 8926     {
 8927 $clean-up-blocks:reclaim-loop:
 8928       # if (vars->top <= 0) break
 8929       8b/-> *esi 0/r32/eax  # Stack-top
 8930       3d/compare-eax-and 0/imm32
 8931       7e/jump-if-<= break/disp8
 8932       # var v/eax: (addr var) = lookup(vars[vars->top-8])
 8933       (lookup *(esi+eax) *(esi+eax+4))  # vars + 8 + vars->top - 8 => eax
 8934       # if (v->block-depth < until-block-depth) break
 8935       39/compare *(eax+0x10) 1/r32/ecx  # Var-block-depth
 8936       7c/jump-if-< break/disp8
 8937       # if v is on the stack, update Curr-local-stack-offset
 8938       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 8939       {
 8940         75/jump-if-!= break/disp8
 8941 $clean-up-blocks:reclaim-var-on-stack:
 8942         (size-of %eax)  # => eax
 8943         01/add-to *Curr-local-stack-offset 0/r32/eax
 8944       }
 8945       (pop %esi)  # => eax
 8946       (pop %esi)  # => eax
 8947       e9/jump loop/disp32
 8948     }
 8949 $clean-up-blocks:end:
 8950     # . restore registers
 8951     5e/pop-to-esi
 8952     59/pop-to-ecx
 8953     58/pop-to-eax
 8954     # . epilogue
 8955     89/<- %esp 5/r32/ebp
 8956     5d/pop-to-ebp
 8957     c3/return
 8958 
 8959 emit-subx-var-def:  # out: (addr buffered-file), stmt: (addr stmt)
 8960     # . prologue
 8961     55/push-ebp
 8962     89/<- %ebp 4/r32/esp
 8963     # . save registers
 8964     50/push-eax
 8965     51/push-ecx
 8966     52/push-edx
 8967     # eax = stmt
 8968     8b/-> *(ebp+0xc) 0/r32/eax
 8969     # var v/ecx: (addr var)
 8970     (lookup *(eax+4) *(eax+8))  # Vardef-var Vardef-var => eax
 8971     89/<- %ecx 0/r32/eax
 8972     # v->block-depth = *Curr-block-depth
 8973     8b/-> *Curr-block-depth 0/r32/eax
 8974     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
 8975     # var n/edx: int = size-of(stmt->var)
 8976     (size-of %ecx)  # => eax
 8977     89/<- %edx 0/r32/eax
 8978     # *Curr-local-stack-offset -= n
 8979     29/subtract-from *Curr-local-stack-offset 2/r32/edx
 8980     # v->offset = *Curr-local-stack-offset
 8981     8b/-> *Curr-local-stack-offset 0/r32/eax
 8982     89/<- *(ecx+0x14) 0/r32/eax  # Var-offset
 8983     # if v is an array, do something special
 8984     {
 8985       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 8986       (is-mu-array? %eax)  # => eax
 8987       3d/compare-eax-and 0/imm32/false
 8988       0f 84/jump-if-= break/disp32
 8989       # var array-size-without-size/edx: int = n-4
 8990       81 5/subop/subtract %edx 4/imm32
 8991       (emit-indent *(ebp+8) *Curr-block-depth)
 8992       (write-buffered *(ebp+8) "(push-n-zero-bytes ")
 8993       (print-int32-buffered *(ebp+8) %edx)
 8994       (write-buffered *(ebp+8) ")\n")
 8995       (emit-indent *(ebp+8) *Curr-block-depth)
 8996       (write-buffered *(ebp+8) "68/push ")
 8997       (print-int32-buffered *(ebp+8) %edx)
 8998       (write-buffered *(ebp+8) "/imm32\n")
 8999       eb/jump $emit-subx-var-def:end/disp8
 9000     }
 9001     # while n > 0
 9002     {
 9003       81 7/subop/compare %edx 0/imm32
 9004       7e/jump-if-<= break/disp8
 9005       (emit-indent *(ebp+8) *Curr-block-depth)
 9006       (write-buffered *(ebp+8) "68/push 0/imm32\n")
 9007       # n -= 4
 9008       81 5/subop/subtract %edx 4/imm32
 9009       #
 9010       eb/jump loop/disp8
 9011     }
 9012 $emit-subx-var-def:end:
 9013     # . restore registers
 9014     5a/pop-to-edx
 9015     59/pop-to-ecx
 9016     58/pop-to-eax
 9017     # . epilogue
 9018     89/<- %esp 5/r32/ebp
 9019     5d/pop-to-ebp
 9020     c3/return
 9021 
 9022 emit-subx-stmt:  # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive)
 9023     # . prologue
 9024     55/push-ebp
 9025     89/<- %ebp 4/r32/esp
 9026     # . save registers
 9027     50/push-eax
 9028     51/push-ecx
 9029     # - some special-case primitives that don't actually use the 'primitives' data structure
 9030     # var op/ecx: (addr array byte) = lookup(stmt->operation)
 9031     8b/-> *(ebp+0xc) 1/r32/ecx
 9032     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
 9033     89/<- %ecx 0/r32/eax
 9034     # array size
 9035     {
 9036       # if (!string-equal?(stmt->operation, "length")) break
 9037       (string-equal? %ecx "length")  # => eax
 9038       3d/compare-eax-and 0/imm32
 9039       0f 84/jump-if-= break/disp32
 9040       (translate-mu-length-stmt *(ebp+8) *(ebp+0xc))
 9041       e9/jump $emit-subx-stmt:end/disp32
 9042     }
 9043     # index into array
 9044     {
 9045       # if (!string-equal?(stmt->operation, "index")) break
 9046       (string-equal? %ecx "index")  # => eax
 9047       3d/compare-eax-and 0/imm32
 9048       0f 84/jump-if-= break/disp32
 9049       (translate-mu-index-stmt *(ebp+8) *(ebp+0xc))
 9050       e9/jump $emit-subx-stmt:end/disp32
 9051     }
 9052     # compute-offset for index into array
 9053     {
 9054       # if (!string-equal?(stmt->operation, "compute-offset")) break
 9055       (string-equal? %ecx "compute-offset")  # => eax
 9056       3d/compare-eax-and 0/imm32
 9057       0f 84/jump-if-= break/disp32
 9058       (translate-mu-compute-index-stmt *(ebp+8) *(ebp+0xc))
 9059       e9/jump $emit-subx-stmt:end/disp32
 9060     }
 9061     # get field from record
 9062     {
 9063       # if (!string-equal?(stmt->operation, "get")) break
 9064       (string-equal? %ecx "get")  # => eax
 9065       3d/compare-eax-and 0/imm32
 9066       0f 84/jump-if-= break/disp32
 9067       (translate-mu-get-stmt *(ebp+8) *(ebp+0xc))
 9068       e9/jump $emit-subx-stmt:end/disp32
 9069     }
 9070     # - if stmt matches a primitive, emit it
 9071     {
 9072 $emit-subx-stmt:check-for-primitive:
 9073       # var curr/eax: (addr primitive)
 9074       (find-matching-primitive *(ebp+0x10) *(ebp+0xc))  # primitives, stmt => eax
 9075       3d/compare-eax-and 0/imm32
 9076       74/jump-if-= break/disp8
 9077 $emit-subx-stmt:primitive:
 9078       (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax)  # out, stmt, curr
 9079       e9/jump $emit-subx-stmt:end/disp32
 9080     }
 9081     # - otherwise emit a call
 9082     # TODO: type-checking
 9083 $emit-subx-stmt:call:
 9084     (emit-call *(ebp+8) *(ebp+0xc))
 9085 $emit-subx-stmt:end:
 9086     # . restore registers
 9087     59/pop-to-ecx
 9088     58/pop-to-eax
 9089     # . epilogue
 9090     89/<- %esp 5/r32/ebp
 9091     5d/pop-to-ebp
 9092     c3/return
 9093 
 9094 translate-mu-length-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
 9095     # . prologue
 9096     55/push-ebp
 9097     89/<- %ebp 4/r32/esp
 9098     # . save registers
 9099     50/push-eax
 9100     51/push-ecx
 9101     52/push-edx
 9102     53/push-ebx
 9103     56/push-esi
 9104     # esi = stmt
 9105     8b/-> *(ebp+0xc) 6/r32/esi
 9106     # var base/ebx: (addr var) = stmt->inouts[0]->value
 9107     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9108     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9109     89/<- %ebx 0/r32/eax
 9110     # var elemsize/ecx: int = element-size(base)
 9111     (array-element-type-id %ebx)  # => eax
 9112     (size-of-type-id %eax)  # => eax
 9113     89/<- %ecx 0/r32/eax
 9114     # var outreg/edx: (addr array byte) = stmt->outputs[0]->value->register
 9115     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
 9116     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9117     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 9118     89/<- %edx 0/r32/eax
 9119     # if elemsize == 1
 9120     {
 9121       81 7/subop/compare %ecx 1/imm32
 9122       75/jump-if-!= break/disp8
 9123       (emit-save-size-to *(ebp+8) %ebx %edx)
 9124       e9/jump $translate-mu-length-stmt:end/disp32
 9125     }
 9126     # if elemsize is a power of 2 less than 256
 9127     {
 9128       (power-of-2? %ecx)  # => eax
 9129       3d/compare-eax-and 0/imm32/false
 9130       74/jump-if-= break/disp8
 9131       81 7/subop/compare %ecx 0xff/imm32
 9132       7f/jump-if-> break/disp8
 9133       (emit-save-size-to *(ebp+8) %ebx %edx)
 9134       (emit-divide-by-shift-right *(ebp+8) %edx %ecx)
 9135       e9/jump $translate-mu-length-stmt:end/disp32
 9136     }
 9137     # otherwise, the complex case
 9138     # . emit register spills
 9139     {
 9140       (string-equal? %edx "eax")  # => eax
 9141       3d/compare-eax-and 0/imm32/false
 9142       75/break-if-!= break/disp8
 9143       (emit-indent *(ebp+8) *Curr-block-depth)
 9144       (write-buffered *(ebp+8) "50/push-eax\n")
 9145     }
 9146     {
 9147       (string-equal? %edx "ecx")  # => eax
 9148       3d/compare-eax-and 0/imm32/false
 9149       75/break-if-!= break/disp8
 9150       (emit-indent *(ebp+8) *Curr-block-depth)
 9151       (write-buffered *(ebp+8) "51/push-ecx\n")
 9152     }
 9153     {
 9154       (string-equal? %edx "edx")  # => eax
 9155       3d/compare-eax-and 0/imm32/false
 9156       75/break-if-!= break/disp8
 9157       (emit-indent *(ebp+8) *Curr-block-depth)
 9158       (write-buffered *(ebp+8) "52/push-edx\n")
 9159     }
 9160     # .
 9161     (emit-save-size-to *(ebp+8) %ebx "eax")
 9162     (emit-indent *(ebp+8) *Curr-block-depth)
 9163     (write-buffered *(ebp+8) "31/xor %edx 2/r32/edx\n")
 9164     (emit-indent *(ebp+8) *Curr-block-depth)
 9165     (write-buffered *(ebp+8) "b9/copy-to-ecx ")
 9166     (print-int32-buffered *(ebp+8) %ecx)
 9167     (write-buffered *(ebp+8) "/imm32\n")
 9168     (emit-indent *(ebp+8) *Curr-block-depth)
 9169     (write-buffered *(ebp+8) "f7 7/subop/idiv-eax-edx-by %ecx\n")
 9170     {
 9171       (string-equal? %edx "eax")  # => eax
 9172       3d/compare-eax-and 0/imm32/false
 9173       75/break-if-!= break/disp8
 9174       (emit-indent *(ebp+8) *Curr-block-depth)
 9175       (write-buffered *(ebp+8) "89/<- %")
 9176       (write-buffered *(ebp+8) %edx)
 9177       (write-buffered *(ebp+8) " 0/r32/eax\n")
 9178     }
 9179     # . emit register restores
 9180     {
 9181       (string-equal? %edx "edx")  # => eax
 9182       3d/compare-eax-and 0/imm32/false
 9183       75/break-if-!= break/disp8
 9184       (emit-indent *(ebp+8) *Curr-block-depth)
 9185       (write-buffered *(ebp+8) "5a/pop-to-edx\n")
 9186     }
 9187     {
 9188       (string-equal? %edx "ecx")  # => eax
 9189       3d/compare-eax-and 0/imm32/false
 9190       75/break-if-!= break/disp8
 9191       (emit-indent *(ebp+8) *Curr-block-depth)
 9192       (write-buffered *(ebp+8) "59/pop-to-ecx\n")
 9193     }
 9194     {
 9195       (string-equal? %edx "eax")  # => eax
 9196       3d/compare-eax-and 0/imm32/false
 9197       75/break-if-!= break/disp8
 9198       (emit-indent *(ebp+8) *Curr-block-depth)
 9199       (write-buffered *(ebp+8) "58/pop-to-eax\n")
 9200     }
 9201 $translate-mu-length-stmt:end:
 9202     # . restore registers
 9203     5e/pop-to-esi
 9204     5b/pop-to-ebx
 9205     5a/pop-to-edx
 9206     59/pop-to-ecx
 9207     58/pop-to-eax
 9208     # . epilogue
 9209     89/<- %esp 5/r32/ebp
 9210     5d/pop-to-ebp
 9211     c3/return
 9212 
 9213 emit-save-size-to:  # out: (addr buffered-file), base: (addr var), outreg: (addr array byte)
 9214     # . prologue
 9215     55/push-ebp
 9216     89/<- %ebp 4/r32/esp
 9217     # . save registers
 9218     50/push-eax
 9219     53/push-ebx
 9220     # ebx = base
 9221     8b/-> *(ebp+0xc) 3/r32/ebx
 9222     (emit-indent *(ebp+8) *Curr-block-depth)
 9223     (write-buffered *(ebp+8) "8b/-> *")
 9224     # if base is an (addr array ...) in a register
 9225     {
 9226       81 7/subop/compare *(ebx+0x18)) 0/imm32  # Var-register
 9227       74/jump-if-= break/disp8
 9228 $emit-save-size-to:emit-base-from-register:
 9229       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 9230       (write-buffered *(ebp+8) %eax)
 9231       eb/jump $emit-save-size-to:emit-output/disp8
 9232     }
 9233     # otherwise if base is an (array ...) on the stack
 9234     {
 9235       81 7/subop/compare *(ebx+0x14)) 0/imm32  # Var-offset
 9236       74/jump-if-= break/disp8
 9237 $emit-save-size-to:emit-base-from-stack:
 9238       (write-buffered *(ebp+8) "(ebp+")
 9239       (print-int32-buffered *(ebp+8) *(ebx+0x14))  # Var-offset
 9240       (write-buffered *(ebp+8) ")")
 9241     }
 9242 $emit-save-size-to:emit-output:
 9243     (write-buffered *(ebp+8) " ")
 9244     (get Registers *(ebp+0x10) 0xc "Registers")  # => eax
 9245     (print-int32-buffered *(ebp+8) *eax)
 9246     (write-buffered *(ebp+8) "/r32\n")
 9247 $emit-save-size-to:end:
 9248     # . restore registers
 9249     5b/pop-to-ebx
 9250     58/pop-to-eax
 9251     # . epilogue
 9252     89/<- %esp 5/r32/ebp
 9253     5d/pop-to-ebp
 9254     c3/return
 9255 
 9256 emit-divide-by-shift-right:  # out: (addr buffered-file), reg: (addr array byte), size: int
 9257     # . prologue
 9258     55/push-ebp
 9259     89/<- %ebp 4/r32/esp
 9260     # . save registers
 9261     50/push-eax
 9262     #
 9263     (emit-indent *(ebp+8) *Curr-block-depth)
 9264     (write-buffered *(ebp+8) "c1/shift 5/subop/>> %")
 9265     (write-buffered *(ebp+8) *(ebp+0xc))
 9266     (write-buffered *(ebp+8) Space)
 9267     (num-shift-rights *(ebp+0x10))  # => eax
 9268     (print-int32-buffered *(ebp+8) %eax)
 9269     (write-buffered *(ebp+8) "/imm8\n")
 9270 $emit-divide-by-shift-right:end:
 9271     # . restore registers
 9272     58/pop-to-eax
 9273     # . epilogue
 9274     89/<- %esp 5/r32/ebp
 9275     5d/pop-to-ebp
 9276     c3/return
 9277 
 9278 translate-mu-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
 9279     # . prologue
 9280     55/push-ebp
 9281     89/<- %ebp 4/r32/esp
 9282     # . save registers
 9283     51/push-ecx
 9284     # ecx = stmt
 9285     8b/-> *(ebp+0xc) 1/r32/ecx
 9286     # var base/ecx: (addr var) = stmt->inouts[0]
 9287     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9288     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9289     89/<- %ecx 0/r32/eax
 9290     # if (var->register) do one thing
 9291     {
 9292       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
 9293       74/jump-if-= break/disp8
 9294       # TODO: ensure there's no dereference
 9295       (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc))
 9296       eb/jump $translate-mu-index-stmt:end/disp8
 9297     }
 9298     # if (var->offset) do a different thing
 9299     {
 9300       81 7/subop/compare *(ecx+0x14) 0/imm32  # Var-offset
 9301       74/jump-if-= break/disp8
 9302       # TODO: ensure there's no dereference
 9303       (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc))
 9304       eb/jump $translate-mu-index-stmt:end/disp8
 9305     }
 9306 $translate-mu-index-stmt:end:
 9307     # . restore registers
 9308     59/pop-to-ecx
 9309     # . epilogue
 9310     89/<- %esp 5/r32/ebp
 9311     5d/pop-to-ebp
 9312     c3/return
 9313 
 9314 $translate-mu-index-stmt-with-array:error1:
 9315     (write-buffered Stderr "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
 9316     (flush Stderr)
 9317     # . syscall(exit, 1)
 9318     bb/copy-to-ebx  1/imm32
 9319     b8/copy-to-eax  1/imm32/exit
 9320     cd/syscall  0x80/imm8
 9321     # never gets here
 9322 
 9323 $translate-mu-index-stmt-with-array:error2:
 9324     (write-buffered Stderr "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
 9325     (flush Stderr)
 9326     # . syscall(exit, 1)
 9327     bb/copy-to-ebx  1/imm32
 9328     b8/copy-to-eax  1/imm32/exit
 9329     cd/syscall  0x80/imm8
 9330     # never gets here
 9331 
 9332 translate-mu-index-stmt-with-array-in-register:  # out: (addr buffered-file), stmt: (addr stmt)
 9333     # . prologue
 9334     55/push-ebp
 9335     89/<- %ebp 4/r32/esp
 9336     # . save registers
 9337     50/push-eax
 9338     51/push-ecx
 9339     52/push-edx
 9340     53/push-ebx
 9341     #
 9342     (emit-indent *(ebp+8) *Curr-block-depth)
 9343     (write-buffered *(ebp+8) "8d/copy-address *(")
 9344     # TODO: ensure inouts[0] is in a register and not dereferenced
 9345 $translate-mu-index-stmt-with-array-in-register:emit-base:
 9346     # ecx = stmt
 9347     8b/-> *(ebp+0xc) 1/r32/ecx
 9348     # var base/ebx: (addr var) = inouts[0]
 9349     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9350     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9351     89/<- %ebx 0/r32/eax
 9352     # print base->register " + "
 9353     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 9354     (write-buffered *(ebp+8) %eax)
 9355     (write-buffered *(ebp+8) " + ")
 9356     # var index/edx: (addr var) = inouts[1]
 9357     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9358     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
 9359     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9360     89/<- %edx 0/r32/eax
 9361     # if index->register
 9362     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
 9363     {
 9364       0f 84/jump-if-= break/disp32
 9365 $translate-mu-index-stmt-with-array-in-register:emit-register-index:
 9366       # if index is an int
 9367       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9368       (is-simple-mu-type? %eax 1)  # int => eax
 9369       3d/compare-eax-and 0/imm32/false
 9370       {
 9371         0f 84/jump-if-= break/disp32
 9372 $translate-mu-index-stmt-with-array-in-register:emit-int-register-index:
 9373         # print index->register "<<" log2(size-of(element(base->type))) " + 4) "
 9374         # . index->register "<<"
 9375         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 9376         (write-buffered *(ebp+8) %eax)
 9377         (write-buffered *(ebp+8) "<<")
 9378         # . log2(size-of(element(base->type)))
 9379         # TODO: ensure size is a power of 2
 9380         (array-element-type-id %ebx)  # => eax
 9381         (size-of-type-id %eax)  # => eax
 9382         (num-shift-rights %eax)  # => eax
 9383         (print-int32-buffered *(ebp+8) %eax)
 9384         e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32
 9385       }
 9386       # if index->type is any other atom, abort
 9387       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9388       81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
 9389       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
 9390       # if index has type (offset ...)
 9391       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 9392       (is-simple-mu-type? %eax 7)  # => eax
 9393       3d/compare-eax-and 0/imm32/false
 9394       {
 9395         0f 84/jump-if-= break/disp32
 9396         # print index->register
 9397 $translate-mu-index-stmt-with-array-in-register:emit-offset-register-index:
 9398         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 9399         (write-buffered *(ebp+8) %eax)
 9400       }
 9401 $translate-mu-index-stmt-with-array-in-register:emit-register-index-done:
 9402       (write-buffered *(ebp+8) " + 4) ")
 9403       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
 9404     }
 9405     # otherwise if index is a literal
 9406     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9407     (is-simple-mu-type? %eax 0)  # => eax
 9408     3d/compare-eax-and 0/imm32/false
 9409     {
 9410       0f 84/jump-if-= break/disp32
 9411 $translate-mu-index-stmt-with-array-in-register:emit-literal-index:
 9412       # var index-value/edx: int = parse-hex-int(index->name)
 9413       (lookup *edx *(edx+4))  # Var-name Var-name => eax
 9414       (parse-hex-int %eax)  # => eax
 9415       89/<- %edx 0/r32/eax
 9416       # offset = idx-value * size-of(element(base->type))
 9417       (array-element-type-id %ebx)  # => eax
 9418       (size-of-type-id %eax)  # => eax
 9419       f7 4/subop/multiply-into-eax %edx  # clobbers edx
 9420       # offset += 4 for array size
 9421       05/add-to-eax 4/imm32
 9422       # TODO: check edx for overflow
 9423       # print offset
 9424       (print-int32-buffered *(ebp+8) %eax)
 9425       (write-buffered *(ebp+8) ") ")
 9426       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
 9427     }
 9428     # otherwise abort
 9429     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
 9430 $translate-mu-index-stmt-with-array-in-register:emit-output:
 9431     # outputs[0] "/r32"
 9432     8b/-> *(ebp+0xc) 1/r32/ecx
 9433     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
 9434     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9435     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 9436     (get Registers %eax 0xc "Registers")  # => eax: (addr int)
 9437     (print-int32-buffered *(ebp+8) *eax)
 9438     (write-buffered *(ebp+8) "/r32\n")
 9439 $translate-mu-index-stmt-with-array-in-register:end:
 9440     # . restore registers
 9441     5b/pop-to-ebx
 9442     5a/pop-to-edx
 9443     59/pop-to-ecx
 9444     58/pop-to-eax
 9445     # . epilogue
 9446     89/<- %esp 5/r32/ebp
 9447     5d/pop-to-ebp
 9448     c3/return
 9449 
 9450 translate-mu-index-stmt-with-array-on-stack:  # out: (addr buffered-file), stmt: (addr stmt)
 9451     # . prologue
 9452     55/push-ebp
 9453     89/<- %ebp 4/r32/esp
 9454     # . save registers
 9455     50/push-eax
 9456     51/push-ecx
 9457     52/push-edx
 9458     53/push-ebx
 9459     #
 9460     (emit-indent *(ebp+8) *Curr-block-depth)
 9461     (write-buffered *(ebp+8) "8d/copy-address *(ebp + ")
 9462     # var curr/edx: (addr stmt-var) = lookup(stmt->inouts)
 9463     8b/-> *(ebp+0xc) 0/r32/eax
 9464     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9465     89/<- %edx 0/r32/eax
 9466     # var base/ecx: (addr var) = lookup(curr->value)
 9467     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9468     89/<- %ecx 0/r32/eax
 9469     # var curr2/eax: (addr stmt-var) = lookup(curr->next)
 9470     (lookup *(edx+8) *(edx+0xc))  # Stmt-var-next Stmt-var-next => eax
 9471     # var index/edx: (handle var) = curr2->value
 9472     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9473     89/<- %edx 0/r32/eax
 9474     # if index->register
 9475     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
 9476     {
 9477       0f 84/jump-if-= break/disp32
 9478 $translate-mu-index-stmt-with-array-on-stack:emit-register-index:
 9479       # if index is an int
 9480       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9481       (is-simple-mu-type? %eax 1)  # int => eax
 9482       3d/compare-eax-and 0/imm32/false
 9483       {
 9484         0f 84/jump-if-= break/disp32
 9485 $translate-mu-index-stmt-with-array-on-stack:emit-int-register-index:
 9486         # print index->register "<<" log2(size-of(element-type(base))) " + " base->offset+4
 9487         # . inouts[1]->register "<<"
 9488         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 9489         (write-buffered *(ebp+8) %eax)
 9490         (write-buffered *(ebp+8) "<<")
 9491         # . log2(size-of(element(base)))
 9492         # TODO: ensure size is a power of 2
 9493         (array-element-type-id %ecx)  # => eax
 9494         (size-of-type-id %eax)  # => eax
 9495         (num-shift-rights %eax)  # => eax
 9496         (print-int32-buffered *(ebp+8) %eax)
 9497         #
 9498         (write-buffered *(ebp+8) " + ")
 9499         #
 9500         8b/-> *(ecx+0x14) 0/r32/eax  # Var-offset
 9501         05/add-to-eax 4/imm32  # for array length
 9502         (print-int32-buffered *(ebp+8) %eax)
 9503         e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32
 9504       }
 9505       # if index->type is any other atom, abort
 9506       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9507       81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
 9508       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
 9509       # if index has type (offset ...)
 9510       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 9511       (is-simple-mu-type? %eax 7)  # => eax
 9512       3d/compare-eax-and 0/imm32/false
 9513       {
 9514         0f 84/jump-if-= break/disp32
 9515         # print index->register
 9516 $translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index:
 9517         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 9518         (write-buffered *(ebp+8) %eax)
 9519       }
 9520 $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done:
 9521       (write-buffered *(ebp+8) ") ")
 9522       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
 9523     }
 9524     # otherwise if index is a literal
 9525     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9526     (is-simple-mu-type? %eax 0)  # => eax
 9527     3d/compare-eax-and 0/imm32/false
 9528     {
 9529       0f 84/jump-if-= break/disp32
 9530 $translate-mu-index-stmt-with-array-on-stack:emit-literal-index:
 9531       # var idx-value/edx: int = parse-hex-int(index->name)
 9532       (lookup *edx *(edx+4))  # Var-name Var-name => eax
 9533       (parse-hex-int %eax)  # Var-name => eax
 9534       89/<- %edx 0/r32/eax
 9535       # offset = idx-value * size-of(element-type(base->type))
 9536       (array-element-type-id %ecx)  # => eax
 9537       (size-of-type-id %eax)  # => eax
 9538       f7 4/subop/multiply-into-eax %edx  # clobbers edx
 9539       # offset += base->offset
 9540       03/add *(ecx+0x14) 0/r32/eax  # Var-offset
 9541       # offset += 4 for array size
 9542       05/add-to-eax 4/imm32
 9543       # TODO: check edx for overflow
 9544       # print offset
 9545       (print-int32-buffered *(ebp+8) %eax)
 9546       (write-buffered *(ebp+8) ") ")
 9547       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
 9548     }
 9549     # otherwise abort
 9550     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
 9551 $translate-mu-index-stmt-with-array-on-stack:emit-output:
 9552     # outputs[0] "/r32"
 9553     8b/-> *(ebp+0xc) 0/r32/eax
 9554     (lookup *(eax+0x14) *(eax+0x18))  # Stmt1-outputs Stmt1-outputs => eax
 9555     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9556     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 9557     (get Registers %eax 0xc "Registers")  # => eax: (addr int)
 9558     (print-int32-buffered *(ebp+8) *eax)
 9559     (write-buffered *(ebp+8) "/r32\n")
 9560 $translate-mu-index-stmt-with-array-on-stack:end:
 9561     # . restore registers
 9562     5b/pop-to-ebx
 9563     5a/pop-to-edx
 9564     59/pop-to-ecx
 9565     58/pop-to-eax
 9566     # . epilogue
 9567     89/<- %esp 5/r32/ebp
 9568     5d/pop-to-ebp
 9569     c3/return
 9570 
 9571 translate-mu-compute-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
 9572     # . prologue
 9573     55/push-ebp
 9574     89/<- %ebp 4/r32/esp
 9575     # . save registers
 9576     50/push-eax
 9577     51/push-ecx
 9578     52/push-edx
 9579     53/push-ebx
 9580     #
 9581     (emit-indent *(ebp+8) *Curr-block-depth)
 9582     (write-buffered *(ebp+8) "69/multiply")
 9583     # ecx = stmt
 9584     8b/-> *(ebp+0xc) 1/r32/ecx
 9585     # var first-inout/ebx: (addr stmt-var) = stmt->inouts[0]
 9586     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9587     89/<- %ebx 0/r32/eax
 9588 $translate-mu-compute-index-stmt:emit-index:
 9589     (lookup *(ebx+8) *(ebx+0xc))  # Stmt-var-next Stmt-var-next => eax
 9590     (emit-subx-var-as-rm32 *(ebp+8) %eax)
 9591     (write-buffered *(ebp+8) Space)
 9592 $translate-mu-compute-index-stmt:emit-elem-size:
 9593     # var base/ebx: (addr var)
 9594     (lookup *ebx *(ebx+4))  # Stmt-var-value Stmt-var-value => eax
 9595     89/<- %ebx 0/r32/eax
 9596     # print size-of(element(base->type))
 9597     (array-element-type-id %ebx)  # => eax
 9598     (size-of-type-id %eax)  # => eax
 9599     (print-int32-buffered *(ebp+8) %eax)
 9600     (write-buffered *(ebp+8) "/imm32 ")
 9601 $translate-mu-compute-index-stmt:emit-output:
 9602     # outputs[0] "/r32"
 9603     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
 9604     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9605     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 9606     (get Registers %eax 0xc "Registers")  # => eax: (addr int)
 9607     (print-int32-buffered *(ebp+8) *eax)
 9608     (write-buffered *(ebp+8) "/r32\n")
 9609 $translate-mu-compute-index-stmt:end:
 9610     # . restore registers
 9611     5b/pop-to-ebx
 9612     5a/pop-to-edx
 9613     59/pop-to-ecx
 9614     58/pop-to-eax
 9615     # . epilogue
 9616     89/<- %esp 5/r32/ebp
 9617     5d/pop-to-ebp
 9618     c3/return
 9619 
 9620 translate-mu-get-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
 9621     # . prologue
 9622     55/push-ebp
 9623     89/<- %ebp 4/r32/esp
 9624     # . save registers
 9625     50/push-eax
 9626     51/push-ecx
 9627     52/push-edx
 9628     #
 9629     (emit-indent *(ebp+8) *Curr-block-depth)
 9630     (write-buffered *(ebp+8) "8d/copy-address ")
 9631     # ecx = stmt
 9632     8b/-> *(ebp+0xc) 1/r32/ecx
 9633     # var offset/edx: int = get offset of stmt
 9634     (mu-get-offset %ecx)  # => eax
 9635     89/<- %edx 0/r32/eax
 9636     # var base/eax: (addr var) = stmt->inouts->value
 9637     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9638     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9639     # if base is in a register
 9640     81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 9641     {
 9642       0f 84/jump-if-= break/disp32
 9643 $translate-mu-get-stmt:emit-register-input:
 9644       # emit "*(" base->register " + " offset ") "
 9645       (write-buffered *(ebp+8) "*(")
 9646       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 9647       (write-buffered *(ebp+8) %eax)
 9648       (write-buffered *(ebp+8) " + ")
 9649       (print-int32-buffered *(ebp+8) %edx)
 9650       (write-buffered *(ebp+8) ") ")
 9651       e9/jump $translate-mu-get-stmt:emit-output/disp32
 9652     }
 9653     # otherwise base is on the stack
 9654     {
 9655 $translate-mu-get-stmt:emit-stack-input:
 9656       # emit "*(ebp + " inouts[0]->stack-offset + offset ") "
 9657       (write-buffered *(ebp+8) "*(ebp+")
 9658       03/add *(eax+0x14) 2/r32/edx  # Var-offset
 9659       (print-int32-buffered *(ebp+8) %edx)
 9660       (write-buffered *(ebp+8) ") ")
 9661       eb/jump $translate-mu-get-stmt:emit-output/disp8
 9662     }
 9663 $translate-mu-get-stmt:emit-output:
 9664     # var output/eax: (addr var) = stmt->outputs->value
 9665     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
 9666     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9667     # emit offset->register "/r32"
 9668     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 9669     (get Registers %eax 0xc "Registers")  # => eax: (addr int)
 9670     (print-int32-buffered *(ebp+8) *eax)
 9671     (write-buffered *(ebp+8) "/r32\n")
 9672 $translate-mu-get-stmt:end:
 9673     # . restore registers
 9674     5a/pop-to-edx
 9675     59/pop-to-ecx
 9676     58/pop-to-eax
 9677     # . epilogue
 9678     89/<- %esp 5/r32/ebp
 9679     5d/pop-to-ebp
 9680     c3/return
 9681 
 9682 array-element-type-id:  # v: (addr var) -> result/eax: type-id
 9683     # precondition: n is positive
 9684     # . prologue
 9685     55/push-ebp
 9686     89/<- %ebp 4/r32/esp
 9687     #
 9688     8b/-> *(ebp+8) 0/r32/eax
 9689     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
 9690     # TODO: ensure type->left is 'addr'
 9691     (lookup *(eax+0xc) *(eax+0x10))  # Tree-right Tree-right => eax
 9692     # TODO: ensure that type->right is non-null
 9693     # TODO: ensure that type->right->left is 'array'
 9694     (lookup *(eax+0xc) *(eax+0x10))  # Tree-right Tree-right => eax
 9695     # TODO: ensure that type->right->right is non-null
 9696     (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 9697     8b/-> *(eax+4) 0/r32/eax  # Tree-value
 9698 $array-element-type-id:end:
 9699     # . epilogue
 9700     89/<- %esp 5/r32/ebp
 9701     5d/pop-to-ebp
 9702     c3/return
 9703 
 9704 power-of-2?:  # n: int -> result/eax: boolean
 9705     # precondition: n is positive
 9706     # . prologue
 9707     55/push-ebp
 9708     89/<- %ebp 4/r32/esp
 9709     # eax = n
 9710     8b/-> *(ebp+8) 0/r32/eax
 9711     # if (n < 0) abort
 9712     3d/compare-eax-with 0/imm32
 9713     0f 8c/jump-if-< $power-of-2?:abort/disp32
 9714     # var tmp/eax: int = n-1
 9715     48/decrement-eax
 9716     # var tmp2/eax: int = n & tmp
 9717     23/and-> *(ebp+8) 0/r32/eax
 9718     # return (tmp2 == 0)
 9719     3d/compare-eax-and 0/imm32
 9720     0f 94/set-byte-if-= %al
 9721     81 4/subop/and %eax 0xff/imm32
 9722 $power-of-2?:end:
 9723     # . epilogue
 9724     89/<- %esp 5/r32/ebp
 9725     5d/pop-to-ebp
 9726     c3/return
 9727 
 9728 $power-of-2?:abort:
 9729     (write-buffered Stderr "power-of-2?: negative number\n")
 9730     (flush Stderr)
 9731     # . syscall(exit, 1)
 9732     bb/copy-to-ebx  1/imm32
 9733     b8/copy-to-eax  1/imm32/exit
 9734     cd/syscall  0x80/imm8
 9735     # never gets here
 9736 
 9737 num-shift-rights:  # n: int -> result/eax: int
 9738     # precondition: n is a positive power of 2
 9739     # . prologue
 9740     55/push-ebp
 9741     89/<- %ebp 4/r32/esp
 9742     # . save registers
 9743     51/push-ecx
 9744     # var curr/ecx: int = n
 9745     8b/-> *(ebp+8) 1/r32/ecx
 9746     # result = 0
 9747     b8/copy-to-eax 0/imm32
 9748     {
 9749       # if (curr <= 1) break
 9750       81 7/subop/compare %ecx 1/imm32
 9751       7e/jump-if-<= break/disp8
 9752       40/increment-eax
 9753       c1/shift 5/subop/arithmetic-right %ecx 1/imm8
 9754       eb/jump loop/disp8
 9755     }
 9756 $num-shift-rights:end:
 9757     # . restore registers
 9758     59/pop-to-ecx
 9759     # . epilogue
 9760     89/<- %esp 5/r32/ebp
 9761     5d/pop-to-ebp
 9762     c3/return
 9763 
 9764 mu-get-offset:  # stmt: (addr stmt) -> result/eax: int
 9765     # . prologue
 9766     55/push-ebp
 9767     89/<- %ebp 4/r32/esp
 9768     # var second-inout/eax: (addr stmt-var) = stmt->inouts->next
 9769     8b/-> *(ebp+8) 0/r32/eax
 9770     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9771     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
 9772     # var output-var/eax: (addr var) = second-inout->value
 9773     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9774 #?     (write-buffered Stderr "mu-get-offset: ")
 9775 #?     (print-int32-buffered Stderr %eax)
 9776 #?     (write-buffered Stderr " name: ")
 9777 #?     50/push-eax
 9778 #?     (lookup *eax *(eax+4))  # Var-name
 9779 #?     (write-buffered Stderr %eax)
 9780 #?     58/pop-to-eax
 9781 #?     (write-buffered Stderr Newline)
 9782 #?     (flush Stderr)
 9783     # return output-var->stack-offset
 9784     8b/-> *(eax+0x14) 0/r32/eax  # Var-offset
 9785 #?     (write-buffered Stderr "=> ")
 9786 #?     (print-int32-buffered Stderr %eax)
 9787 #?     (write-buffered Stderr Newline)
 9788 #?     (flush Stderr)
 9789 $emit-get-offset:end:
 9790     # . epilogue
 9791     89/<- %esp 5/r32/ebp
 9792     5d/pop-to-ebp
 9793     c3/return
 9794 
 9795 emit-subx-block:  # out: (addr buffered-file), block: (addr block), vars: (addr stack (handle var))
 9796     # . prologue
 9797     55/push-ebp
 9798     89/<- %ebp 4/r32/esp
 9799     # . save registers
 9800     50/push-eax
 9801     51/push-ecx
 9802     56/push-esi
 9803     # esi = block
 9804     8b/-> *(ebp+0xc) 6/r32/esi
 9805     # block->var->block-depth = *Curr-block-depth
 9806     (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
 9807     8b/-> *Curr-block-depth 1/r32/ecx
 9808     89/<- *(eax+0x10) 1/r32/ecx  # Var-block-depth
 9809     # var stmts/eax: (addr list stmt) = lookup(block->statements)
 9810     (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
 9811     #
 9812     {
 9813 $emit-subx-block:check-empty:
 9814       3d/compare-eax-and 0/imm32
 9815       0f 84/jump-if-= break/disp32
 9816       (emit-indent *(ebp+8) *Curr-block-depth)
 9817       (write-buffered *(ebp+8) "{\n")
 9818       # var v/ecx: (addr var) = lookup(block->var)
 9819       (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
 9820       89/<- %ecx 0/r32/eax
 9821       #
 9822       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 9823       (write-buffered *(ebp+8) %eax)
 9824       (write-buffered *(ebp+8) ":loop:\n")
 9825       ff 0/subop/increment *Curr-block-depth
 9826       (push *(ebp+0x10) *(esi+0xc))  # Block-var
 9827       (push *(ebp+0x10) *(esi+0x10))  # Block-var
 9828       # emit block->statements
 9829       (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
 9830       (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10))
 9831       (pop *(ebp+0x10))  # => eax
 9832       (pop *(ebp+0x10))  # => eax
 9833       ff 1/subop/decrement *Curr-block-depth
 9834       (emit-indent *(ebp+8) *Curr-block-depth)
 9835       (write-buffered *(ebp+8) "}\n")
 9836       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 9837       (write-buffered *(ebp+8) %eax)
 9838       (write-buffered *(ebp+8) ":break:\n")
 9839     }
 9840 $emit-subx-block:end:
 9841     # . restore registers
 9842     5e/pop-to-esi
 9843     59/pop-to-ecx
 9844     58/pop-to-eax
 9845     # . epilogue
 9846     89/<- %esp 5/r32/ebp
 9847     5d/pop-to-ebp
 9848     c3/return
 9849 
 9850 # Primitives supported
 9851 # See mu_instructions for a summary of this linked-list data structure.
 9852 #
 9853 # For each operation, put variants with hard-coded registers before flexible ones.
 9854 #
 9855 # Unfortunately, our restrictions on addresses require that various fields in
 9856 # primitives be handles, which complicates these definitions.
 9857 #   - we need to insert dummy fields all over the place for fake alloc-ids
 9858 #   - we can't use our syntax sugar of quoted literals for string fields
 9859 #
 9860 # Fake alloc-ids are needed because our type definitions up top require
 9861 # handles but it's clearer to statically allocate these long-lived objects.
 9862 # Fake alloc-ids are perfectly safe, but they can't be reclaimed.
 9863 #
 9864 # Every 'object' below starts with a fake alloc-id. It may also contain other
 9865 # fake alloc-ids for various handle fields.
 9866 #
 9867 # I think of objects starting with a fake alloc-id as having type 'payload'.
 9868 # It's not really intended to be created dynamically; for that use `allocate`
 9869 # as usual.
 9870 #
 9871 # Idea for a notation to simplify such definitions:
 9872 #   _Primitive-increment-eax:  # (payload primitive)
 9873 #     0x11/alloc-id:fake:payload
 9874 #     0x11 @(0x11 "increment")  # name
 9875 #     0 0                       # inouts
 9876 #     0x11 @(0x11/payload
 9877 #            0x11 @(0x11/payload  # List-value
 9878 #                   0 0             # Var-name
 9879 #                   0x11 @(0x11     # Var-type
 9880 #                          1/is-atom
 9881 #                          1/value 0/unused   # Tree-left
 9882 #                          0 0                # Tree-right
 9883 #                         )
 9884 #                   1               # block-depth
 9885 #                   0               # stack-offset
 9886 #                   0x11 @(0x11 "eax")  # Var-register
 9887 #                  )
 9888 #            0 0)                 # List-next
 9889 #     ...
 9890 #     _Primitive-increment-ecx/imm32/next
 9891 #   ...
 9892 # Awfully complex and non-obvious. But also clearly signals there's something
 9893 # to learn here, so may be worth trying.
 9894 #
 9895 # '@' is just an initial thought. Punctuation used so far in Mu: () * % # / "
 9896 #
 9897 # For now we'll continue to just use comments and manually ensure they stay up
 9898 # to date.
 9899 == data
 9900 Primitives:  # (addr primitive)
 9901 # - increment/decrement
 9902 _Primitive-increment-eax:  # (addr primitive)
 9903     # var/eax <- increment => 40/increment-eax
 9904     0x11/imm32/alloc-id:fake
 9905     _string-increment/imm32/name
 9906     0/imm32/no-inouts
 9907     0/imm32/no-inouts
 9908     0x11/imm32/alloc-id:fake
 9909     Single-int-var-in-eax/imm32/outputs
 9910     0x11/imm32/alloc-id:fake
 9911     _string_40_increment_eax/imm32/subx-name
 9912     0/imm32/no-rm32
 9913     0/imm32/no-r32
 9914     0/imm32/no-imm32
 9915     0/imm32/no-disp32
 9916     0/imm32/output-is-write-only
 9917     0x11/imm32/alloc-id:fake
 9918     _Primitive-increment-ecx/imm32/next
 9919 _Primitive-increment-ecx:  # (payload primitive)
 9920     0x11/imm32/alloc-id:fake:payload
 9921     # var/ecx <- increment => 41/increment-ecx
 9922     0x11/imm32/alloc-id:fake
 9923     _string-increment/imm32/name
 9924     0/imm32/no-inouts
 9925     0/imm32/no-inouts
 9926     0x11/imm32/alloc-id:fake
 9927     Single-int-var-in-ecx/imm32/outputs
 9928     0x11/imm32/alloc-id:fake
 9929     _string_41_increment_ecx/imm32/subx-name
 9930     0/imm32/no-rm32
 9931     0/imm32/no-r32
 9932     0/imm32/no-imm32
 9933     0/imm32/no-disp32
 9934     0/imm32/output-is-write-only
 9935     0x11/imm32/alloc-id:fake
 9936     _Primitive-increment-edx/imm32/next
 9937 _Primitive-increment-edx:  # (payload primitive)
 9938     0x11/imm32/alloc-id:fake:payload
 9939     # var/edx <- increment => 42/increment-edx
 9940     0x11/imm32/alloc-id:fake
 9941     _string-increment/imm32/name
 9942     0/imm32/no-inouts
 9943     0/imm32/no-inouts
 9944     0x11/imm32/alloc-id:fake
 9945     Single-int-var-in-edx/imm32/outputs
 9946     0x11/imm32/alloc-id:fake
 9947     _string_42_increment_edx/imm32/subx-name
 9948     0/imm32/no-rm32
 9949     0/imm32/no-r32
 9950     0/imm32/no-imm32
 9951     0/imm32/no-disp32
 9952     0/imm32/output-is-write-only
 9953     0x11/imm32/alloc-id:fake
 9954     _Primitive-increment-ebx/imm32/next
 9955 _Primitive-increment-ebx:  # (payload primitive)
 9956     0x11/imm32/alloc-id:fake:payload
 9957     # var/ebx <- increment => 43/increment-ebx
 9958     0x11/imm32/alloc-id:fake
 9959     _string-increment/imm32/name
 9960     0/imm32/no-inouts
 9961     0/imm32/no-inouts
 9962     0x11/imm32/alloc-id:fake
 9963     Single-int-var-in-ebx/imm32/outputs
 9964     0x11/imm32/alloc-id:fake
 9965     _string_43_increment_ebx/imm32/subx-name
 9966     0/imm32/no-rm32
 9967     0/imm32/no-r32
 9968     0/imm32/no-imm32
 9969     0/imm32/no-disp32
 9970     0/imm32/output-is-write-only
 9971     0x11/imm32/alloc-id:fake
 9972     _Primitive-increment-esi/imm32/next
 9973 _Primitive-increment-esi:  # (payload primitive)
 9974     0x11/imm32/alloc-id:fake:payload
 9975     # var/esi <- increment => 46/increment-esi
 9976     0x11/imm32/alloc-id:fake
 9977     _string-increment/imm32/name
 9978     0/imm32/no-inouts
 9979     0/imm32/no-inouts
 9980     0x11/imm32/alloc-id:fake
 9981     Single-int-var-in-esi/imm32/outputs
 9982     0x11/imm32/alloc-id:fake
 9983     _string_46_increment_esi/imm32/subx-name
 9984     0/imm32/no-rm32
 9985     0/imm32/no-r32
 9986     0/imm32/no-imm32
 9987     0/imm32/no-disp32
 9988     0/imm32/output-is-write-only
 9989     0x11/imm32/alloc-id:fake
 9990     _Primitive-increment-edi/imm32/next
 9991 _Primitive-increment-edi:  # (payload primitive)
 9992     0x11/imm32/alloc-id:fake:payload
 9993     # var/edi <- increment => 47/increment-edi
 9994     0x11/imm32/alloc-id:fake
 9995     _string-increment/imm32/name
 9996     0/imm32/no-inouts
 9997     0/imm32/no-inouts
 9998     0x11/imm32/alloc-id:fake
 9999     Single-int-var-in-edi/imm32/outputs
10000     0x11/imm32/alloc-id:fake
10001     _string_47_increment_edi/imm32/subx-name
10002     0/imm32/no-rm32
10003     0/imm32/no-r32
10004     0/imm32/no-imm32
10005     0/imm32/no-disp32
10006     0/imm32/output-is-write-only
10007     0x11/imm32/alloc-id:fake
10008     _Primitive-decrement-eax/imm32/next
10009 _Primitive-decrement-eax:  # (payload primitive)
10010     0x11/imm32/alloc-id:fake:payload
10011     # var/eax <- decrement => 48/decrement-eax
10012     0x11/imm32/alloc-id:fake
10013     _string-decrement/imm32/name
10014     0/imm32/no-inouts
10015     0/imm32/no-inouts
10016     0x11/imm32/alloc-id:fake
10017     Single-int-var-in-eax/imm32/outputs
10018     0x11/imm32/alloc-id:fake
10019     _string_48_decrement_eax/imm32/subx-name
10020     0/imm32/no-rm32
10021     0/imm32/no-r32
10022     0/imm32/no-imm32
10023     0/imm32/no-disp32
10024     0/imm32/output-is-write-only
10025     0x11/imm32/alloc-id:fake
10026     _Primitive-decrement-ecx/imm32/next
10027 _Primitive-decrement-ecx:  # (payload primitive)
10028     0x11/imm32/alloc-id:fake:payload
10029     # var/ecx <- decrement => 49/decrement-ecx
10030     0x11/imm32/alloc-id:fake
10031     _string-decrement/imm32/name
10032     0/imm32/no-inouts
10033     0/imm32/no-inouts
10034     0x11/imm32/alloc-id:fake
10035     Single-int-var-in-ecx/imm32/outputs
10036     0x11/imm32/alloc-id:fake
10037     _string_49_decrement_ecx/imm32/subx-name
10038     0/imm32/no-rm32
10039     0/imm32/no-r32
10040     0/imm32/no-imm32
10041     0/imm32/no-disp32
10042     0/imm32/output-is-write-only
10043     0x11/imm32/alloc-id:fake
10044     _Primitive-decrement-edx/imm32/next
10045 _Primitive-decrement-edx:  # (payload primitive)
10046     0x11/imm32/alloc-id:fake:payload
10047     # var/edx <- decrement => 4a/decrement-edx
10048     0x11/imm32/alloc-id:fake
10049     _string-decrement/imm32/name
10050     0/imm32/no-inouts
10051     0/imm32/no-inouts
10052     0x11/imm32/alloc-id:fake
10053     Single-int-var-in-edx/imm32/outputs
10054     0x11/imm32/alloc-id:fake
10055     _string_4a_decrement_edx/imm32/subx-name
10056     0/imm32/no-rm32
10057     0/imm32/no-r32
10058     0/imm32/no-imm32
10059     0/imm32/no-disp32
10060     0/imm32/output-is-write-only
10061     0x11/imm32/alloc-id:fake
10062     _Primitive-decrement-ebx/imm32/next
10063 _Primitive-decrement-ebx:  # (payload primitive)
10064     0x11/imm32/alloc-id:fake:payload
10065     # var/ebx <- decrement => 4b/decrement-ebx
10066     0x11/imm32/alloc-id:fake
10067     _string-decrement/imm32/name
10068     0/imm32/no-inouts
10069     0/imm32/no-inouts
10070     0x11/imm32/alloc-id:fake
10071     Single-int-var-in-ebx/imm32/outputs
10072     0x11/imm32/alloc-id:fake
10073     _string_4b_decrement_ebx/imm32/subx-name
10074     0/imm32/no-rm32
10075     0/imm32/no-r32
10076     0/imm32/no-imm32
10077     0/imm32/no-disp32
10078     0/imm32/output-is-write-only
10079     0x11/imm32/alloc-id:fake
10080     _Primitive-decrement-esi/imm32/next
10081 _Primitive-decrement-esi:  # (payload primitive)
10082     0x11/imm32/alloc-id:fake:payload
10083     # var/esi <- decrement => 4e/decrement-esi
10084     0x11/imm32/alloc-id:fake
10085     _string-decrement/imm32/name
10086     0/imm32/no-inouts
10087     0/imm32/no-inouts
10088     0x11/imm32/alloc-id:fake
10089     Single-int-var-in-esi/imm32/outputs
10090     0x11/imm32/alloc-id:fake
10091     _string_4e_decrement_esi/imm32/subx-name
10092     0/imm32/no-rm32
10093     0/imm32/no-r32
10094     0/imm32/no-imm32
10095     0/imm32/no-disp32
10096     0/imm32/output-is-write-only
10097     0x11/imm32/alloc-id:fake
10098     _Primitive-decrement-edi/imm32/next
10099 _Primitive-decrement-edi:  # (payload primitive)
10100     0x11/imm32/alloc-id:fake:payload
10101     # var/edi <- decrement => 4f/decrement-edi
10102     0x11/imm32/alloc-id:fake
10103     _string-decrement/imm32/name
10104     0/imm32/no-inouts
10105     0/imm32/no-inouts
10106     0x11/imm32/alloc-id:fake
10107     Single-int-var-in-edi/imm32/outputs
10108     0x11/imm32/alloc-id:fake
10109     _string_4f_decrement_edi/imm32/subx-name
10110     0/imm32/no-rm32
10111     0/imm32/no-r32
10112     0/imm32/no-imm32
10113     0/imm32/no-disp32
10114     0/imm32/output-is-write-only
10115     0x11/imm32/alloc-id:fake
10116     _Primitive-increment-mem/imm32/next
10117 _Primitive-increment-mem:  # (payload primitive)
10118     0x11/imm32/alloc-id:fake:payload
10119     # increment var => ff 0/subop/increment *(ebp+__)
10120     0x11/imm32/alloc-id:fake
10121     _string-increment/imm32/name
10122     0x11/imm32/alloc-id:fake
10123     Single-int-var-in-mem/imm32/inouts
10124     0/imm32/no-outputs
10125     0/imm32/no-outputs
10126     0x11/imm32/alloc-id:fake
10127     _string_ff_subop_increment/imm32/subx-name
10128     1/imm32/rm32-is-first-inout
10129     0/imm32/no-r32
10130     0/imm32/no-imm32
10131     0/imm32/no-disp32
10132     0/imm32/output-is-write-only
10133     0x11/imm32/alloc-id:fake
10134     _Primitive-increment-reg/imm32/next
10135 _Primitive-increment-reg:  # (payload primitive)
10136     0x11/imm32/alloc-id:fake:payload
10137     # var/reg <- increment => ff 0/subop/increment %__
10138     0x11/imm32/alloc-id:fake
10139     _string-increment/imm32/name
10140     0/imm32/no-inouts
10141     0/imm32/no-inouts
10142     0x11/imm32/alloc-id:fake
10143     Single-int-var-in-some-register/imm32/outputs
10144     0x11/imm32/alloc-id:fake
10145     _string_ff_subop_increment/imm32/subx-name
10146     3/imm32/rm32-is-first-output
10147     0/imm32/no-r32
10148     0/imm32/no-imm32
10149     0/imm32/no-disp32
10150     0/imm32/output-is-write-only
10151     0x11/imm32/alloc-id:fake
10152     _Primitive-decrement-mem/imm32/next
10153 _Primitive-decrement-mem:  # (payload primitive)
10154     0x11/imm32/alloc-id:fake:payload
10155     # decrement var => ff 1/subop/decrement *(ebp+__)
10156     0x11/imm32/alloc-id:fake
10157     _string-decrement/imm32/name
10158     0x11/imm32/alloc-id:fake
10159     Single-int-var-in-mem/imm32/inouts
10160     0/imm32/no-outputs
10161     0/imm32/no-outputs
10162     0x11/imm32/alloc-id:fake
10163     _string_ff_subop_decrement/imm32/subx-name
10164     1/imm32/rm32-is-first-inout
10165     0/imm32/no-r32
10166     0/imm32/no-imm32
10167     0/imm32/no-disp32
10168     0/imm32/output-is-write-only
10169     0x11/imm32/alloc-id:fake
10170     _Primitive-decrement-reg/imm32/next
10171 _Primitive-decrement-reg:  # (payload primitive)
10172     0x11/imm32/alloc-id:fake:payload
10173     # var/reg <- decrement => ff 1/subop/decrement %__
10174     0x11/imm32/alloc-id:fake
10175     _string-decrement/imm32/name
10176     0/imm32/no-inouts
10177     0/imm32/no-inouts
10178     0x11/imm32/alloc-id:fake
10179     Single-int-var-in-some-register/imm32/outputs
10180     0x11/imm32/alloc-id:fake
10181     _string_ff_subop_decrement/imm32/subx-name
10182     3/imm32/rm32-is-first-output
10183     0/imm32/no-r32
10184     0/imm32/no-imm32
10185     0/imm32/no-disp32
10186     0/imm32/output-is-write-only
10187     0x11/imm32/alloc-id:fake
10188     _Primitive-add-to-eax/imm32/next
10189 # - add
10190 _Primitive-add-to-eax:  # (payload primitive)
10191     0x11/imm32/alloc-id:fake:payload
10192     # var/eax <- add lit => 05/add-to-eax lit/imm32
10193     0x11/imm32/alloc-id:fake
10194     _string-add/imm32/name
10195     0x11/imm32/alloc-id:fake
10196     Single-lit-var/imm32/inouts
10197     0x11/imm32/alloc-id:fake
10198     Single-int-var-in-eax/imm32/outputs
10199     0x11/imm32/alloc-id:fake
10200     _string_05_add_to_eax/imm32/subx-name
10201     0/imm32/no-rm32
10202     0/imm32/no-r32
10203     1/imm32/imm32-is-first-inout
10204     0/imm32/no-disp32
10205     0/imm32/output-is-write-only
10206     0x11/imm32/alloc-id:fake
10207     _Primitive-add-reg-to-reg/imm32/next
10208 _Primitive-add-reg-to-reg:  # (payload primitive)
10209     0x11/imm32/alloc-id:fake:payload
10210     # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32
10211     0x11/imm32/alloc-id:fake
10212     _string-add/imm32/name
10213     0x11/imm32/alloc-id:fake
10214     Single-int-var-in-some-register/imm32/inouts
10215     0x11/imm32/alloc-id:fake
10216     Single-int-var-in-some-register/imm32/outputs
10217     0x11/imm32/alloc-id:fake
10218     _string_01_add_to/imm32/subx-name
10219     3/imm32/rm32-is-first-output
10220     1/imm32/r32-is-first-inout
10221     0/imm32/no-imm32
10222     0/imm32/no-disp32
10223     0/imm32/output-is-write-only
10224     0x11/imm32/alloc-id:fake
10225     _Primitive-add-reg-to-mem/imm32/next
10226 _Primitive-add-reg-to-mem:  # (payload primitive)
10227     0x11/imm32/alloc-id:fake:payload
10228     # add-to var1 var2/reg => 01/add-to var1 var2/r32
10229     0x11/imm32/alloc-id:fake
10230     _string-add-to/imm32/name
10231     0x11/imm32/alloc-id:fake
10232     Two-args-int-stack-int-reg/imm32/inouts
10233     0/imm32/no-outputs
10234     0/imm32/no-outputs
10235     0x11/imm32/alloc-id:fake
10236     _string_01_add_to/imm32/subx-name
10237     1/imm32/rm32-is-first-inout
10238     2/imm32/r32-is-second-inout
10239     0/imm32/no-imm32
10240     0/imm32/no-disp32
10241     0/imm32/output-is-write-only
10242     0x11/imm32/alloc-id:fake
10243     _Primitive-add-mem-to-reg/imm32/next
10244 _Primitive-add-mem-to-reg:  # (payload primitive)
10245     0x11/imm32/alloc-id:fake:payload
10246     # var1/reg <- add var2 => 03/add var2/rm32 var1/r32
10247     0x11/imm32/alloc-id:fake
10248     _string-add/imm32/name
10249     0x11/imm32/alloc-id:fake
10250     Single-int-var-in-mem/imm32/inouts
10251     0x11/imm32/alloc-id:fake
10252     Single-int-var-in-some-register/imm32/outputs
10253     0x11/imm32/alloc-id:fake
10254     _string_03_add/imm32/subx-name
10255     1/imm32/rm32-is-first-inout
10256     3/imm32/r32-is-first-output
10257     0/imm32/no-imm32
10258     0/imm32/no-disp32
10259     0/imm32/output-is-write-only
10260     0x11/imm32/alloc-id:fake
10261     _Primitive-add-lit-to-reg/imm32/next
10262 _Primitive-add-lit-to-reg:  # (payload primitive)
10263     0x11/imm32/alloc-id:fake:payload
10264     # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32
10265     0x11/imm32/alloc-id:fake
10266     _string-add/imm32/name
10267     0x11/imm32/alloc-id:fake
10268     Single-lit-var/imm32/inouts
10269     0x11/imm32/alloc-id:fake
10270     Single-int-var-in-some-register/imm32/outputs
10271     0x11/imm32/alloc-id:fake
10272     _string_81_subop_add/imm32/subx-name
10273     3/imm32/rm32-is-first-output
10274     0/imm32/no-r32
10275     1/imm32/imm32-is-first-inout
10276     0/imm32/no-disp32
10277     0/imm32/output-is-write-only
10278     0x11/imm32/alloc-id:fake
10279     _Primitive-add-lit-to-mem/imm32/next
10280 _Primitive-add-lit-to-mem:  # (payload primitive)
10281     0x11/imm32/alloc-id:fake:payload
10282     # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32
10283     0x11/imm32/alloc-id:fake
10284     _string-add-to/imm32/name
10285     0x11/imm32/alloc-id:fake
10286     Int-var-and-literal/imm32/inouts
10287     0/imm32/no-outputs
10288     0/imm32/no-outputs
10289     0x11/imm32/alloc-id:fake
10290     _string_81_subop_add/imm32/subx-name
10291     1/imm32/rm32-is-first-inout
10292     0/imm32/no-r32
10293     2/imm32/imm32-is-second-inout
10294     0/imm32/no-disp32
10295     0/imm32/output-is-write-only
10296     0x11/imm32/alloc-id:fake
10297     _Primitive-subtract-from-eax/imm32/next
10298 # - subtract
10299 _Primitive-subtract-from-eax:  # (payload primitive)
10300     0x11/imm32/alloc-id:fake:payload
10301     # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32
10302     0x11/imm32/alloc-id:fake
10303     _string-subtract/imm32/name
10304     0x11/imm32/alloc-id:fake
10305     Single-lit-var/imm32/inouts
10306     0x11/imm32/alloc-id:fake
10307     Single-int-var-in-eax/imm32/outputs
10308     0x11/imm32/alloc-id:fake
10309     _string_2d_subtract_from_eax/imm32/subx-name
10310     0/imm32/no-rm32
10311     0/imm32/no-r32
10312     1/imm32/imm32-is-first-inout
10313     0/imm32/no-disp32
10314     0/imm32/output-is-write-only
10315     0x11/imm32/alloc-id:fake
10316     _Primitive-subtract-reg-from-reg/imm32/next
10317 _Primitive-subtract-reg-from-reg:  # (payload primitive)
10318     0x11/imm32/alloc-id:fake:payload
10319     # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32
10320     0x11/imm32/alloc-id:fake
10321     _string-subtract/imm32/name
10322     0x11/imm32/alloc-id:fake
10323     Single-int-var-in-some-register/imm32/inouts
10324     0x11/imm32/alloc-id:fake
10325     Single-int-var-in-some-register/imm32/outputs
10326     0x11/imm32/alloc-id:fake
10327     _string_29_subtract_from/imm32/subx-name
10328     3/imm32/rm32-is-first-output
10329     1/imm32/r32-is-first-inout
10330     0/imm32/no-imm32
10331     0/imm32/no-disp32
10332     0/imm32/output-is-write-only
10333     0x11/imm32/alloc-id:fake
10334     _Primitive-subtract-reg-from-mem/imm32/next
10335 _Primitive-subtract-reg-from-mem:  # (payload primitive)
10336     0x11/imm32/alloc-id:fake:payload
10337     # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32
10338     0x11/imm32/alloc-id:fake
10339     _string-subtract-from/imm32/name
10340     0x11/imm32/alloc-id:fake
10341     Two-args-int-stack-int-reg/imm32/inouts
10342     0/imm32/no-outputs
10343     0/imm32/no-outputs
10344     0x11/imm32/alloc-id:fake
10345     _string_29_subtract_from/imm32/subx-name
10346     1/imm32/rm32-is-first-inout
10347     2/imm32/r32-is-second-inout
10348     0/imm32/no-imm32
10349     0/imm32/no-disp32
10350     0/imm32/output-is-write-only
10351     0x11/imm32/alloc-id:fake
10352     _Primitive-subtract-mem-from-reg/imm32/next
10353 _Primitive-subtract-mem-from-reg:  # (payload primitive)
10354     0x11/imm32/alloc-id:fake:payload
10355     # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32
10356     0x11/imm32/alloc-id:fake
10357     _string-subtract/imm32/name
10358     0x11/imm32/alloc-id:fake
10359     Single-int-var-in-mem/imm32/inouts
10360     0x11/imm32/alloc-id:fake
10361     Single-int-var-in-some-register/imm32/outputs
10362     0x11/imm32/alloc-id:fake
10363     _string_2b_subtract/imm32/subx-name
10364     1/imm32/rm32-is-first-inout
10365     3/imm32/r32-is-first-output
10366     0/imm32/no-imm32
10367     0/imm32/no-disp32
10368     0/imm32/output-is-write-only
10369     0x11/imm32/alloc-id:fake
10370     _Primitive-subtract-lit-from-reg/imm32/next
10371 _Primitive-subtract-lit-from-reg:  # (payload primitive)
10372     0x11/imm32/alloc-id:fake:payload
10373     # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32
10374     0x11/imm32/alloc-id:fake
10375     _string-subtract/imm32/name
10376     0x11/imm32/alloc-id:fake
10377     Single-lit-var/imm32/inouts
10378     0x11/imm32/alloc-id:fake
10379     Single-int-var-in-some-register/imm32/outputs
10380     0x11/imm32/alloc-id:fake
10381     _string_81_subop_subtract/imm32/subx-name
10382     3/imm32/rm32-is-first-output
10383     0/imm32/no-r32
10384     1/imm32/imm32-is-first-inout
10385     0/imm32/no-disp32
10386     0/imm32/output-is-write-only
10387     0x11/imm32/alloc-id:fake
10388     _Primitive-subtract-lit-from-mem/imm32/next
10389 _Primitive-subtract-lit-from-mem:  # (payload primitive)
10390     0x11/imm32/alloc-id:fake:payload
10391     # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32
10392     0x11/imm32/alloc-id:fake
10393     _string-subtract-from/imm32/name
10394     0x11/imm32/alloc-id:fake
10395     Int-var-and-literal/imm32/inouts
10396     0/imm32/no-outputs
10397     0/imm32/no-outputs
10398     0x11/imm32/alloc-id:fake
10399     _string_81_subop_subtract/imm32/subx-name
10400     1/imm32/rm32-is-first-inout
10401     0/imm32/no-r32
10402     2/imm32/imm32-is-first-inout
10403     0/imm32/no-disp32
10404     0/imm32/output-is-write-only
10405     0x11/imm32/alloc-id:fake
10406     _Primitive-and-with-eax/imm32/next
10407 # - and
10408 _Primitive-and-with-eax:  # (payload primitive)
10409     0x11/imm32/alloc-id:fake:payload
10410     # var/eax <- and lit => 25/and-with-eax lit/imm32
10411     0x11/imm32/alloc-id:fake
10412     _string-and/imm32/name
10413     0x11/imm32/alloc-id:fake
10414     Single-lit-var/imm32/inouts
10415     0x11/imm32/alloc-id:fake
10416     Single-int-var-in-eax/imm32/outputs
10417     0x11/imm32/alloc-id:fake
10418     _string_25_and_with_eax/imm32/subx-name
10419     0/imm32/no-rm32
10420     0/imm32/no-r32
10421     1/imm32/imm32-is-first-inout
10422     0/imm32/no-disp32
10423     0/imm32/output-is-write-only
10424     0x11/imm32/alloc-id:fake
10425     _Primitive-and-reg-with-reg/imm32/next
10426 _Primitive-and-reg-with-reg:  # (payload primitive)
10427     0x11/imm32/alloc-id:fake:payload
10428     # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32
10429     0x11/imm32/alloc-id:fake
10430     _string-and/imm32/name
10431     0x11/imm32/alloc-id:fake
10432     Single-int-var-in-some-register/imm32/inouts
10433     0x11/imm32/alloc-id:fake
10434     Single-int-var-in-some-register/imm32/outputs
10435     0x11/imm32/alloc-id:fake
10436     _string_21_and_with/imm32/subx-name
10437     3/imm32/rm32-is-first-output
10438     1/imm32/r32-is-first-inout
10439     0/imm32/no-imm32
10440     0/imm32/no-disp32
10441     0/imm32/output-is-write-only
10442     0x11/imm32/alloc-id:fake
10443     _Primitive-and-reg-with-mem/imm32/next
10444 _Primitive-and-reg-with-mem:  # (payload primitive)
10445     0x11/imm32/alloc-id:fake:payload
10446     # and-with var1 var2/reg => 21/and-with var1 var2/r32
10447     0x11/imm32/alloc-id:fake
10448     _string-and-with/imm32/name
10449     0x11/imm32/alloc-id:fake
10450     Two-args-int-stack-int-reg/imm32/inouts
10451     0/imm32/no-outputs
10452     0/imm32/no-outputs
10453     0x11/imm32/alloc-id:fake
10454     _string_21_and_with/imm32/subx-name
10455     1/imm32/rm32-is-first-inout
10456     2/imm32/r32-is-second-inout
10457     0/imm32/no-imm32
10458     0/imm32/no-disp32
10459     0/imm32/output-is-write-only
10460     0x11/imm32/alloc-id:fake
10461     _Primitive-and-mem-with-reg/imm32/next
10462 _Primitive-and-mem-with-reg:  # (payload primitive)
10463     0x11/imm32/alloc-id:fake:payload
10464     # var1/reg <- and var2 => 23/and var2/rm32 var1/r32
10465     0x11/imm32/alloc-id:fake
10466     _string-and/imm32/name
10467     0x11/imm32/alloc-id:fake
10468     Single-int-var-in-mem/imm32/inouts
10469     0x11/imm32/alloc-id:fake
10470     Single-int-var-in-some-register/imm32/outputs
10471     0x11/imm32/alloc-id:fake
10472     _string_23_and/imm32/subx-name
10473     1/imm32/rm32-is-first-inout
10474     3/imm32/r32-is-first-output
10475     0/imm32/no-imm32
10476     0/imm32/no-disp32
10477     0/imm32/output-is-write-only
10478     0x11/imm32/alloc-id:fake
10479     _Primitive-and-lit-with-reg/imm32/next
10480 _Primitive-and-lit-with-reg:  # (payload primitive)
10481     0x11/imm32/alloc-id:fake:payload
10482     # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32
10483     0x11/imm32/alloc-id:fake
10484     _string-and/imm32/name
10485     0x11/imm32/alloc-id:fake
10486     Single-lit-var/imm32/inouts
10487     0x11/imm32/alloc-id:fake
10488     Single-int-var-in-some-register/imm32/outputs
10489     0x11/imm32/alloc-id:fake
10490     _string_81_subop_and/imm32/subx-name
10491     3/imm32/rm32-is-first-output
10492     0/imm32/no-r32
10493     1/imm32/imm32-is-first-inout
10494     0/imm32/no-disp32
10495     0/imm32/output-is-write-only
10496     0x11/imm32/alloc-id:fake
10497     _Primitive-and-lit-with-mem/imm32/next
10498 _Primitive-and-lit-with-mem:  # (payload primitive)
10499     0x11/imm32/alloc-id:fake:payload
10500     # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32
10501     0x11/imm32/alloc-id:fake
10502     _string-and-with/imm32/name
10503     0x11/imm32/alloc-id:fake
10504     Int-var-and-literal/imm32/inouts
10505     0/imm32/no-outputs
10506     0/imm32/no-outputs
10507     0x11/imm32/alloc-id:fake
10508     _string_81_subop_and/imm32/subx-name
10509     1/imm32/rm32-is-first-inout
10510     0/imm32/no-r32
10511     2/imm32/imm32-is-first-inout
10512     0/imm32/no-disp32
10513     0/imm32/output-is-write-only
10514     0x11/imm32/alloc-id:fake
10515     _Primitive-or-with-eax/imm32/next
10516 # - or
10517 _Primitive-or-with-eax:  # (payload primitive)
10518     0x11/imm32/alloc-id:fake:payload
10519     # var/eax <- or lit => 0d/or-with-eax lit/imm32
10520     0x11/imm32/alloc-id:fake
10521     _string-or/imm32/name
10522     0x11/imm32/alloc-id:fake
10523     Single-lit-var/imm32/inouts
10524     0x11/imm32/alloc-id:fake
10525     Single-int-var-in-eax/imm32/outputs
10526     0x11/imm32/alloc-id:fake
10527     _string_0d_or_with_eax/imm32/subx-name
10528     0/imm32/no-rm32
10529     0/imm32/no-r32
10530     1/imm32/imm32-is-first-inout
10531     0/imm32/no-disp32
10532     0/imm32/output-is-write-only
10533     0x11/imm32/alloc-id:fake
10534     _Primitive-or-reg-with-reg/imm32/next
10535 _Primitive-or-reg-with-reg:  # (payload primitive)
10536     0x11/imm32/alloc-id:fake:payload
10537     # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32
10538     0x11/imm32/alloc-id:fake
10539     _string-or/imm32/name
10540     0x11/imm32/alloc-id:fake
10541     Single-int-var-in-some-register/imm32/inouts
10542     0x11/imm32/alloc-id:fake
10543     Single-int-var-in-some-register/imm32/outputs
10544     0x11/imm32/alloc-id:fake
10545     _string_09_or_with/imm32/subx-name
10546     3/imm32/rm32-is-first-output
10547     1/imm32/r32-is-first-inout
10548     0/imm32/no-imm32
10549     0/imm32/no-disp32
10550     0/imm32/output-is-write-only
10551     0x11/imm32/alloc-id:fake
10552     _Primitive-or-reg-with-mem/imm32/next
10553 _Primitive-or-reg-with-mem:  # (payload primitive)
10554     0x11/imm32/alloc-id:fake:payload
10555     # or-with var1 var2/reg => 09/or-with var1 var2/r32
10556     0x11/imm32/alloc-id:fake
10557     _string-or-with/imm32/name
10558     0x11/imm32/alloc-id:fake
10559     Two-args-int-stack-int-reg/imm32/inouts
10560     0/imm32/no-outputs
10561     0/imm32/no-outputs
10562     0x11/imm32/alloc-id:fake
10563     _string_09_or_with/imm32/subx-name
10564     1/imm32/rm32-is-first-inout
10565     2/imm32/r32-is-second-inout
10566     0/imm32/no-imm32
10567     0/imm32/no-disp32
10568     0/imm32/output-is-write-only
10569     0x11/imm32/alloc-id:fake
10570     _Primitive-or-mem-with-reg/imm32/next
10571 _Primitive-or-mem-with-reg:  # (payload primitive)
10572     0x11/imm32/alloc-id:fake:payload
10573     # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32
10574     0x11/imm32/alloc-id:fake
10575     _string-or/imm32/name
10576     0x11/imm32/alloc-id:fake
10577     Single-int-var-in-mem/imm32/inouts
10578     0x11/imm32/alloc-id:fake
10579     Single-int-var-in-some-register/imm32/outputs
10580     0x11/imm32/alloc-id:fake
10581     _string_0b_or/imm32/subx-name
10582     1/imm32/rm32-is-first-inout
10583     3/imm32/r32-is-first-output
10584     0/imm32/no-imm32
10585     0/imm32/no-disp32
10586     0/imm32/output-is-write-only
10587     0x11/imm32/alloc-id:fake
10588     _Primitive-or-lit-with-reg/imm32/next
10589 _Primitive-or-lit-with-reg:  # (payload primitive)
10590     0x11/imm32/alloc-id:fake:payload
10591     # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32
10592     0x11/imm32/alloc-id:fake
10593     _string-or/imm32/name
10594     0x11/imm32/alloc-id:fake
10595     Single-lit-var/imm32/inouts
10596     0x11/imm32/alloc-id:fake
10597     Single-int-var-in-some-register/imm32/outputs
10598     0x11/imm32/alloc-id:fake
10599     _string_81_subop_or/imm32/subx-name
10600     3/imm32/rm32-is-first-output
10601     0/imm32/no-r32
10602     1/imm32/imm32-is-first-inout
10603     0/imm32/no-disp32
10604     0/imm32/output-is-write-only
10605     0x11/imm32/alloc-id:fake
10606     _Primitive-or-lit-with-mem/imm32/next
10607 _Primitive-or-lit-with-mem:  # (payload primitive)
10608     0x11/imm32/alloc-id:fake:payload
10609     # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32
10610     0x11/imm32/alloc-id:fake
10611     _string-or-with/imm32/name
10612     0x11/imm32/alloc-id:fake
10613     Int-var-and-literal/imm32/inouts
10614     0/imm32/no-outputs
10615     0/imm32/no-outputs
10616     0x11/imm32/alloc-id:fake
10617     _string_81_subop_or/imm32/subx-name
10618     1/imm32/rm32-is-first-inout
10619     0/imm32/no-r32
10620     2/imm32/imm32-is-second-inout
10621     0/imm32/no-disp32
10622     0/imm32/output-is-write-only
10623     0x11/imm32/alloc-id:fake
10624     _Primitive-xor-with-eax/imm32/next
10625 # - xor
10626 _Primitive-xor-with-eax:  # (payload primitive)
10627     0x11/imm32/alloc-id:fake:payload
10628     # var/eax <- xor lit => 35/xor-with-eax lit/imm32
10629     0x11/imm32/alloc-id:fake
10630     _string-xor/imm32/name
10631     0x11/imm32/alloc-id:fake
10632     Single-lit-var/imm32/inouts
10633     0x11/imm32/alloc-id:fake
10634     Single-int-var-in-eax/imm32/outputs
10635     0x11/imm32/alloc-id:fake
10636     _string_35_xor_with_eax/imm32/subx-name
10637     0/imm32/no-rm32
10638     0/imm32/no-r32
10639     1/imm32/imm32-is-first-inout
10640     0/imm32/no-disp32
10641     0/imm32/output-is-write-only
10642     0x11/imm32/alloc-id:fake
10643     _Primitive-xor-reg-with-reg/imm32/next
10644 _Primitive-xor-reg-with-reg:  # (payload primitive)
10645     0x11/imm32/alloc-id:fake:payload
10646     # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32
10647     0x11/imm32/alloc-id:fake
10648     _string-xor/imm32/name
10649     0x11/imm32/alloc-id:fake
10650     Single-int-var-in-some-register/imm32/inouts
10651     0x11/imm32/alloc-id:fake
10652     Single-int-var-in-some-register/imm32/outputs
10653     0x11/imm32/alloc-id:fake
10654     _string_31_xor_with/imm32/subx-name
10655     3/imm32/rm32-is-first-output
10656     1/imm32/r32-is-first-inout
10657     0/imm32/no-imm32
10658     0/imm32/no-disp32
10659     0/imm32/output-is-write-only
10660     0x11/imm32/alloc-id:fake
10661     _Primitive-xor-reg-with-mem/imm32/next
10662 _Primitive-xor-reg-with-mem:  # (payload primitive)
10663     0x11/imm32/alloc-id:fake:payload
10664     # xor-with var1 var2/reg => 31/xor-with var1 var2/r32
10665     0x11/imm32/alloc-id:fake
10666     _string-xor-with/imm32/name
10667     0x11/imm32/alloc-id:fake
10668     Two-args-int-stack-int-reg/imm32/inouts
10669     0/imm32/no-outputs
10670     0/imm32/no-outputs
10671     0x11/imm32/alloc-id:fake
10672     _string_31_xor_with/imm32/subx-name
10673     1/imm32/rm32-is-first-inout
10674     2/imm32/r32-is-second-inout
10675     0/imm32/no-imm32
10676     0/imm32/no-disp32
10677     0/imm32/output-is-write-only
10678     0x11/imm32/alloc-id:fake
10679     _Primitive-xor-mem-with-reg/imm32/next
10680 _Primitive-xor-mem-with-reg:  # (payload primitive)
10681     0x11/imm32/alloc-id:fake:payload
10682     # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32
10683     0x11/imm32/alloc-id:fake
10684     _string-xor/imm32/name
10685     0x11/imm32/alloc-id:fake
10686     Single-int-var-in-mem/imm32/inouts
10687     0x11/imm32/alloc-id:fake
10688     Single-int-var-in-some-register/imm32/outputs
10689     0x11/imm32/alloc-id:fake
10690     _string_33_xor/imm32/subx-name
10691     1/imm32/rm32-is-first-inout
10692     3/imm32/r32-is-first-output
10693     0/imm32/no-imm32
10694     0/imm32/no-disp32
10695     0/imm32/output-is-write-only
10696     0x11/imm32/alloc-id:fake
10697     _Primitive-xor-lit-with-reg/imm32/next
10698 _Primitive-xor-lit-with-reg:  # (payload primitive)
10699     0x11/imm32/alloc-id:fake:payload
10700     # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32
10701     0x11/imm32/alloc-id:fake
10702     _string-xor/imm32/name
10703     0x11/imm32/alloc-id:fake
10704     Single-lit-var/imm32/inouts
10705     0x11/imm32/alloc-id:fake
10706     Single-int-var-in-some-register/imm32/outputs
10707     0x11/imm32/alloc-id:fake
10708     _string_81_subop_xor/imm32/subx-name
10709     3/imm32/rm32-is-first-output
10710     0/imm32/no-r32
10711     1/imm32/imm32-is-first-inout
10712     0/imm32/no-disp32
10713     0/imm32/output-is-write-only
10714     0x11/imm32/alloc-id:fake
10715     _Primitive-xor-lit-with-mem/imm32/next
10716 _Primitive-xor-lit-with-mem:  # (payload primitive)
10717     0x11/imm32/alloc-id:fake:payload
10718     # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32
10719     0x11/imm32/alloc-id:fake
10720     _string-xor-with/imm32/name
10721     0x11/imm32/alloc-id:fake
10722     Int-var-and-literal/imm32/inouts
10723     0/imm32/no-outputs
10724     0/imm32/no-outputs
10725     0x11/imm32/alloc-id:fake
10726     _string_81_subop_xor/imm32/subx-name
10727     1/imm32/rm32-is-first-inout
10728     0/imm32/no-r32
10729     2/imm32/imm32-is-first-inout
10730     0/imm32/no-disp32
10731     0/imm32/output-is-write-only
10732     0x11/imm32/alloc-id:fake
10733     _Primitive-copy-to-eax/imm32/next
10734 # - copy
10735 _Primitive-copy-to-eax:  # (payload primitive)
10736     0x11/imm32/alloc-id:fake:payload
10737     # var/eax <- copy lit => b8/copy-to-eax lit/imm32
10738     0x11/imm32/alloc-id:fake
10739     _string-copy/imm32/name
10740     0x11/imm32/alloc-id:fake
10741     Single-lit-var/imm32/inouts
10742     0x11/imm32/alloc-id:fake
10743     Single-int-var-in-eax/imm32/outputs
10744     0x11/imm32/alloc-id:fake
10745     _string_b8_copy_to_eax/imm32/subx-name
10746     0/imm32/no-rm32
10747     0/imm32/no-r32
10748     1/imm32/imm32-is-first-inout
10749     0/imm32/no-disp32
10750     1/imm32/output-is-write-only
10751     0x11/imm32/alloc-id:fake
10752     _Primitive-copy-to-ecx/imm32/next
10753 _Primitive-copy-to-ecx:  # (payload primitive)
10754     0x11/imm32/alloc-id:fake:payload
10755     # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32
10756     0x11/imm32/alloc-id:fake
10757     _string-copy/imm32/name
10758     0x11/imm32/alloc-id:fake
10759     Single-lit-var/imm32/inouts
10760     0x11/imm32/alloc-id:fake
10761     Single-int-var-in-ecx/imm32/outputs
10762     0x11/imm32/alloc-id:fake
10763     _string_b9_copy_to_ecx/imm32/subx-name
10764     0/imm32/no-rm32
10765     0/imm32/no-r32
10766     1/imm32/imm32-is-first-inout
10767     0/imm32/no-disp32
10768     1/imm32/output-is-write-only
10769     0x11/imm32/alloc-id:fake
10770     _Primitive-copy-to-edx/imm32/next
10771 _Primitive-copy-to-edx:  # (payload primitive)
10772     0x11/imm32/alloc-id:fake:payload
10773     # var/edx <- copy lit => ba/copy-to-edx lit/imm32
10774     0x11/imm32/alloc-id:fake
10775     _string-copy/imm32/name
10776     0x11/imm32/alloc-id:fake
10777     Single-lit-var/imm32/inouts
10778     0x11/imm32/alloc-id:fake
10779     Single-int-var-in-edx/imm32/outputs
10780     0x11/imm32/alloc-id:fake
10781     _string_ba_copy_to_edx/imm32/subx-name
10782     0/imm32/no-rm32
10783     0/imm32/no-r32
10784     1/imm32/imm32-is-first-inout
10785     0/imm32/no-disp32
10786     1/imm32/output-is-write-only
10787     0x11/imm32/alloc-id:fake
10788     _Primitive-copy-to-ebx/imm32/next
10789 _Primitive-copy-to-ebx:  # (payload primitive)
10790     0x11/imm32/alloc-id:fake:payload
10791     # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32
10792     0x11/imm32/alloc-id:fake
10793     _string-copy/imm32/name
10794     0x11/imm32/alloc-id:fake
10795     Single-lit-var/imm32/inouts
10796     0x11/imm32/alloc-id:fake
10797     Single-int-var-in-ebx/imm32/outputs
10798     0x11/imm32/alloc-id:fake
10799     _string_bb_copy_to_ebx/imm32/subx-name
10800     0/imm32/no-rm32
10801     0/imm32/no-r32
10802     1/imm32/imm32-is-first-inout
10803     0/imm32/no-disp32
10804     1/imm32/output-is-write-only
10805     0x11/imm32/alloc-id:fake
10806     _Primitive-copy-to-esi/imm32/next
10807 _Primitive-copy-to-esi:  # (payload primitive)
10808     0x11/imm32/alloc-id:fake:payload
10809     # var/esi <- copy lit => be/copy-to-esi lit/imm32
10810     0x11/imm32/alloc-id:fake
10811     _string-copy/imm32/name
10812     0x11/imm32/alloc-id:fake
10813     Single-lit-var/imm32/inouts
10814     0x11/imm32/alloc-id:fake
10815     Single-int-var-in-esi/imm32/outputs
10816     0x11/imm32/alloc-id:fake
10817     _string_be_copy_to_esi/imm32/subx-name
10818     0/imm32/no-rm32
10819     0/imm32/no-r32
10820     1/imm32/imm32-is-first-inout
10821     0/imm32/no-disp32
10822     1/imm32/output-is-write-only
10823     0x11/imm32/alloc-id:fake
10824     _Primitive-copy-to-edi/imm32/next
10825 _Primitive-copy-to-edi:  # (payload primitive)
10826     0x11/imm32/alloc-id:fake:payload
10827     # var/edi <- copy lit => bf/copy-to-edi lit/imm32
10828     0x11/imm32/alloc-id:fake
10829     _string-copy/imm32/name
10830     0x11/imm32/alloc-id:fake
10831     Single-lit-var/imm32/inouts
10832     0x11/imm32/alloc-id:fake
10833     Single-int-var-in-edi/imm32/outputs
10834     0x11/imm32/alloc-id:fake
10835     _string_bf_copy_to_edi/imm32/subx-name
10836     0/imm32/no-rm32
10837     0/imm32/no-r32
10838     1/imm32/imm32-is-first-inout
10839     0/imm32/no-disp32
10840     1/imm32/output-is-write-only
10841     0x11/imm32/alloc-id:fake
10842     _Primitive-copy-reg-to-reg/imm32/next
10843 _Primitive-copy-reg-to-reg:  # (payload primitive)
10844     0x11/imm32/alloc-id:fake:payload
10845     # var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32
10846     0x11/imm32/alloc-id:fake
10847     _string-copy/imm32/name
10848     0x11/imm32/alloc-id:fake
10849     Single-int-var-in-some-register/imm32/inouts
10850     0x11/imm32/alloc-id:fake
10851     Single-int-var-in-some-register/imm32/outputs
10852     0x11/imm32/alloc-id:fake
10853     _string_89_<-/imm32/subx-name
10854     3/imm32/rm32-is-first-output
10855     1/imm32/r32-is-first-inout
10856     0/imm32/no-imm32
10857     0/imm32/no-disp32
10858     1/imm32/output-is-write-only
10859     0x11/imm32/alloc-id:fake
10860     _Primitive-copy-reg-to-mem/imm32/next
10861 _Primitive-copy-reg-to-mem:  # (payload primitive)
10862     0x11/imm32/alloc-id:fake:payload
10863     # copy-to var1 var2/reg => 89/<- var1 var2/r32
10864     0x11/imm32/alloc-id:fake
10865     _string-copy-to/imm32/name
10866     0x11/imm32/alloc-id:fake
10867     Two-args-int-stack-int-reg/imm32/inouts
10868     0/imm32/no-outputs
10869     0/imm32/no-outputs
10870     0x11/imm32/alloc-id:fake
10871     _string_89_<-/imm32/subx-name
10872     1/imm32/rm32-is-first-inout
10873     2/imm32/r32-is-second-inout
10874     0/imm32/no-imm32
10875     0/imm32/no-disp32
10876     1/imm32/output-is-write-only
10877     0x11/imm32/alloc-id:fake
10878     _Primitive-copy-mem-to-reg/imm32/next
10879 _Primitive-copy-mem-to-reg:  # (payload primitive)
10880     0x11/imm32/alloc-id:fake:payload
10881     # var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32
10882     0x11/imm32/alloc-id:fake
10883     _string-copy/imm32/name
10884     0x11/imm32/alloc-id:fake
10885     Single-int-var-in-mem/imm32/inouts
10886     0x11/imm32/alloc-id:fake
10887     Single-int-var-in-some-register/imm32/outputs
10888     0x11/imm32/alloc-id:fake
10889     _string_8b_->/imm32/subx-name
10890     1/imm32/rm32-is-first-inout
10891     3/imm32/r32-is-first-output
10892     0/imm32/no-imm32
10893     0/imm32/no-disp32
10894     1/imm32/output-is-write-only
10895     0x11/imm32/alloc-id:fake
10896     _Primitive-copy-lit-to-reg/imm32/next
10897 _Primitive-copy-lit-to-reg:  # (payload primitive)
10898     0x11/imm32/alloc-id:fake:payload
10899     # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32
10900     0x11/imm32/alloc-id:fake
10901     _string-copy/imm32/name
10902     0x11/imm32/alloc-id:fake
10903     Single-lit-var/imm32/inouts
10904     0x11/imm32/alloc-id:fake
10905     Single-int-var-in-some-register/imm32/outputs
10906     0x11/imm32/alloc-id:fake
10907     _string_c7_subop_copy/imm32/subx-name
10908     3/imm32/rm32-is-first-output
10909     0/imm32/no-r32
10910     1/imm32/imm32-is-first-inout
10911     0/imm32/no-disp32
10912     1/imm32/output-is-write-only
10913     0x11/imm32/alloc-id:fake
10914     _Primitive-copy-lit-to-mem/imm32/next
10915 _Primitive-copy-lit-to-mem:  # (payload primitive)
10916     0x11/imm32/alloc-id:fake:payload
10917     # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32
10918     0x11/imm32/alloc-id:fake
10919     _string-copy-to/imm32/name
10920     0x11/imm32/alloc-id:fake
10921     Int-var-and-literal/imm32/inouts
10922     0/imm32/no-outputs
10923     0/imm32/no-outputs
10924     0x11/imm32/alloc-id:fake
10925     _string_c7_subop_copy/imm32/subx-name
10926     1/imm32/rm32-is-first-inout
10927     0/imm32/no-r32
10928     2/imm32/imm32-is-first-inout
10929     0/imm32/no-disp32
10930     1/imm32/output-is-write-only
10931     0x11/imm32/alloc-id:fake
10932     _Primitive-address/imm32/next
10933 # - address
10934 _Primitive-address:  # (payload primitive)
10935     0x11/imm32/alloc-id:fake:payload
10936     # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32
10937     0x11/imm32/alloc-id:fake
10938     _string-address/imm32/name
10939     0x11/imm32/alloc-id:fake
10940     Single-int-var-in-mem/imm32/inouts
10941     0x11/imm32/alloc-id:fake
10942     Single-addr-var-in-some-register/imm32/outputs
10943     0x11/imm32/alloc-id:fake
10944     _string_8d_copy_address/imm32/subx-name
10945     1/imm32/rm32-is-first-inout
10946     3/imm32/r32-is-first-output
10947     0/imm32/no-imm32
10948     0/imm32/no-disp32
10949     1/imm32/output-is-write-only
10950     0x11/imm32/alloc-id:fake
10951     _Primitive-compare-mem-with-reg/imm32/next
10952 # - compare
10953 _Primitive-compare-mem-with-reg:  # (payload primitive)
10954     0x11/imm32/alloc-id:fake:payload
10955     # compare var1 var2/reg => 39/compare var1/rm32 var2/r32
10956     0x11/imm32/alloc-id:fake
10957     _string-compare/imm32/name
10958     0x11/imm32/alloc-id:fake
10959     Two-args-int-stack-int-reg/imm32/inouts
10960     0/imm32/no-outputs
10961     0/imm32/no-outputs
10962     0x11/imm32/alloc-id:fake
10963     _string_39_compare->/imm32/subx-name
10964     1/imm32/rm32-is-first-inout
10965     2/imm32/r32-is-second-inout
10966     0/imm32/no-imm32
10967     0/imm32/no-disp32
10968     0/imm32/output-is-write-only
10969     0x11/imm32/alloc-id:fake
10970     _Primitive-compare-reg-with-mem/imm32/next
10971 _Primitive-compare-reg-with-mem:  # (payload primitive)
10972     0x11/imm32/alloc-id:fake:payload
10973     # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32
10974     0x11/imm32/alloc-id:fake
10975     _string-compare/imm32/name
10976     0x11/imm32/alloc-id:fake
10977     Two-args-int-reg-int-stack/imm32/inouts
10978     0/imm32/no-outputs
10979     0/imm32/no-outputs
10980     0x11/imm32/alloc-id:fake
10981     _string_3b_compare<-/imm32/subx-name
10982     2/imm32/rm32-is-second-inout
10983     1/imm32/r32-is-first-inout
10984     0/imm32/no-imm32
10985     0/imm32/no-disp32
10986     0/imm32/output-is-write-only
10987     0x11/imm32/alloc-id:fake
10988     _Primitive-compare-eax-with-literal/imm32/next
10989 _Primitive-compare-eax-with-literal:  # (payload primitive)
10990     0x11/imm32/alloc-id:fake:payload
10991     # compare var1/eax n => 3d/compare-eax-with n/imm32
10992     0x11/imm32/alloc-id:fake
10993     _string-compare/imm32/name
10994     0x11/imm32/alloc-id:fake
10995     Two-args-int-eax-int-literal/imm32/inouts
10996     0/imm32/no-outputs
10997     0/imm32/no-outputs
10998     0x11/imm32/alloc-id:fake
10999     _string_3d_compare_eax_with/imm32/subx-name
11000     0/imm32/no-rm32
11001     0/imm32/no-r32
11002     2/imm32/imm32-is-second-inout
11003     0/imm32/no-disp32
11004     0/imm32/output-is-write-only
11005     0x11/imm32/alloc-id:fake
11006     _Primitive-compare-reg-with-literal/imm32/next
11007 _Primitive-compare-reg-with-literal:  # (payload primitive)
11008     0x11/imm32/alloc-id:fake:payload
11009     # compare var1/reg n => 81 7/subop/compare %reg n/imm32
11010     0x11/imm32/alloc-id:fake
11011     _string-compare/imm32/name
11012     0x11/imm32/alloc-id:fake
11013     Int-var-in-register-and-literal/imm32/inouts
11014     0/imm32/no-outputs
11015     0/imm32/no-outputs
11016     0x11/imm32/alloc-id:fake
11017     _string_81_subop_compare/imm32/subx-name
11018     1/imm32/rm32-is-first-inout
11019     0/imm32/no-r32
11020     2/imm32/imm32-is-second-inout
11021     0/imm32/no-disp32
11022     0/imm32/output-is-write-only
11023     0x11/imm32/alloc-id:fake
11024     _Primitive-compare-mem-with-literal/imm32/next
11025 _Primitive-compare-mem-with-literal:  # (payload primitive)
11026     0x11/imm32/alloc-id:fake:payload
11027     # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32
11028     0x11/imm32/alloc-id:fake
11029     _string-compare/imm32/name
11030     0x11/imm32/alloc-id:fake
11031     Int-var-and-literal/imm32/inouts
11032     0/imm32/no-outputs
11033     0/imm32/no-outputs
11034     0x11/imm32/alloc-id:fake
11035     _string_81_subop_compare/imm32/subx-name
11036     1/imm32/rm32-is-first-inout
11037     0/imm32/no-r32
11038     2/imm32/imm32-is-second-inout
11039     0/imm32/no-disp32
11040     0/imm32/output-is-write-only
11041     0x11/imm32/alloc-id:fake
11042     _Primitive-multiply-reg-by-mem/imm32/next
11043 # - multiply
11044 _Primitive-multiply-reg-by-mem:  # (payload primitive)
11045     0x11/imm32/alloc-id:fake:payload
11046     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
11047     0x11/imm32/alloc-id:fake
11048     _string-multiply/imm32/name
11049     0x11/imm32/alloc-id:fake
11050     Single-int-var-in-mem/imm32/inouts
11051     0x11/imm32/alloc-id:fake
11052     Single-int-var-in-some-register/imm32/outputs
11053     0x11/imm32/alloc-id:fake
11054     _string_0f_af_multiply/imm32/subx-name
11055     1/imm32/rm32-is-first-inout
11056     3/imm32/r32-is-first-output
11057     0/imm32/no-imm32
11058     0/imm32/no-disp32
11059     0/imm32/output-is-write-only
11060     0x11/imm32/alloc-id:fake
11061     _Primitive-break-if-addr</imm32/next
11062 # - branches
11063 _Primitive-break-if-addr<:  # (payload primitive)
11064     0x11/imm32/alloc-id:fake:payload
11065     0x11/imm32/alloc-id:fake
11066     _string-break-if-addr</imm32/name
11067     0/imm32/no-inouts
11068     0/imm32/no-inouts
11069     0/imm32/no-outputs
11070     0/imm32/no-outputs
11071     0x11/imm32/alloc-id:fake
11072     _string_0f_82_jump_break/imm32/subx-name
11073     0/imm32/no-rm32
11074     0/imm32/no-r32
11075     0/imm32/no-imm32
11076     0/imm32/no-disp32
11077     0/imm32/no-output
11078     0x11/imm32/alloc-id:fake
11079     _Primitive-break-if-addr>=/imm32/next
11080 _Primitive-break-if-addr>=:  # (payload primitive)
11081     0x11/imm32/alloc-id:fake:payload
11082     0x11/imm32/alloc-id:fake
11083     _string-break-if-addr>=/imm32/name
11084     0/imm32/no-inouts
11085     0/imm32/no-inouts
11086     0/imm32/no-outputs
11087     0/imm32/no-outputs
11088     0x11/imm32/alloc-id:fake
11089     _string_0f_83_jump_break/imm32/subx-name
11090     0/imm32/no-rm32
11091     0/imm32/no-r32
11092     0/imm32/no-imm32
11093     0/imm32/no-disp32
11094     0/imm32/no-output
11095     0x11/imm32/alloc-id:fake
11096     _Primitive-break-if-=/imm32/next
11097 _Primitive-break-if-=:  # (payload primitive)
11098     0x11/imm32/alloc-id:fake:payload
11099     0x11/imm32/alloc-id:fake
11100     _string-break-if-=/imm32/name
11101     0/imm32/no-inouts
11102     0/imm32/no-inouts
11103     0/imm32/no-outputs
11104     0/imm32/no-outputs
11105     0x11/imm32/alloc-id:fake
11106     _string_0f_84_jump_break/imm32/subx-name
11107     0/imm32/no-rm32
11108     0/imm32/no-r32
11109     0/imm32/no-imm32
11110     0/imm32/no-disp32
11111     0/imm32/no-output
11112     0x11/imm32/alloc-id:fake
11113     _Primitive-break-if-!=/imm32/next
11114 _Primitive-break-if-!=:  # (payload primitive)
11115     0x11/imm32/alloc-id:fake:payload
11116     0x11/imm32/alloc-id:fake
11117     _string-break-if-!=/imm32/name
11118     0/imm32/no-inouts
11119     0/imm32/no-inouts
11120     0/imm32/no-outputs
11121     0/imm32/no-outputs
11122     0x11/imm32/alloc-id:fake
11123     _string_0f_85_jump_break/imm32/subx-name
11124     0/imm32/no-rm32
11125     0/imm32/no-r32
11126     0/imm32/no-imm32
11127     0/imm32/no-disp32
11128     0/imm32/no-output
11129     0x11/imm32/alloc-id:fake
11130     _Primitive-break-if-addr<=/imm32/next
11131 _Primitive-break-if-addr<=:  # (payload primitive)
11132     0x11/imm32/alloc-id:fake:payload
11133     0x11/imm32/alloc-id:fake
11134     _string-break-if-addr<=/imm32/name
11135     0/imm32/no-inouts
11136     0/imm32/no-inouts
11137     0/imm32/no-outputs
11138     0/imm32/no-outputs
11139     0x11/imm32/alloc-id:fake
11140     _string_0f_86_jump_break/imm32/subx-name
11141     0/imm32/no-rm32
11142     0/imm32/no-r32
11143     0/imm32/no-imm32
11144     0/imm32/no-disp32
11145     0/imm32/no-output
11146     0x11/imm32/alloc-id:fake
11147     _Primitive-break-if-addr>/imm32/next
11148 _Primitive-break-if-addr>:  # (payload primitive)
11149     0x11/imm32/alloc-id:fake:payload
11150     0x11/imm32/alloc-id:fake
11151     _string-break-if-addr>/imm32/name
11152     0/imm32/no-inouts
11153     0/imm32/no-inouts
11154     0/imm32/no-outputs
11155     0/imm32/no-outputs
11156     0x11/imm32/alloc-id:fake
11157     _string_0f_87_jump_break/imm32/subx-name
11158     0/imm32/no-rm32
11159     0/imm32/no-r32
11160     0/imm32/no-imm32
11161     0/imm32/no-disp32
11162     0/imm32/no-output
11163     0x11/imm32/alloc-id:fake
11164     _Primitive-break-if-</imm32/next
11165 _Primitive-break-if-<:  # (payload primitive)
11166     0x11/imm32/alloc-id:fake:payload
11167     0x11/imm32/alloc-id:fake
11168     _string-break-if-</imm32/name
11169     0/imm32/no-inouts
11170     0/imm32/no-inouts
11171     0/imm32/no-outputs
11172     0/imm32/no-outputs
11173     0x11/imm32/alloc-id:fake
11174     _string_0f_8c_jump_break/imm32/subx-name
11175     0/imm32/no-rm32
11176     0/imm32/no-r32
11177     0/imm32/no-imm32
11178     0/imm32/no-disp32
11179     0/imm32/no-output
11180     0x11/imm32/alloc-id:fake
11181     _Primitive-break-if->=/imm32/next
11182 _Primitive-break-if->=:  # (payload primitive)
11183     0x11/imm32/alloc-id:fake:payload
11184     0x11/imm32/alloc-id:fake
11185     _string-break-if->=/imm32/name
11186     0/imm32/no-inouts
11187     0/imm32/no-inouts
11188     0/imm32/no-outputs
11189     0/imm32/no-outputs
11190     0x11/imm32/alloc-id:fake
11191     _string_0f_8d_jump_break/imm32/subx-name
11192     0/imm32/no-rm32
11193     0/imm32/no-r32
11194     0/imm32/no-imm32
11195     0/imm32/no-disp32
11196     0/imm32/no-output
11197     0x11/imm32/alloc-id:fake
11198     _Primitive-break-if-<=/imm32/next
11199 _Primitive-break-if-<=:  # (payload primitive)
11200     0x11/imm32/alloc-id:fake:payload
11201     0x11/imm32/alloc-id:fake
11202     _string-break-if-<=/imm32/name
11203     0/imm32/no-inouts
11204     0/imm32/no-inouts
11205     0/imm32/no-outputs
11206     0/imm32/no-outputs
11207     0x11/imm32/alloc-id:fake
11208     _string_0f_8e_jump_break/imm32/subx-name
11209     0/imm32/no-rm32
11210     0/imm32/no-r32
11211     0/imm32/no-imm32
11212     0/imm32/no-disp32
11213     0/imm32/no-output
11214     0x11/imm32/alloc-id:fake
11215     _Primitive-break-if->/imm32/next
11216 _Primitive-break-if->:  # (payload primitive)
11217     0x11/imm32/alloc-id:fake:payload
11218     0x11/imm32/alloc-id:fake
11219     _string-break-if->/imm32/name
11220     0/imm32/no-inouts
11221     0/imm32/no-inouts
11222     0/imm32/no-outputs
11223     0/imm32/no-outputs
11224     0x11/imm32/alloc-id:fake
11225     _string_0f_8f_jump_break/imm32/subx-name
11226     0/imm32/no-rm32
11227     0/imm32/no-r32
11228     0/imm32/no-imm32
11229     0/imm32/no-disp32
11230     0/imm32/no-output
11231     0x11/imm32/alloc-id:fake
11232     _Primitive-break/imm32/next
11233 _Primitive-break:  # (payload primitive)
11234     0x11/imm32/alloc-id:fake:payload
11235     0x11/imm32/alloc-id:fake
11236     _string-break/imm32/name
11237     0/imm32/no-inouts
11238     0/imm32/no-inouts
11239     0/imm32/no-outputs
11240     0/imm32/no-outputs
11241     0x11/imm32/alloc-id:fake
11242     _string_e9_jump_break/imm32/subx-name
11243     0/imm32/no-rm32
11244     0/imm32/no-r32
11245     0/imm32/no-imm32
11246     0/imm32/no-disp32
11247     0/imm32/no-output
11248     0x11/imm32/alloc-id:fake
11249     _Primitive-loop-if-addr</imm32/next
11250 _Primitive-loop-if-addr<:  # (payload primitive)
11251     0x11/imm32/alloc-id:fake:payload
11252     0x11/imm32/alloc-id:fake
11253     _string-loop-if-addr</imm32/name
11254     0/imm32/no-inouts
11255     0/imm32/no-inouts
11256     0/imm32/no-outputs
11257     0/imm32/no-outputs
11258     0x11/imm32/alloc-id:fake
11259     _string_0f_82_jump_loop/imm32/subx-name
11260     0/imm32/no-rm32
11261     0/imm32/no-r32
11262     0/imm32/no-imm32
11263     0/imm32/no-disp32
11264     0/imm32/no-output
11265     0x11/imm32/alloc-id:fake
11266     _Primitive-loop-if-addr>=/imm32/next
11267 _Primitive-loop-if-addr>=:  # (payload primitive)
11268     0x11/imm32/alloc-id:fake:payload
11269     0x11/imm32/alloc-id:fake
11270     _string-loop-if-addr>=/imm32/name
11271     0/imm32/no-inouts
11272     0/imm32/no-inouts
11273     0/imm32/no-outputs
11274     0/imm32/no-outputs
11275     0x11/imm32/alloc-id:fake
11276     _string_0f_83_jump_loop/imm32/subx-name
11277     0/imm32/no-rm32
11278     0/imm32/no-r32
11279     0/imm32/no-imm32
11280     0/imm32/no-disp32
11281     0/imm32/no-output
11282     0x11/imm32/alloc-id:fake
11283     _Primitive-loop-if-=/imm32/next
11284 _Primitive-loop-if-=:  # (payload primitive)
11285     0x11/imm32/alloc-id:fake:payload
11286     0x11/imm32/alloc-id:fake
11287     _string-loop-if-=/imm32/name
11288     0/imm32/no-inouts
11289     0/imm32/no-inouts
11290     0/imm32/no-outputs
11291     0/imm32/no-outputs
11292     0x11/imm32/alloc-id:fake
11293     _string_0f_84_jump_loop/imm32/subx-name
11294     0/imm32/no-rm32
11295     0/imm32/no-r32
11296     0/imm32/no-imm32
11297     0/imm32/no-disp32
11298     0/imm32/no-output
11299     0x11/imm32/alloc-id:fake
11300     _Primitive-loop-if-!=/imm32/next
11301 _Primitive-loop-if-!=:  # (payload primitive)
11302     0x11/imm32/alloc-id:fake:payload
11303     0x11/imm32/alloc-id:fake
11304     _string-loop-if-!=/imm32/name
11305     0/imm32/no-inouts
11306     0/imm32/no-inouts
11307     0/imm32/no-outputs
11308     0/imm32/no-outputs
11309     0x11/imm32/alloc-id:fake
11310     _string_0f_85_jump_loop/imm32/subx-name
11311     0/imm32/no-rm32
11312     0/imm32/no-r32
11313     0/imm32/no-imm32
11314     0/imm32/no-disp32
11315     0/imm32/no-output
11316     0x11/imm32/alloc-id:fake
11317     _Primitive-loop-if-addr<=/imm32/next
11318 _Primitive-loop-if-addr<=:  # (payload primitive)
11319     0x11/imm32/alloc-id:fake:payload
11320     0x11/imm32/alloc-id:fake
11321     _string-loop-if-addr<=/imm32/name
11322     0/imm32/no-inouts
11323     0/imm32/no-inouts
11324     0/imm32/no-outputs
11325     0/imm32/no-outputs
11326     0x11/imm32/alloc-id:fake
11327     _string_0f_86_jump_loop/imm32/subx-name
11328     0/imm32/no-rm32
11329     0/imm32/no-r32
11330     0/imm32/no-imm32
11331     0/imm32/no-disp32
11332     0/imm32/no-output
11333     0x11/imm32/alloc-id:fake
11334     _Primitive-loop-if-addr>/imm32/next
11335 _Primitive-loop-if-addr>:  # (payload primitive)
11336     0x11/imm32/alloc-id:fake:payload
11337     0x11/imm32/alloc-id:fake
11338     _string-loop-if-addr>/imm32/name
11339     0/imm32/no-inouts
11340     0/imm32/no-inouts
11341     0/imm32/no-outputs
11342     0/imm32/no-outputs
11343     0x11/imm32/alloc-id:fake
11344     _string_0f_87_jump_loop/imm32/subx-name
11345     0/imm32/no-rm32
11346     0/imm32/no-r32
11347     0/imm32/no-imm32
11348     0/imm32/no-disp32
11349     0/imm32/no-output
11350     0x11/imm32/alloc-id:fake
11351     _Primitive-loop-if-</imm32/next
11352 _Primitive-loop-if-<:  # (payload primitive)
11353     0x11/imm32/alloc-id:fake:payload
11354     0x11/imm32/alloc-id:fake
11355     _string-loop-if-</imm32/name
11356     0/imm32/no-inouts
11357     0/imm32/no-inouts
11358     0/imm32/no-outputs
11359     0/imm32/no-outputs
11360     0x11/imm32/alloc-id:fake
11361     _string_0f_8c_jump_loop/imm32/subx-name
11362     0/imm32/no-rm32
11363     0/imm32/no-r32
11364     0/imm32/no-imm32
11365     0/imm32/no-disp32
11366     0/imm32/no-output
11367     0x11/imm32/alloc-id:fake
11368     _Primitive-loop-if->=/imm32/next
11369 _Primitive-loop-if->=:  # (payload primitive)
11370     0x11/imm32/alloc-id:fake:payload
11371     0x11/imm32/alloc-id:fake
11372     _string-loop-if->=/imm32/name
11373     0/imm32/no-inouts
11374     0/imm32/no-inouts
11375     0/imm32/no-outputs
11376     0/imm32/no-outputs
11377     0x11/imm32/alloc-id:fake
11378     _string_0f_8d_jump_loop/imm32/subx-name
11379     0/imm32/no-rm32
11380     0/imm32/no-r32
11381     0/imm32/no-imm32
11382     0/imm32/no-disp32
11383     0/imm32/no-output
11384     0x11/imm32/alloc-id:fake
11385     _Primitive-loop-if-<=/imm32/next
11386 _Primitive-loop-if-<=:  # (payload primitive)
11387     0x11/imm32/alloc-id:fake:payload
11388     0x11/imm32/alloc-id:fake
11389     _string-loop-if-<=/imm32/name
11390     0/imm32/no-inouts
11391     0/imm32/no-inouts
11392     0/imm32/no-outputs
11393     0/imm32/no-outputs
11394     0x11/imm32/alloc-id:fake
11395     _string_0f_8e_jump_loop/imm32/subx-name
11396     0/imm32/no-rm32
11397     0/imm32/no-r32
11398     0/imm32/no-imm32
11399     0/imm32/no-disp32
11400     0/imm32/no-output
11401     0x11/imm32/alloc-id:fake
11402     _Primitive-loop-if->/imm32/next
11403 _Primitive-loop-if->:  # (payload primitive)
11404     0x11/imm32/alloc-id:fake:payload
11405     0x11/imm32/alloc-id:fake
11406     _string-loop-if->/imm32/name
11407     0/imm32/no-inouts
11408     0/imm32/no-inouts
11409     0/imm32/no-outputs
11410     0/imm32/no-outputs
11411     0x11/imm32/alloc-id:fake
11412     _string_0f_8f_jump_loop/imm32/subx-name
11413     0/imm32/no-rm32
11414     0/imm32/no-r32
11415     0/imm32/no-imm32
11416     0/imm32/no-disp32
11417     0/imm32/no-output
11418     0x11/imm32/alloc-id:fake
11419     _Primitive-loop/imm32/next  # we probably don't need an unconditional break
11420 _Primitive-loop:  # (payload primitive)
11421     0x11/imm32/alloc-id:fake:payload
11422     0x11/imm32/alloc-id:fake
11423     _string-loop/imm32/name
11424     0/imm32/no-inouts
11425     0/imm32/no-inouts
11426     0/imm32/no-outputs
11427     0/imm32/no-outputs
11428     0x11/imm32/alloc-id:fake
11429     _string_e9_jump_loop/imm32/subx-name
11430     0/imm32/no-rm32
11431     0/imm32/no-r32
11432     0/imm32/no-imm32
11433     0/imm32/no-disp32
11434     0/imm32/no-output
11435     0x11/imm32/alloc-id:fake
11436     _Primitive-break-if-addr<-named/imm32/next
11437 # - branches to named blocks
11438 _Primitive-break-if-addr<-named:  # (payload primitive)
11439     0x11/imm32/alloc-id:fake:payload
11440     0x11/imm32/alloc-id:fake
11441     _string-break-if-addr</imm32/name
11442     0x11/imm32/alloc-id:fake
11443     Single-lit-var/imm32/inouts
11444     0/imm32/no-outputs
11445     0/imm32/no-outputs
11446     0x11/imm32/alloc-id:fake
11447     _string_0f_82_jump_label/imm32/subx-name
11448     0/imm32/no-rm32
11449     0/imm32/no-r32
11450     0/imm32/no-imm32
11451     1/imm32/disp32-is-first-inout
11452     0/imm32/no-output
11453     0x11/imm32/alloc-id:fake
11454     _Primitive-break-if-addr>=-named/imm32/next
11455 _Primitive-break-if-addr>=-named:  # (payload primitive)
11456     0x11/imm32/alloc-id:fake:payload
11457     0x11/imm32/alloc-id:fake
11458     _string-break-if-addr>=/imm32/name
11459     0x11/imm32/alloc-id:fake
11460     Single-lit-var/imm32/inouts
11461     0/imm32/no-outputs
11462     0/imm32/no-outputs
11463     0x11/imm32/alloc-id:fake
11464     _string_0f_83_jump_label/imm32/subx-name
11465     0/imm32/no-rm32
11466     0/imm32/no-r32
11467     0/imm32/no-imm32
11468     1/imm32/disp32-is-first-inout
11469     0/imm32/no-output
11470     0x11/imm32/alloc-id:fake
11471     _Primitive-break-if-=-named/imm32/next
11472 _Primitive-break-if-=-named:  # (payload primitive)
11473     0x11/imm32/alloc-id:fake:payload
11474     0x11/imm32/alloc-id:fake
11475     _string-break-if-=/imm32/name
11476     0x11/imm32/alloc-id:fake
11477     Single-lit-var/imm32/inouts
11478     0/imm32/no-outputs
11479     0/imm32/no-outputs
11480     0x11/imm32/alloc-id:fake
11481     _string_0f_84_jump_label/imm32/subx-name
11482     0/imm32/no-rm32
11483     0/imm32/no-r32
11484     0/imm32/no-imm32
11485     1/imm32/disp32-is-first-inout
11486     0/imm32/no-output
11487     0x11/imm32/alloc-id:fake
11488     _Primitive-break-if-!=-named/imm32/next
11489 _Primitive-break-if-!=-named:  # (payload primitive)
11490     0x11/imm32/alloc-id:fake:payload
11491     0x11/imm32/alloc-id:fake
11492     _string-break-if-!=/imm32/name
11493     0x11/imm32/alloc-id:fake
11494     Single-lit-var/imm32/inouts
11495     0/imm32/no-outputs
11496     0/imm32/no-outputs
11497     0x11/imm32/alloc-id:fake
11498     _string_0f_85_jump_label/imm32/subx-name
11499     0/imm32/no-rm32
11500     0/imm32/no-r32
11501     0/imm32/no-imm32
11502     1/imm32/disp32-is-first-inout
11503     0/imm32/no-output
11504     0x11/imm32/alloc-id:fake
11505     _Primitive-break-if-addr<=-named/imm32/next
11506 _Primitive-break-if-addr<=-named:  # (payload primitive)
11507     0x11/imm32/alloc-id:fake:payload
11508     0x11/imm32/alloc-id:fake
11509     _string-break-if-addr<=/imm32/name
11510     0x11/imm32/alloc-id:fake
11511     Single-lit-var/imm32/inouts
11512     0/imm32/no-outputs
11513     0/imm32/no-outputs
11514     0x11/imm32/alloc-id:fake
11515     _string_0f_86_jump_label/imm32/subx-name
11516     0/imm32/no-rm32
11517     0/imm32/no-r32
11518     0/imm32/no-imm32
11519     1/imm32/disp32-is-first-inout
11520     0/imm32/no-output
11521     0x11/imm32/alloc-id:fake
11522     _Primitive-break-if-addr>-named/imm32/next
11523 _Primitive-break-if-addr>-named:  # (payload primitive)
11524     0x11/imm32/alloc-id:fake:payload
11525     0x11/imm32/alloc-id:fake
11526     _string-break-if-addr>/imm32/name
11527     0x11/imm32/alloc-id:fake
11528     Single-lit-var/imm32/inouts
11529     0/imm32/no-outputs
11530     0/imm32/no-outputs
11531     0x11/imm32/alloc-id:fake
11532     _string_0f_87_jump_label/imm32/subx-name
11533     0/imm32/no-rm32
11534     0/imm32/no-r32
11535     0/imm32/no-imm32
11536     1/imm32/disp32-is-first-inout
11537     0/imm32/no-output
11538     0x11/imm32/alloc-id:fake
11539     _Primitive-break-if-<-named/imm32/next
11540 _Primitive-break-if-<-named:  # (payload primitive)
11541     0x11/imm32/alloc-id:fake:payload
11542     0x11/imm32/alloc-id:fake
11543     _string-break-if-</imm32/name
11544     0x11/imm32/alloc-id:fake
11545     Single-lit-var/imm32/inouts
11546     0/imm32/no-outputs
11547     0/imm32/no-outputs
11548     0x11/imm32/alloc-id:fake
11549     _string_0f_8c_jump_label/imm32/subx-name
11550     0/imm32/no-rm32
11551     0/imm32/no-r32
11552     0/imm32/no-imm32
11553     1/imm32/disp32-is-first-inout
11554     0/imm32/no-output
11555     0x11/imm32/alloc-id:fake
11556     _Primitive-break-if->=-named/imm32/next
11557 _Primitive-break-if->=-named:  # (payload primitive)
11558     0x11/imm32/alloc-id:fake:payload
11559     0x11/imm32/alloc-id:fake
11560     _string-break-if->=/imm32/name
11561     0x11/imm32/alloc-id:fake
11562     Single-lit-var/imm32/inouts
11563     0/imm32/no-outputs
11564     0/imm32/no-outputs
11565     0x11/imm32/alloc-id:fake
11566     _string_0f_8d_jump_label/imm32/subx-name
11567     0/imm32/no-rm32
11568     0/imm32/no-r32
11569     0/imm32/no-imm32
11570     1/imm32/disp32-is-first-inout
11571     0/imm32/no-output
11572     0x11/imm32/alloc-id:fake
11573     _Primitive-break-if-<=-named/imm32/next
11574 _Primitive-break-if-<=-named:  # (payload primitive)
11575     0x11/imm32/alloc-id:fake:payload
11576     0x11/imm32/alloc-id:fake
11577     _string-break-if-<=/imm32/name
11578     0x11/imm32/alloc-id:fake
11579     Single-lit-var/imm32/inouts
11580     0/imm32/no-outputs
11581     0/imm32/no-outputs
11582     0x11/imm32/alloc-id:fake
11583     _string_0f_8e_jump_label/imm32/subx-name
11584     0/imm32/no-rm32
11585     0/imm32/no-r32
11586     0/imm32/no-imm32
11587     1/imm32/disp32-is-first-inout
11588     0/imm32/no-output
11589     0x11/imm32/alloc-id:fake
11590     _Primitive-break-if->-named/imm32/next
11591 _Primitive-break-if->-named:  # (payload primitive)
11592     0x11/imm32/alloc-id:fake:payload
11593     0x11/imm32/alloc-id:fake
11594     _string-break-if->/imm32/name
11595     0x11/imm32/alloc-id:fake
11596     Single-lit-var/imm32/inouts
11597     0/imm32/no-outputs
11598     0/imm32/no-outputs
11599     0x11/imm32/alloc-id:fake
11600     _string_0f_8f_jump_label/imm32/subx-name
11601     0/imm32/no-rm32
11602     0/imm32/no-r32
11603     0/imm32/no-imm32
11604     1/imm32/disp32-is-first-inout
11605     0/imm32/no-output
11606     0x11/imm32/alloc-id:fake
11607     _Primitive-break-named/imm32/next
11608 _Primitive-break-named:  # (payload primitive)
11609     0x11/imm32/alloc-id:fake:payload
11610     0x11/imm32/alloc-id:fake
11611     _string-break/imm32/name
11612     0x11/imm32/alloc-id:fake
11613     Single-lit-var/imm32/inouts
11614     0/imm32/no-outputs
11615     0/imm32/no-outputs
11616     0x11/imm32/alloc-id:fake
11617     _string_e9_jump_label/imm32/subx-name
11618     0/imm32/no-rm32
11619     0/imm32/no-r32
11620     0/imm32/no-imm32
11621     1/imm32/disp32-is-first-inout
11622     0/imm32/no-output
11623     0x11/imm32/alloc-id:fake
11624     _Primitive-loop-if-addr<-named/imm32/next
11625 _Primitive-loop-if-addr<-named:  # (payload primitive)
11626     0x11/imm32/alloc-id:fake:payload
11627     0x11/imm32/alloc-id:fake
11628     _string-loop-if-addr</imm32/name
11629     0x11/imm32/alloc-id:fake
11630     Single-lit-var/imm32/inouts
11631     0/imm32/no-outputs
11632     0/imm32/no-outputs
11633     0x11/imm32/alloc-id:fake
11634     _string_0f_82_jump_label/imm32/subx-name
11635     0/imm32/no-rm32
11636     0/imm32/no-r32
11637     0/imm32/no-imm32
11638     1/imm32/disp32-is-first-inout
11639     0/imm32/no-output
11640     0x11/imm32/alloc-id:fake
11641     _Primitive-loop-if-addr>=-named/imm32/next
11642 _Primitive-loop-if-addr>=-named:  # (payload primitive)
11643     0x11/imm32/alloc-id:fake:payload
11644     0x11/imm32/alloc-id:fake
11645     _string-loop-if-addr>=/imm32/name
11646     0x11/imm32/alloc-id:fake
11647     Single-lit-var/imm32/inouts
11648     0/imm32/no-outputs
11649     0/imm32/no-outputs
11650     0x11/imm32/alloc-id:fake
11651     _string_0f_83_jump_label/imm32/subx-name
11652     0/imm32/no-rm32
11653     0/imm32/no-r32
11654     0/imm32/no-imm32
11655     1/imm32/disp32-is-first-inout
11656     0/imm32/no-output
11657     0x11/imm32/alloc-id:fake
11658     _Primitive-loop-if-=-named/imm32/next
11659 _Primitive-loop-if-=-named:  # (payload primitive)
11660     0x11/imm32/alloc-id:fake:payload
11661     0x11/imm32/alloc-id:fake
11662     _string-loop-if-=/imm32/name
11663     0x11/imm32/alloc-id:fake
11664     Single-lit-var/imm32/inouts
11665     0/imm32/no-outputs
11666     0/imm32/no-outputs
11667     0x11/imm32/alloc-id:fake
11668     _string_0f_84_jump_label/imm32/subx-name
11669     0/imm32/no-rm32
11670     0/imm32/no-r32
11671     0/imm32/no-imm32
11672     1/imm32/disp32-is-first-inout
11673     0/imm32/no-output
11674     0x11/imm32/alloc-id:fake
11675     _Primitive-loop-if-!=-named/imm32/next
11676 _Primitive-loop-if-!=-named:  # (payload primitive)
11677     0x11/imm32/alloc-id:fake:payload
11678     0x11/imm32/alloc-id:fake
11679     _string-loop-if-!=/imm32/name
11680     0x11/imm32/alloc-id:fake
11681     Single-lit-var/imm32/inouts
11682     0/imm32/no-outputs
11683     0/imm32/no-outputs
11684     0x11/imm32/alloc-id:fake
11685     _string_0f_85_jump_label/imm32/subx-name
11686     0/imm32/no-rm32
11687     0/imm32/no-r32
11688     0/imm32/no-imm32
11689     1/imm32/disp32-is-first-inout
11690     0/imm32/no-output
11691     0x11/imm32/alloc-id:fake
11692     _Primitive-loop-if-addr<=-named/imm32/next
11693 _Primitive-loop-if-addr<=-named:  # (payload primitive)
11694     0x11/imm32/alloc-id:fake:payload
11695     0x11/imm32/alloc-id:fake
11696     _string-loop-if-addr<=/imm32/name
11697     0x11/imm32/alloc-id:fake
11698     Single-lit-var/imm32/inouts
11699     0/imm32/no-outputs
11700     0/imm32/no-outputs
11701     0x11/imm32/alloc-id:fake
11702     _string_0f_86_jump_label/imm32/subx-name
11703     0/imm32/no-rm32
11704     0/imm32/no-r32
11705     0/imm32/no-imm32
11706     1/imm32/disp32-is-first-inout
11707     0/imm32/no-output
11708     0x11/imm32/alloc-id:fake
11709     _Primitive-loop-if-addr>-named/imm32/next
11710 _Primitive-loop-if-addr>-named:  # (payload primitive)
11711     0x11/imm32/alloc-id:fake:payload
11712     0x11/imm32/alloc-id:fake
11713     _string-loop-if-addr>/imm32/name
11714     0x11/imm32/alloc-id:fake
11715     Single-lit-var/imm32/inouts
11716     0/imm32/no-outputs
11717     0/imm32/no-outputs
11718     0x11/imm32/alloc-id:fake
11719     _string_0f_87_jump_label/imm32/subx-name
11720     0/imm32/no-rm32
11721     0/imm32/no-r32
11722     0/imm32/no-imm32
11723     1/imm32/disp32-is-first-inout
11724     0/imm32/no-output
11725     0x11/imm32/alloc-id:fake
11726     _Primitive-loop-if-<-named/imm32/next
11727 _Primitive-loop-if-<-named:  # (payload primitive)
11728     0x11/imm32/alloc-id:fake:payload
11729     0x11/imm32/alloc-id:fake
11730     _string-loop-if-</imm32/name
11731     0x11/imm32/alloc-id:fake
11732     Single-lit-var/imm32/inouts
11733     0/imm32/no-outputs
11734     0/imm32/no-outputs
11735     0x11/imm32/alloc-id:fake
11736     _string_0f_8c_jump_label/imm32/subx-name
11737     0/imm32/no-rm32
11738     0/imm32/no-r32
11739     0/imm32/no-imm32
11740     1/imm32/disp32-is-first-inout
11741     0/imm32/no-output
11742     0x11/imm32/alloc-id:fake
11743     _Primitive-loop-if->=-named/imm32/next
11744 _Primitive-loop-if->=-named:  # (payload primitive)
11745     0x11/imm32/alloc-id:fake:payload
11746     0x11/imm32/alloc-id:fake
11747     _string-loop-if->=/imm32/name
11748     0x11/imm32/alloc-id:fake
11749     Single-lit-var/imm32/inouts
11750     0/imm32/no-outputs
11751     0/imm32/no-outputs
11752     0x11/imm32/alloc-id:fake
11753     _string_0f_8d_jump_label/imm32/subx-name
11754     0/imm32/no-rm32
11755     0/imm32/no-r32
11756     0/imm32/no-imm32
11757     1/imm32/disp32-is-first-inout
11758     0/imm32/no-output
11759     0x11/imm32/alloc-id:fake
11760     _Primitive-loop-if-<=-named/imm32/next
11761 _Primitive-loop-if-<=-named:  # (payload primitive)
11762     0x11/imm32/alloc-id:fake:payload
11763     0x11/imm32/alloc-id:fake
11764     _string-loop-if-<=/imm32/name
11765     0x11/imm32/alloc-id:fake
11766     Single-lit-var/imm32/inouts
11767     0/imm32/no-outputs
11768     0/imm32/no-outputs
11769     0x11/imm32/alloc-id:fake
11770     _string_0f_8e_jump_label/imm32/subx-name
11771     0/imm32/no-rm32
11772     0/imm32/no-r32
11773     0/imm32/no-imm32
11774     1/imm32/disp32-is-first-inout
11775     0/imm32/no-output
11776     0x11/imm32/alloc-id:fake
11777     _Primitive-loop-if->-named/imm32/next
11778 _Primitive-loop-if->-named:  # (payload primitive)
11779     0x11/imm32/alloc-id:fake:payload
11780     0x11/imm32/alloc-id:fake
11781     _string-loop-if->/imm32/name
11782     0x11/imm32/alloc-id:fake
11783     Single-lit-var/imm32/inouts
11784     0/imm32/no-outputs
11785     0/imm32/no-outputs
11786     0x11/imm32/alloc-id:fake
11787     _string_0f_8f_jump_label/imm32/subx-name
11788     0/imm32/no-rm32
11789     0/imm32/no-r32
11790     0/imm32/no-imm32
11791     1/imm32/disp32-is-first-inout
11792     0/imm32/no-output
11793     0x11/imm32/alloc-id:fake
11794     _Primitive-loop-named/imm32/next  # we probably don't need an unconditional break
11795 _Primitive-loop-named:  # (payload primitive)
11796     0x11/imm32/alloc-id:fake:payload
11797     0x11/imm32/alloc-id:fake
11798     _string-loop/imm32/name
11799     0x11/imm32/alloc-id:fake
11800     Single-lit-var/imm32/inouts
11801     0/imm32/no-outputs
11802     0/imm32/no-outputs
11803     0x11/imm32/alloc-id:fake
11804     _string_e9_jump_label/imm32/subx-name
11805     0/imm32/no-rm32
11806     0/imm32/no-r32
11807     0/imm32/no-imm32
11808     1/imm32/disp32-is-first-inout
11809     0/imm32/no-output
11810     0/imm32/next
11811     0/imm32/next
11812 
11813 # string literals for Mu instructions
11814 _string-add:  # (payload array byte)
11815     0x11/imm32/alloc-id:fake:payload
11816     # "add"
11817     0x3/imm32/size
11818     0x61/a 0x64/d 0x64/d
11819 _string-address:  # (payload array byte)
11820     0x11/imm32/alloc-id:fake:payload
11821     # "address"
11822     0x7/imm32/size
11823     0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
11824 _string-add-to:  # (payload array byte)
11825     0x11/imm32/alloc-id:fake:payload
11826     # "add-to"
11827     0x6/imm32/size
11828     0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
11829 _string-and:  # (payload array byte)
11830     0x11/imm32/alloc-id:fake:payload
11831     # "and"
11832     0x3/imm32/size
11833     0x61/a 0x6e/n 0x64/d
11834 _string-and-with:  # (payload array byte)
11835     0x11/imm32/alloc-id:fake:payload
11836     # "and-with"
11837     0x8/imm32/size
11838     0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
11839 _string-break:  # (payload array byte)
11840     0x11/imm32/alloc-id:fake:payload
11841     # "break"
11842     0x5/imm32/size
11843     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k
11844 _string-break-if-<:  # (payload array byte)
11845     0x11/imm32/alloc-id:fake:payload
11846     # "break-if-<"
11847     0xa/imm32/size
11848     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
11849 _string-break-if-<=:  # (payload array byte)
11850     0x11/imm32/alloc-id:fake:payload
11851     # "break-if-<="
11852     0xb/imm32/size
11853     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
11854 _string-break-if-=:  # (payload array byte)
11855     0x11/imm32/alloc-id:fake:payload
11856     # "break-if-="
11857     0xa/imm32/size
11858     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
11859 _string-break-if->:  # (payload array byte)
11860     0x11/imm32/alloc-id:fake:payload
11861     # "break-if->"
11862     0xa/imm32/size
11863     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
11864 _string-break-if->=:  # (payload array byte)
11865     0x11/imm32/alloc-id:fake:payload
11866     # "break-if->="
11867     0xb/imm32/size
11868     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
11869 _string-break-if-!=:  # (payload array byte)
11870     0x11/imm32/alloc-id:fake:payload
11871     # "break-if-!="
11872     0xb/imm32/size
11873     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
11874 _string-break-if-addr<:  # (payload array byte)
11875     0x11/imm32/alloc-id:fake:payload
11876     # "break-if-addr<"
11877     0xe/imm32/size
11878     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 0x3c/<
11879 _string-break-if-addr<=:  # (payload array byte)
11880     0x11/imm32/alloc-id:fake:payload
11881     # "break-if-addr<="
11882     0xf/imm32/size
11883     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 0x3c/< 0x3d/=
11884 _string-break-if-addr>:  # (payload array byte)
11885     0x11/imm32/alloc-id:fake:payload
11886     # "break-if-addr>"
11887     0xe/imm32/size
11888     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/>
11889 _string-break-if-addr>=:  # (payload array byte)
11890     0x11/imm32/alloc-id:fake:payload
11891     # "break-if-addr>="
11892     0xf/imm32/size
11893     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/=
11894 _string-compare:  # (payload array byte)
11895     0x11/imm32/alloc-id:fake:payload
11896     # "compare"
11897     0x7/imm32/size
11898     0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
11899 _string-copy:  # (payload array byte)
11900     0x11/imm32/alloc-id:fake:payload
11901     # "copy"
11902     0x4/imm32/size
11903     0x63/c 0x6f/o 0x70/p 0x79/y
11904 _string-copy-to:  # (payload array byte)
11905     0x11/imm32/alloc-id:fake:payload
11906     # "copy-to"
11907     0x7/imm32/size
11908     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o
11909 _string-decrement:  # (payload array byte)
11910     0x11/imm32/alloc-id:fake:payload
11911     # "decrement"
11912     0x9/imm32/size
11913     0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
11914 _string-increment:  # (payload array byte)
11915     0x11/imm32/alloc-id:fake:payload
11916     # "increment"
11917     0x9/imm32/size
11918     0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
11919 _string-loop:  # (payload array byte)
11920     0x11/imm32/alloc-id:fake:payload
11921     # "loop"
11922     0x4/imm32/size
11923     0x6c/l 0x6f/o 0x6f/o 0x70/p
11924 _string-loop-if-<:  # (payload array byte)
11925     0x11/imm32/alloc-id:fake:payload
11926     # "loop-if-<"
11927     0x9/imm32/size
11928     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
11929 _string-loop-if-<=:  # (payload array byte)
11930     0x11/imm32/alloc-id:fake:payload
11931     # "loop-if-<="
11932     0xa/imm32/size
11933     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
11934 _string-loop-if-=:  # (payload array byte)
11935     0x11/imm32/alloc-id:fake:payload
11936     # "loop-if-="
11937     0x9/imm32/size
11938     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
11939 _string-loop-if->:  # (payload array byte)
11940     0x11/imm32/alloc-id:fake:payload
11941     # "loop-if->"
11942     0x9/imm32/size
11943     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
11944 _string-loop-if->=:  # (payload array byte)
11945     0x11/imm32/alloc-id:fake:payload
11946     # "loop-if->="
11947     0xa/imm32/size
11948     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
11949 _string-loop-if-!=:  # (payload array byte)
11950     0x11/imm32/alloc-id:fake:payload
11951     # "loop-if-!="
11952     0xa/imm32/size
11953     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
11954 _string-loop-if-addr<:  # (payload array byte)
11955     0x11/imm32/alloc-id:fake:payload
11956     # "loop-if-addr<"
11957     0xd/imm32/size
11958     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/<
11959 _string-loop-if-addr<=:  # (payload array byte)
11960     0x11/imm32/alloc-id:fake:payload
11961     # "loop-if-addr<="
11962     0xe/imm32/size
11963     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x3d/=
11964 _string-loop-if-addr>:  # (payload array byte)
11965     0x11/imm32/alloc-id:fake:payload
11966     # "loop-if-addr>"
11967     0xd/imm32/size
11968     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/>
11969 _string-loop-if-addr>=:  # (payload array byte)
11970     0x11/imm32/alloc-id:fake:payload
11971     # "loop-if-addr>="
11972     0xe/imm32/size
11973     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/=
11974 _string-multiply:  # (payload array byte)
11975     0x11/imm32/alloc-id:fake:payload
11976     # "multiply"
11977     0x8/imm32/size
11978     0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
11979 _string-or:  # (payload array byte)
11980     0x11/imm32/alloc-id:fake:payload
11981     # "or"
11982     0x2/imm32/size
11983     0x6f/o 0x72/r
11984 _string-or-with:  # (payload array byte)
11985     0x11/imm32/alloc-id:fake:payload
11986     # "or-with"
11987     0x7/imm32/size
11988     0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
11989 _string-subtract:  # (payload array byte)
11990     0x11/imm32/alloc-id:fake:payload
11991     # "subtract"
11992     0x8/imm32/size
11993     0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
11994 _string-subtract-from:  # (payload array byte)
11995     0x11/imm32/alloc-id:fake:payload
11996     # "subtract-from"
11997     0xd/imm32/size
11998     0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t 0x2d/dash 0x66/f 0x72/r 0x6f/o 0x6d/m
11999 _string-xor:  # (payload array byte)
12000     0x11/imm32/alloc-id:fake:payload
12001     # "xor"
12002     0x3/imm32/size
12003     0x78/x 0x6f/o 0x72/r
12004 _string-xor-with:  # (payload array byte)
12005     0x11/imm32/alloc-id:fake:payload
12006     # "xor-with"
12007     0x8/imm32/size
12008     0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
12009 
12010 # string literals for SubX instructions
12011 _string_01_add_to:  # (payload array byte)
12012     0x11/imm32/alloc-id:fake:payload
12013     # "01/add-to"
12014     0x9/imm32/size
12015     0x30/0 0x31/1 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
12016 _string_03_add:  # (payload array byte)
12017     0x11/imm32/alloc-id:fake:payload
12018     # "03/add"
12019     0x6/imm32/size
12020     0x30/0 0x33/3 0x2f/slash 0x61/a 0x64/d 0x64/d
12021 _string_05_add_to_eax:  # (payload array byte)
12022     0x11/imm32/alloc-id:fake:payload
12023     # "05/add-to-eax"
12024     0xd/imm32/size
12025     0x30/0 0x35/5 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x61/a 0x78/x
12026 _string_09_or_with:  # (payload array byte)
12027     0x11/imm32/alloc-id:fake:payload
12028     # "09/or-with"
12029     0xa/imm32/size
12030     0x30/0 0x39/9 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
12031 _string_0b_or:  # (payload array byte)
12032     0x11/imm32/alloc-id:fake:payload
12033     # "0b/or"
12034     0x5/imm32/size
12035     0x30/0 0x62/b 0x2f/slash 0x6f/o 0x72/r
12036 _string_0d_or_with_eax:  # (payload array byte)
12037     0x11/imm32/alloc-id:fake:payload
12038     # "0d/or-with-eax"
12039     0xe/imm32/size
12040     0x30/0 0x64/d 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h 0x2d/dash 0x65/e 0x61/a 0x78/x
12041 _string_0f_82_jump_label:  # (payload array byte)
12042     0x11/imm32/alloc-id:fake:payload
12043     # "0f 82/jump-if-addr<"
12044     0x13/imm32/size
12045     0x30/0 0x66/f 0x20/space 0x38/8 0x32/2 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/<
12046 _string_0f_82_jump_break:  # (payload array byte)
12047     0x11/imm32/alloc-id:fake:payload
12048     # "0f 82/jump-if-addr< break/disp32"
12049     0x20/imm32/size
12050     0x30/0 0x66/f 0x20/space 0x38/8 0x32/2 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12051 _string_0f_82_jump_loop:  # (payload array byte)
12052     0x11/imm32/alloc-id:fake:payload
12053     # "0f 82/jump-if-addr< loop/disp32"
12054     0x1f/imm32/size
12055     0x30/0 0x66/f 0x20/space 0x38/8 0x32/2 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12056 _string_0f_83_jump_label:  # (payload array byte)
12057     0x11/imm32/alloc-id:fake:payload
12058     # "0f 83/jump-if-addr>="
12059     0x14/imm32/size
12060     0x30/0 0x66/f 0x20/space 0x38/8 0x33/3 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x3d/=
12061 _string_0f_83_jump_break:  # (payload array byte)
12062     0x11/imm32/alloc-id:fake:payload
12063     # "0f 83/jump-if-addr>= break/disp32"
12064     0x21/imm32/size
12065     0x30/0 0x66/f 0x20/space 0x38/8 0x33/3 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12066 _string_0f_83_jump_loop:  # (payload array byte)
12067     0x11/imm32/alloc-id:fake:payload
12068     # "0f 83/jump-if-addr>= loop/disp32"
12069     0x20/imm32/size
12070     0x30/0 0x66/f 0x20/space 0x38/8 0x33/3 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x3d/= 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12071 _string_0f_84_jump_label:  # (payload array byte)
12072     0x11/imm32/alloc-id:fake:payload
12073     # "0f 84/jump-if-="
12074     0xf/imm32/size
12075     0x30/0 0x66/f 0x20/space 0x38/8 0x34/4 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
12076 _string_0f_84_jump_break:  # (payload array byte)
12077     0x11/imm32/alloc-id:fake:payload
12078     # "0f 84/jump-if-= break/disp32"
12079     0x1c/imm32/size
12080     0x30/0 0x66/f 0x20/space 0x38/8 0x34/4 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12081 _string_0f_84_jump_loop:  # (payload array byte)
12082     0x11/imm32/alloc-id:fake:payload
12083     # "0f 84/jump-if-= loop/disp32"
12084     0x1b/imm32/size
12085     0x30/0 0x66/f 0x20/space 0x38/8 0x34/4 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/= 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12086 _string_0f_85_jump_label:  # (payload array byte)
12087     0x11/imm32/alloc-id:fake:payload
12088     # "0f 85/jump-if-!="
12089     0x10/imm32/size
12090     0x30/0 0x66/f 0x20/space 0x38/8 0x35/5 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
12091 _string_0f_85_jump_break:  # (payload array byte)
12092     0x11/imm32/alloc-id:fake:payload
12093     # "0f 85/jump-if-!= break/disp32"
12094     0x1d/imm32/size
12095     0x30/0 0x66/f 0x20/space 0x38/8 0x35/5 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12096 _string_0f_85_jump_loop:  # (payload array byte)
12097     0x11/imm32/alloc-id:fake:payload
12098     # "0f 85/jump-if-!= loop/disp32"
12099     0x1c/imm32/size
12100     0x30/0 0x66/f 0x20/space 0x38/8 0x35/5 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/= 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12101 _string_0f_86_jump_label:  # (payload array byte)
12102     0x11/imm32/alloc-id:fake:payload
12103     # "0f 86/jump-if-addr<="
12104     0x14/imm32/size
12105     0x30/0 0x66/f 0x20/space 0x38/8 0x36/6 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x3d/=
12106 _string_0f_86_jump_break:  # (payload array byte)
12107     0x11/imm32/alloc-id:fake:payload
12108     # "0f 86/jump-if-addr<= break/disp32"
12109     0x21/imm32/size
12110     0x30/0 0x66/f 0x20/space 0x38/8 0x36/6 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12111 _string_0f_86_jump_loop:  # (payload array byte)
12112     0x11/imm32/alloc-id:fake:payload
12113     # "0f 86/jump-if-addr<= loop/disp32"
12114     0x20/imm32/size
12115     0x30/0 0x66/f 0x20/space 0x38/8 0x36/6 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x3d/= 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12116 _string_0f_87_jump_label:  # (payload array byte)
12117     0x11/imm32/alloc-id:fake:payload
12118     # "0f 87/jump-if-addr>"
12119     0x13/imm32/size
12120     0x30/0 0x66/f 0x20/space 0x38/8 0x37/7 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/>
12121 _string_0f_87_jump_break:  # (payload array byte)
12122     0x11/imm32/alloc-id:fake:payload
12123     # "0f 87/jump-if-addr> break/disp32"
12124     0x20/imm32/size
12125     0x30/0 0x66/f 0x20/space 0x38/8 0x37/7 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12126 _string_0f_87_jump_loop:  # (payload array byte)
12127     0x11/imm32/alloc-id:fake:payload
12128     # "0f 87/jump-if-addr> loop/disp32"
12129     0x1f/imm32/size
12130     0x30/0 0x66/f 0x20/space 0x38/8 0x37/7 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12131 _string_0f_8c_jump_label:  # (payload array byte)
12132     0x11/imm32/alloc-id:fake:payload
12133     # "0f 8c/jump-if-<"
12134     0xf/imm32/size
12135     0x30/0 0x66/f 0x20/space 0x38/8 0x63/c 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
12136 _string_0f_8c_jump_break:  # (payload array byte)
12137     0x11/imm32/alloc-id:fake:payload
12138     # "0f 8c/jump-if-< break/disp32"
12139     0x1c/imm32/size
12140     0x30/0 0x66/f 0x20/space 0x38/8 0x63/c 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12141 _string_0f_8c_jump_loop:  # (payload array byte)
12142     0x11/imm32/alloc-id:fake:payload
12143     # "0f 8c/jump-if-< loop/disp32"
12144     0x1b/imm32/size
12145     0x30/0 0x66/f 0x20/space 0x38/8 0x63/c 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12146 _string_0f_8d_jump_label:  # (payload array byte)
12147     0x11/imm32/alloc-id:fake:payload
12148     # "0f 8d/jump-if->="
12149     0x10/imm32/size
12150     0x30/0 0x66/f 0x20/space 0x38/8 0x64/d 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
12151 _string_0f_8d_jump_break:  # (payload array byte)
12152     0x11/imm32/alloc-id:fake:payload
12153     # "0f 8d/jump-if->= break/disp32"
12154     0x1d/imm32/size
12155     0x30/0 0x66/f 0x20/space 0x38/8 0x64/d 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12156 _string_0f_8d_jump_loop:  # (payload array byte)
12157     0x11/imm32/alloc-id:fake:payload
12158     # "0f 8d/jump-if->= loop/disp32"
12159     0x1c/imm32/size
12160     0x30/0 0x66/f 0x20/space 0x38/8 0x64/d 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/= 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12161 _string_0f_8e_jump_label:  # (payload array byte)
12162     0x11/imm32/alloc-id:fake:payload
12163     # "0f 8e/jump-if-<="
12164     0x10/imm32/size
12165     0x30/0 0x66/f 0x20/space 0x38/8 0x65/e 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
12166 _string_0f_8e_jump_break:  # (payload array byte)
12167     0x11/imm32/alloc-id:fake:payload
12168     # "0f 8e/jump-if-<= break/disp32"
12169     0x1d/imm32/size
12170     0x30/0 0x66/f 0x20/space 0x38/8 0x65/e 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12171 _string_0f_8e_jump_loop:  # (payload array byte)
12172     0x11/imm32/alloc-id:fake:payload
12173     # "0f 8e/jump-if-<= loop/disp32"
12174     0x1c/imm32/size
12175     0x30/0 0x66/f 0x20/space 0x38/8 0x65/e 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/= 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12176 _string_0f_8f_jump_label:  # (payload array byte)
12177     0x11/imm32/alloc-id:fake:payload
12178     # "0f 8f/jump-if->"
12179     0xf/imm32/size
12180     0x30/0 0x66/f 0x20/space 0x38/8 0x66/f 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
12181 _string_0f_8f_jump_break:  # (payload array byte)
12182     0x11/imm32/alloc-id:fake:payload
12183     # "0f 8f/jump-if-> break/disp32"
12184     0x1c/imm32/size
12185     0x30/0 0x66/f 0x20/space 0x38/8 0x66/f 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12186 _string_0f_8f_jump_loop:  # (payload array byte)
12187     0x11/imm32/alloc-id:fake:payload
12188     # "0f 8f/jump-if-> loop/disp32"
12189     0x1b/imm32/size
12190     0x30/0 0x66/f 0x20/space 0x38/8 0x66/f 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12191 _string_0f_af_multiply:  # (payload array byte)
12192     0x11/imm32/alloc-id:fake:payload
12193     # "0f af/multiply"
12194     0xe/imm32/size
12195     0x30/0 0x66/f 0x20/space 0x61/a 0x66/f 0x2f/slash 0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
12196 _string_21_and_with:  # (payload array byte)
12197     0x11/imm32/alloc-id:fake:payload
12198     # "21/and-with"
12199     0xb/imm32/size
12200     0x32/2 0x31/1 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
12201 _string_23_and:  # (payload array byte)
12202     0x11/imm32/alloc-id:fake:payload
12203     # "23/and"
12204     0x6/imm32/size
12205     0x32/2 0x33/3 0x2f/slash 0x61/a 0x6e/n 0x64/d
12206 _string_25_and_with_eax:  # (payload array byte)
12207     0x11/imm32/alloc-id:fake:payload
12208     # "25/and-with-eax"
12209     0xf/imm32/size
12210     0x32/2 0x35/5 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h 0x2d/dash 0x65/e 0x61/a 0x78/x
12211 _string_29_subtract_from:  # (payload array byte)
12212     0x11/imm32/alloc-id:fake:payload
12213     # "29/subtract-from"
12214     0x10/imm32/size
12215     0x32/2 0x39/9 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t 0x2d/dash 0x66/f 0x72/r 0x6f/o 0x6d/m
12216 _string_2b_subtract:  # (payload array byte)
12217     0x11/imm32/alloc-id:fake:payload
12218     # "2b/subtract"
12219     0xb/imm32/size
12220     0x32/2 0x62/b 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
12221 _string_2d_subtract_from_eax:  # (payload array byte)
12222     0x11/imm32/alloc-id:fake:payload
12223     # "2d/subtract-from-eax"
12224     0x14/imm32/size
12225     0x32/2 0x64/d 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t 0x2d/dash 0x66/f 0x72/r 0x6f/o 0x6d/m 0x2d/dash 0x65/e 0x61/a 0x78/x
12226 _string_31_xor_with:  # (payload array byte)
12227     0x11/imm32/alloc-id:fake:payload
12228     # "31/xor-with"
12229     0xb/imm32/size
12230     0x33/3 0x31/1 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
12231 _string_33_xor:  # (payload array byte)
12232     0x11/imm32/alloc-id:fake:payload
12233     # "33/xor"
12234     0x6/imm32/size
12235     0x33/3 0x33/3 0x2f/slash 0x78/x 0x6f/o 0x72/r
12236 _string_35_xor_with_eax:  # (payload array byte)
12237     0x11/imm32/alloc-id:fake:payload
12238     # "35/xor-with-eax"
12239     0xf/imm32/size
12240     0x33/3 0x35/5 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h 0x2d/dash 0x65/e 0x61/a 0x78/x
12241 _string_39_compare->:  # (payload array byte)
12242     0x11/imm32/alloc-id:fake:payload
12243     # "39/compare->"
12244     0xc/imm32/size
12245     0x33/3 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x3e/>
12246 _string_3b_compare<-:  # (payload array byte)
12247     0x11/imm32/alloc-id:fake:payload
12248     # "3b/compare<-"
12249     0xc/imm32/size
12250     0x33/3 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x3c/< 0x2d/dash
12251 _string_3d_compare_eax_with:  # (payload array byte)
12252     0x11/imm32/alloc-id:fake:payload
12253     # "3d/compare-eax-with"
12254     0x13/imm32/size
12255     0x33/3 0x64/d 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x65/e 0x61/a 0x78/x 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
12256 _string_40_increment_eax:  # (payload array byte)
12257     0x11/imm32/alloc-id:fake:payload
12258     # "40/increment-eax"
12259     0x10/imm32/size
12260     0x34/4 0x30/0 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x61/a 0x78/x
12261 _string_41_increment_ecx:  # (payload array byte)
12262     0x11/imm32/alloc-id:fake:payload
12263     # "41/increment-ecx"
12264     0x10/imm32/size
12265     0x34/4 0x31/1 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x63/c 0x78/x
12266 _string_42_increment_edx:  # (payload array byte)
12267     0x11/imm32/alloc-id:fake:payload
12268     # "42/increment-edx"
12269     0x10/imm32/size
12270     0x34/4 0x32/2 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x64/d 0x78/x
12271 _string_43_increment_ebx:  # (payload array byte)
12272     0x11/imm32/alloc-id:fake:payload
12273     # "43/increment-ebx"
12274     0x10/imm32/size
12275     0x34/4 0x33/3 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x62/b 0x78/x
12276 _string_46_increment_esi:  # (payload array byte)
12277     0x11/imm32/alloc-id:fake:payload
12278     # "46/increment-esi"
12279     0x10/imm32/size
12280     0x34/4 0x36/6 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x73/s 0x69/i
12281 _string_47_increment_edi:  # (payload array byte)
12282     0x11/imm32/alloc-id:fake:payload
12283     # "47/increment-edi"
12284     0x10/imm32/size
12285     0x34/4 0x37/7 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x64/d 0x69/i
12286 _string_48_decrement_eax:  # (payload array byte)
12287     0x11/imm32/alloc-id:fake:payload
12288     # "48/decrement-eax"
12289     0x10/imm32/size
12290     0x34/4 0x38/8 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x61/a 0x78/x
12291 _string_49_decrement_ecx:  # (payload array byte)
12292     0x11/imm32/alloc-id:fake:payload
12293     # "49/decrement-ecx"
12294     0x10/imm32/size
12295     0x34/4 0x39/9 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x63/c 0x78/x
12296 _string_4a_decrement_edx:  # (payload array byte)
12297     0x11/imm32/alloc-id:fake:payload
12298     # "4a/decrement-edx"
12299     0x10/imm32/size
12300     0x34/4 0x61/a 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x64/d 0x78/x
12301 _string_4b_decrement_ebx:  # (payload array byte)
12302     0x11/imm32/alloc-id:fake:payload
12303     # "4b/decrement-ebx"
12304     0x10/imm32/size
12305     0x34/4 0x62/b 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x62/b 0x78/x
12306 _string_4e_decrement_esi:  # (payload array byte)
12307     0x11/imm32/alloc-id:fake:payload
12308     # "4e/decrement-esi"
12309     0x10/imm32/size
12310     0x34/4 0x65/e 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x73/s 0x69/i
12311 _string_4f_decrement_edi:  # (payload array byte)
12312     0x11/imm32/alloc-id:fake:payload
12313     # "4f/decrement-edi"
12314     0x10/imm32/size
12315     0x34/4 0x66/f 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x64/d 0x69/i
12316 _string_81_subop_add:  # (payload array byte)
12317     0x11/imm32/alloc-id:fake:payload
12318     # "81 0/subop/add"
12319     0xe/imm32/size
12320     0x38/8 0x31/1 0x20/space 0x30/0 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x61/a 0x64/d 0x64/d
12321 _string_81_subop_or:  # (payload array byte)
12322     0x11/imm32/alloc-id:fake:payload
12323     # "81 1/subop/or"
12324     0xd/imm32/size
12325     0x38/8 0x31/1 0x20/space 0x31/1 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x6f/o 0x72/r
12326 _string_81_subop_and:  # (payload array byte)
12327     0x11/imm32/alloc-id:fake:payload
12328     # "81 4/subop/and"
12329     0xe/imm32/size
12330     0x38/8 0x31/1 0x20/space 0x34/4 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x61/a 0x6e/n 0x64/d
12331 _string_81_subop_subtract:  # (payload array byte)
12332     0x11/imm32/alloc-id:fake:payload
12333     # "81 5/subop/subtract"
12334     0x13/imm32/size
12335     0x38/8 0x31/1 0x20/space 0x35/5 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
12336 _string_81_subop_xor:  # (payload array byte)
12337     0x11/imm32/alloc-id:fake:payload
12338     # "81 6/subop/xor"
12339     0xe/imm32/size
12340     0x38/8 0x31/1 0x20/space 0x36/6 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x78/x 0x6f/o 0x72/r
12341 _string_81_subop_compare:  # (payload array byte)
12342     0x11/imm32/alloc-id:fake:payload
12343     # "81 7/subop/compare"
12344     0x12/imm32/size
12345     0x38/8 0x31/1 0x20/space 0x37/7 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
12346 _string_89_<-:  # (payload array byte)
12347     0x11/imm32/alloc-id:fake:payload
12348     # "89/<-"
12349     0x5/imm32/size
12350     0x38/8 0x39/9 0x2f/slash 0x3c/< 0x2d/dash
12351 _string_8b_->:  # (payload array byte)
12352     0x11/imm32/alloc-id:fake:payload
12353     # "8b/->"
12354     0x5/imm32/size
12355     0x38/8 0x62/b 0x2f/slash 0x2d/dash 0x3e/>
12356 _string_8d_copy_address:  # (payload array byte)
12357     0x11/imm32/alloc-id:fake:payload
12358     # "8d/copy-address"
12359     0xf/imm32/size
12360     0x38/8 0x64/d 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
12361 _string_b8_copy_to_eax:  # (payload array byte)
12362     0x11/imm32/alloc-id:fake:payload
12363     # "b8/copy-to-eax"
12364     0xe/imm32/size
12365     0x62/b 0x38/8 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x61/a 0x78/x
12366 _string_b9_copy_to_ecx:  # (payload array byte)
12367     0x11/imm32/alloc-id:fake:payload
12368     # "b9/copy-to-ecx"
12369     0xe/imm32/size
12370     0x62/b 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x63/c 0x78/x
12371 _string_ba_copy_to_edx:  # (payload array byte)
12372     0x11/imm32/alloc-id:fake:payload
12373     # "ba/copy-to-edx"
12374     0xe/imm32/size
12375     0x62/b 0x61/a 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x64/d 0x78/x
12376 _string_bb_copy_to_ebx:  # (payload array byte)
12377     0x11/imm32/alloc-id:fake:payload
12378     # "bb/copy-to-ebx"
12379     0xe/imm32/size
12380     0x62/b 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x62/b 0x78/x
12381 _string_be_copy_to_esi:  # (payload array byte)
12382     0x11/imm32/alloc-id:fake:payload
12383     # "be/copy-to-esi"
12384     0xe/imm32/size
12385     0x62/b 0x65/e 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x73/s 0x69/i
12386 _string_bf_copy_to_edi:  # (payload array byte)
12387     0x11/imm32/alloc-id:fake:payload
12388     # "bf/copy-to-edi"
12389     0xe/imm32/size
12390     0x62/b 0x66/f 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x64/d 0x69/i
12391 _string_c7_subop_copy:  # (payload array byte)
12392     0x11/imm32/alloc-id:fake:payload
12393     # "c7 0/subop/copy"
12394     0xf/imm32/size
12395     0x63/c 0x37/7 0x20/space 0x30/0 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y
12396 _string_e9_jump_label:  # (payload array byte)
12397     0x11/imm32/alloc-id:fake:payload
12398     # "e9/jump"
12399     0x7/imm32/size
12400     0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p
12401 _string_e9_jump_break:  # (payload array byte)
12402     0x11/imm32/alloc-id:fake:payload
12403     # "e9/jump break/disp32"
12404     0x14/imm32/size
12405     0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12406 _string_e9_jump_loop:  # (payload array byte)
12407     0x11/imm32/alloc-id:fake:payload
12408     # "e9/jump loop/disp32"
12409     0x13/imm32/size
12410     0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
12411 _string_ff_subop_increment:  # (payload array byte)
12412     0x11/imm32/alloc-id:fake:payload
12413     # "ff 0/subop/increment"
12414     0x14/imm32/size
12415     0x66/f 0x66/f 0x20/space 0x30/0 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
12416 _string_ff_subop_decrement:  # (payload array byte)
12417     0x11/imm32/alloc-id:fake:payload
12418     # "ff 1/subop/decrement"
12419     0x14/imm32/size
12420     0x66/f 0x66/f 0x31/1 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
12421 
12422 Single-int-var-in-mem:  # (payload list var)
12423     0x11/imm32/alloc-id:fake:payload
12424     0x11/imm32/alloc-id:fake
12425     Int-var-in-mem/imm32
12426     0/imm32/next
12427     0/imm32/next
12428 
12429 Int-var-in-mem:  # (payload var)
12430     0x11/imm32/alloc-id:fake:payload
12431     0/imm32/name
12432     0/imm32/name
12433     0x11/imm32/alloc-id:fake
12434     Type-int/imm32
12435     1/imm32/some-block-depth
12436     1/imm32/some-stack-offset
12437     0/imm32/no-register
12438     0/imm32/no-register
12439 
12440 Two-args-int-stack-int-reg:  # (payload list var)
12441     0x11/imm32/alloc-id:fake:payload
12442     0x11/imm32/alloc-id:fake
12443     Int-var-in-mem/imm32
12444     0x11/imm32/alloc-id:fake
12445     Single-int-var-in-some-register/imm32/next
12446 
12447 Two-args-int-reg-int-stack:  # (payload list var)
12448     0x11/imm32/alloc-id:fake:payload
12449     0x11/imm32/alloc-id:fake
12450     Int-var-in-some-register/imm32
12451     0x11/imm32/alloc-id:fake
12452     Single-int-var-in-mem/imm32/next
12453 
12454 Two-args-int-eax-int-literal:  # (payload list var)
12455     0x11/imm32/alloc-id:fake:payload
12456     0x11/imm32/alloc-id:fake
12457     Int-var-in-eax/imm32
12458     0x11/imm32/alloc-id:fake
12459     Single-lit-var/imm32/next
12460 
12461 Int-var-and-literal:  # (payload list var)
12462     0x11/imm32/alloc-id:fake:payload
12463     0x11/imm32/alloc-id:fake
12464     Int-var-in-mem/imm32
12465     0x11/imm32/alloc-id:fake
12466     Single-lit-var/imm32/next
12467 
12468 Int-var-in-register-and-literal:  # (payload list var)
12469     0x11/imm32/alloc-id:fake:payload
12470     0x11/imm32/alloc-id:fake
12471     Int-var-in-some-register/imm32
12472     0x11/imm32/alloc-id:fake
12473     Single-lit-var/imm32/next
12474 
12475 Single-int-var-in-some-register:  # (payload list var)
12476     0x11/imm32/alloc-id:fake:payload
12477     0x11/imm32/alloc-id:fake
12478     Int-var-in-some-register/imm32
12479     0/imm32/next
12480     0/imm32/next
12481 
12482 Single-addr-var-in-some-register:  # (payload list var)
12483     0x11/imm32/alloc-id:fake:payload
12484     0x11/imm32/alloc-id:fake
12485     Addr-var-in-some-register/imm32
12486     0/imm32/next
12487     0/imm32/next
12488 
12489 Int-var-in-some-register:  # (payload var)
12490     0x11/imm32/alloc-id:fake:payload
12491     0/imm32/name
12492     0/imm32/name
12493     0x11/imm32/alloc-id:fake
12494     Type-int/imm32
12495     1/imm32/some-block-depth
12496     0/imm32/no-stack-offset
12497     0x11/imm32/alloc-id:fake
12498     Any-register/imm32
12499 
12500 Any-register:  # (payload array byte)
12501   0x11/imm32/alloc-id:fake:payload
12502   1/imm32/size
12503   # data
12504   2a/asterisk
12505 
12506 Addr-var-in-some-register:  # (payload var)
12507     0x11/imm32/alloc-id:fake:payload
12508     0/imm32/name
12509     0/imm32/name
12510     0x11/imm32/alloc-id:fake
12511     Type-addr/imm32
12512     1/imm32/some-block-depth
12513     0/imm32/no-stack-offset
12514     0x11/imm32/alloc-id:fake
12515     Any-register/imm32
12516 
12517 Single-int-var-in-eax:  # (payload list var)
12518     0x11/imm32/alloc-id:fake:payload
12519     0x11/imm32/alloc-id:fake
12520     Int-var-in-eax/imm32
12521     0/imm32/next
12522     0/imm32/next
12523 
12524 Int-var-in-eax:
12525     0x11/imm32/alloc-id:fake:payload
12526     0/imm32/name
12527     0/imm32/name
12528     0x11/imm32/alloc-id:fake
12529     Type-int/imm32
12530     1/imm32/some-block-depth
12531     0/imm32/no-stack-offset
12532     0x11/imm32/alloc-id:fake
12533     $Register-eax/imm32
12534 
12535 Single-int-var-in-ecx:  # (payload list var)
12536     0x11/imm32/alloc-id:fake:payload
12537     0x11/imm32/alloc-id:fake
12538     Int-var-in-ecx/imm32
12539     0/imm32/next
12540     0/imm32/next
12541 
12542 Int-var-in-ecx:
12543     0x11/imm32/alloc-id:fake:payload
12544     0/imm32/name
12545     0/imm32/name
12546     0x11/imm32/alloc-id:fake
12547     Type-int/imm32
12548     1/imm32/some-block-depth
12549     0/imm32/no-stack-offset
12550     0x11/imm32/alloc-id:fake
12551     $Register-ecx/imm32/register
12552 
12553 Single-int-var-in-edx:  # (payload list var)
12554     0x11/imm32/alloc-id:fake:payload
12555     0x11/imm32/alloc-id:fake
12556     Int-var-in-edx/imm32
12557     0/imm32/next
12558     0/imm32/next
12559 
12560 Int-var-in-edx:  # (payload list var)
12561     0x11/imm32/alloc-id:fake:payload
12562     0/imm32/name
12563     0/imm32/name
12564     0x11/imm32/alloc-id:fake
12565     Type-int/imm32
12566     1/imm32/some-block-depth
12567     0/imm32/no-stack-offset
12568     0x11/imm32/alloc-id:fake
12569     $Register-edx/imm32/register
12570 
12571 Single-int-var-in-ebx:  # (payload list var)
12572     0x11/imm32/alloc-id:fake:payload
12573     0x11/imm32/alloc-id:fake
12574     Int-var-in-ebx/imm32
12575     0/imm32/next
12576     0/imm32/next
12577 
12578 Int-var-in-ebx:  # (payload list var)
12579     0x11/imm32/alloc-id:fake:payload
12580     0/imm32/name
12581     0/imm32/name
12582     0x11/imm32/alloc-id:fake
12583     Type-int/imm32
12584     1/imm32/some-block-depth
12585     0/imm32/no-stack-offset
12586     0x11/imm32/alloc-id:fake
12587     $Register-ebx/imm32/register
12588 
12589 Single-int-var-in-esi:  # (payload list var)
12590     0x11/imm32/alloc-id:fake:payload
12591     0x11/imm32/alloc-id:fake
12592     Int-var-in-esi/imm32
12593     0/imm32/next
12594     0/imm32/next
12595 
12596 Int-var-in-esi:  # (payload list var)
12597     0x11/imm32/alloc-id:fake:payload
12598     0/imm32/name
12599     0/imm32/name
12600     0x11/imm32/alloc-id:fake
12601     Type-int/imm32
12602     1/imm32/some-block-depth
12603     0/imm32/no-stack-offset
12604     0x11/imm32/alloc-id:fake
12605     $Register-esi/imm32/register
12606 
12607 Single-int-var-in-edi:  # (payload list var)
12608     0x11/imm32/alloc-id:fake:payload
12609     0x11/imm32/alloc-id:fake
12610     Int-var-in-edi/imm32
12611     0/imm32/next
12612     0/imm32/next
12613 
12614 Int-var-in-edi:  # (payload list var)
12615     0x11/imm32/alloc-id:fake:payload
12616     0/imm32/name
12617     0/imm32/name
12618     0x11/imm32/alloc-id:fake
12619     Type-int/imm32
12620     1/imm32/some-block-depth
12621     0/imm32/no-stack-offset
12622     0x11/imm32/alloc-id:fake
12623     $Register-edi/imm32/register
12624 
12625 Single-lit-var:  # (payload list var)
12626     0x11/imm32/alloc-id:fake:payload
12627     0x11/imm32/alloc-id:fake
12628     Lit-var/imm32
12629     0/imm32/next
12630     0/imm32/next
12631 
12632 Lit-var:  # (payload var)
12633     0x11/imm32/alloc-id:fake:payload
12634     0/imm32/name
12635     0/imm32/name
12636     0x11/imm32/alloc-id:fake
12637     Type-literal/imm32
12638     1/imm32/some-block-depth
12639     0/imm32/no-stack-offset
12640     0/imm32/no-register
12641     0/imm32/no-register
12642 
12643 Type-int:  # (payload tree type-id)
12644     0x11/imm32/alloc-id:fake:payload
12645     1/imm32/left-is-atom
12646     1/imm32/value:int
12647     0/imm32/left:unused
12648     0/imm32/right:null
12649     0/imm32/right:null
12650 
12651 Type-literal:  # (payload tree type-id)
12652     0x11/imm32/alloc-id:fake:payload
12653     1/imm32/is-atom
12654     0/imm32/value:literal
12655     0/imm32/left:unused
12656     0/imm32/right:null
12657     0/imm32/right:null
12658 
12659 Type-addr:  # (payload tree type-id)
12660     0x11/imm32/alloc-id:fake:payload
12661     1/imm32/is-atom
12662     2/imm32/value:addr
12663     0/imm32/left:unused
12664     0/imm32/right:null
12665     0/imm32/right:null
12666 
12667 == code
12668 emit-subx-primitive:  # out: (addr buffered-file), stmt: (addr stmt), primitive: (addr primitive)
12669     # . prologue
12670     55/push-ebp
12671     89/<- %ebp 4/r32/esp
12672     # . save registers
12673     50/push-eax
12674     51/push-ecx
12675     # ecx = primitive
12676     8b/-> *(ebp+0x10) 1/r32/ecx
12677     # emit primitive name
12678     (emit-indent *(ebp+8) *Curr-block-depth)
12679     (lookup *(ecx+0x18) *(ecx+0x1c))  # Primitive-subx-name Primitive-subx-name => eax
12680     (write-buffered *(ebp+8) %eax)
12681     # emit rm32 if necessary
12682     (emit-subx-rm32 *(ebp+8) *(ecx+0x20) *(ebp+0xc))  # out, Primitive-subx-rm32, stmt
12683     # emit r32 if necessary
12684     (emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc))  # out, Primitive-subx-r32, stmt
12685     # emit imm32 if necessary
12686     (emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc))  # out, Primitive-subx-imm32, stmt
12687     # emit disp32 if necessary
12688     (emit-subx-disp32 *(ebp+8) *(ecx+0x2c) *(ebp+0xc))  # out, Primitive-subx-disp32, stmt
12689     (write-buffered *(ebp+8) Newline)
12690 $emit-subx-primitive:end:
12691     # . restore registers
12692     59/pop-to-ecx
12693     58/pop-to-eax
12694     # . epilogue
12695     89/<- %esp 5/r32/ebp
12696     5d/pop-to-ebp
12697     c3/return
12698 
12699 emit-subx-rm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
12700     # . prologue
12701     55/push-ebp
12702     89/<- %ebp 4/r32/esp
12703     # . save registers
12704     50/push-eax
12705     # if (l == 0) return
12706     81 7/subop/compare *(ebp+0xc) 0/imm32
12707     74/jump-if-= $emit-subx-rm32:end/disp8
12708     # var v/eax: (addr stmt-var)
12709     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
12710     (emit-subx-var-as-rm32 *(ebp+8) %eax)
12711 $emit-subx-rm32:end:
12712     # . restore registers
12713     58/pop-to-eax
12714     # . epilogue
12715     89/<- %esp 5/r32/ebp
12716     5d/pop-to-ebp
12717     c3/return
12718 
12719 get-stmt-operand-from-arg-location:  # stmt: (addr stmt), l: arg-location -> var/eax: (addr stmt-var)
12720     # . prologue
12721     55/push-ebp
12722     89/<- %ebp 4/r32/esp
12723     # . save registers
12724     51/push-ecx
12725     # eax = l
12726     8b/-> *(ebp+0xc) 0/r32/eax
12727     # ecx = stmt
12728     8b/-> *(ebp+8) 1/r32/ecx
12729     # if (l == 1) return stmt->inouts
12730     {
12731       3d/compare-eax-and 1/imm32
12732       75/jump-if-!= break/disp8
12733 $get-stmt-operand-from-arg-location:1:
12734       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12735       eb/jump $get-stmt-operand-from-arg-location:end/disp8
12736     }
12737     # if (l == 2) return stmt->inouts->next
12738     {
12739       3d/compare-eax-and 2/imm32
12740       75/jump-if-!= break/disp8
12741 $get-stmt-operand-from-arg-location:2:
12742       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12743       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12744       eb/jump $get-stmt-operand-from-arg-location:end/disp8
12745     }
12746     # if (l == 3) return stmt->outputs
12747     {
12748       3d/compare-eax-and 3/imm32
12749       75/jump-if-!= break/disp8
12750 $get-stmt-operand-from-arg-location:3:
12751       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12752       eb/jump $get-stmt-operand-from-arg-location:end/disp8
12753     }
12754     # abort
12755     e9/jump $get-stmt-operand-from-arg-location:abort/disp32
12756 $get-stmt-operand-from-arg-location:end:
12757     # . restore registers
12758     59/pop-to-ecx
12759     # . epilogue
12760     89/<- %esp 5/r32/ebp
12761     5d/pop-to-ebp
12762     c3/return
12763 
12764 $get-stmt-operand-from-arg-location:abort:
12765     # error("invalid arg-location " eax)
12766     (write-buffered Stderr "invalid arg-location ")
12767     (print-int32-buffered Stderr %eax)
12768     (write-buffered Stderr Newline)
12769     (flush Stderr)
12770     # . syscall(exit, 1)
12771     bb/copy-to-ebx  1/imm32
12772     b8/copy-to-eax  1/imm32/exit
12773     cd/syscall  0x80/imm8
12774     # never gets here
12775 
12776 emit-subx-r32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
12777     # . prologue
12778     55/push-ebp
12779     89/<- %ebp 4/r32/esp
12780     # . save registers
12781     50/push-eax
12782     51/push-ecx
12783     # if (l == 0) return
12784     81 7/subop/compare *(ebp+0xc) 0/imm32
12785     0f 84/jump-if-= $emit-subx-r32:end/disp32
12786     # var v/eax: (addr stmt-var)
12787     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
12788     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12789     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
12790     (maybe-get Registers %eax 0xc)  # => eax: (addr register-index)
12791     (write-buffered *(ebp+8) Space)
12792     (print-int32-buffered *(ebp+8) *eax)
12793     (write-buffered *(ebp+8) "/r32")
12794 $emit-subx-r32:end:
12795     # . restore registers
12796     59/pop-to-ecx
12797     58/pop-to-eax
12798     # . epilogue
12799     89/<- %esp 5/r32/ebp
12800     5d/pop-to-ebp
12801     c3/return
12802 
12803 emit-subx-imm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
12804     # . prologue
12805     55/push-ebp
12806     89/<- %ebp 4/r32/esp
12807     # . save registers
12808     50/push-eax
12809     51/push-ecx
12810     # if (l == 0) return
12811     81 7/subop/compare *(ebp+0xc) 0/imm32
12812     0f 84/jump-if-= $emit-subx-imm32:end/disp32
12813     # var v/eax: (handle var)
12814     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
12815     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12816     (lookup *eax *(eax+4))  # Var-name Var-name => eax
12817     (write-buffered *(ebp+8) Space)
12818     (write-buffered *(ebp+8) %eax)
12819     (write-buffered *(ebp+8) "/imm32")
12820 $emit-subx-imm32:end:
12821     # . restore registers
12822     59/pop-to-ecx
12823     58/pop-to-eax
12824     # . epilogue
12825     89/<- %esp 5/r32/ebp
12826     5d/pop-to-ebp
12827     c3/return
12828 
12829 emit-subx-disp32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
12830     # . prologue
12831     55/push-ebp
12832     89/<- %ebp 4/r32/esp
12833     # . save registers
12834     50/push-eax
12835     51/push-ecx
12836     # if (location == 0) return
12837     81 7/subop/compare *(ebp+0xc) 0/imm32
12838     0f 84/jump-if-= $emit-subx-disp32:end/disp32
12839     # var v/eax: (addr stmt-var)
12840     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
12841     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12842     (lookup *eax *(eax+4))  # Var-name Var-name => eax
12843     (write-buffered *(ebp+8) Space)
12844     (write-buffered *(ebp+8) %eax)
12845     # hack: if instruction operation starts with "break", emit ":break"
12846     # var name/ecx: (addr array byte) = lookup(stmt->operation)
12847     8b/-> *(ebp+0x10) 0/r32/eax
12848     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
12849     89/<- %ecx 0/r32/eax
12850     {
12851       (string-starts-with? %ecx "break")  # => eax
12852       3d/compare-eax-and 0/imm32/false
12853       74/jump-if-= break/disp8
12854       (write-buffered *(ebp+8) ":break")
12855     }
12856     # hack: if instruction operation starts with "loop", emit ":loop"
12857     {
12858       (string-starts-with? %ecx "loop")  # => eax
12859       3d/compare-eax-and 0/imm32/false
12860       74/jump-if-= break/disp8
12861       (write-buffered *(ebp+8) ":loop")
12862     }
12863     (write-buffered *(ebp+8) "/disp32")
12864 $emit-subx-disp32:end:
12865     # . restore registers
12866     59/pop-to-ecx
12867     58/pop-to-eax
12868     # . epilogue
12869     89/<- %esp 5/r32/ebp
12870     5d/pop-to-ebp
12871     c3/return
12872 
12873 emit-call:  # out: (addr buffered-file), stmt: (addr stmt)
12874     # . prologue
12875     55/push-ebp
12876     89/<- %ebp 4/r32/esp
12877     # . save registers
12878     50/push-eax
12879     51/push-ecx
12880     #
12881     (emit-indent *(ebp+8) *Curr-block-depth)
12882     (write-buffered *(ebp+8) "(")
12883     # ecx = stmt
12884     8b/-> *(ebp+0xc) 1/r32/ecx
12885     # - emit function name
12886     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
12887     (write-buffered *(ebp+8) %eax)
12888     # - emit arguments
12889     # var curr/eax: (addr stmt-var) = lookup(stmt->inouts)
12890     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12891     {
12892       # if (curr == null) break
12893       3d/compare-eax-and 0/imm32
12894       74/jump-if-= break/disp8
12895       #
12896       (emit-subx-call-operand *(ebp+8) %eax)
12897       # curr = lookup(curr->next)
12898       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12899       eb/jump loop/disp8
12900     }
12901     #
12902     (write-buffered *(ebp+8) ")\n")
12903 $emit-call:end:
12904     # . restore registers
12905     59/pop-to-ecx
12906     58/pop-to-eax
12907     # . epilogue
12908     89/<- %esp 5/r32/ebp
12909     5d/pop-to-ebp
12910     c3/return
12911 
12912 emit-subx-call-operand:  # out: (addr buffered-file), s: (addr stmt-var)
12913     # shares code with emit-subx-var-as-rm32
12914     # . prologue
12915     55/push-ebp
12916     89/<- %ebp 4/r32/esp
12917     # . save registers
12918     50/push-eax
12919     51/push-ecx
12920     56/push-esi
12921     # ecx = s
12922     8b/-> *(ebp+0xc) 1/r32/ecx
12923     # var operand/esi: (addr var) = lookup(s->value)
12924     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12925     89/<- %esi 0/r32/eax
12926     # if (operand->register && !s->is-deref?) emit "%__"
12927     {
12928 $emit-subx-call-operand:check-for-register-direct:
12929       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
12930       74/jump-if-= break/disp8
12931       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
12932       75/jump-if-!= break/disp8
12933 $emit-subx-call-operand:register-direct:
12934       (write-buffered *(ebp+8) " %")
12935       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
12936       (write-buffered *(ebp+8) %eax)
12937       e9/jump $emit-subx-call-operand:end/disp32
12938     }
12939     # else if (operand->register && s->is-deref?) emit "*__"
12940     {
12941 $emit-subx-call-operand:check-for-register-indirect:
12942       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
12943       74/jump-if-= break/disp8
12944       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
12945       74/jump-if-= break/disp8
12946 $emit-subx-call-operand:register-indirect:
12947       (emit-subx-call-operand-register-indirect *(ebp+8) %esi)
12948       e9/jump $emit-subx-call-operand:end/disp32
12949     }
12950     # else if (operand->stack-offset) emit "*(ebp+__)"
12951     {
12952       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
12953       74/jump-if-= break/disp8
12954 $emit-subx-call-operand:stack:
12955       (emit-subx-call-operand-stack *(ebp+8) %esi)
12956       e9/jump $emit-subx-call-operand:end/disp32
12957     }
12958     # else if (operand->type == literal) emit "__"
12959     {
12960       (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
12961       81 7/subop/compare *(eax+4) 0/imm32  # Tree-left
12962       75/jump-if-!= break/disp8
12963 $emit-subx-call-operand:literal:
12964       (write-buffered *(ebp+8) Space)
12965       (lookup *esi *(esi+4))  # Var-name Var-name => eax
12966       (write-buffered *(ebp+8) %eax)
12967     }
12968 $emit-subx-call-operand:end:
12969     # . restore registers
12970     5e/pop-to-esi
12971     59/pop-to-ecx
12972     58/pop-to-eax
12973     # . epilogue
12974     89/<- %esp 5/r32/ebp
12975     5d/pop-to-ebp
12976     c3/return
12977 
12978 emit-subx-call-operand-register-indirect:  # out: (addr buffered-file), v: (addr var)
12979     # . prologue
12980     55/push-ebp
12981     89/<- %ebp 4/r32/esp
12982     # . save registers
12983     50/push-eax
12984     51/push-ecx
12985     56/push-esi
12986     # esi = v
12987     8b/-> *(ebp+0xc) 6/r32/esi
12988     # var size/ecx: int = size-of-deref(v)
12989     (size-of-deref %esi)  # => eax
12990     89/<- %ecx 0/r32/eax
12991     # var reg-name/esi: (addr array byte) = lookup(v->register)
12992     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
12993     89/<- %esi 0/r32/eax
12994     # TODO: assert size is a multiple of 4
12995     # var i/eax: int = 0
12996     b8/copy-to-eax 0/imm32
12997     {
12998 $emit-subx-call-operand-register-indirect:loop:
12999       # if (i >= size) break
13000       39/compare %eax 1/r32/ecx
13001       7d/jump-if->= break/disp8
13002       # emit " *(" v->register "+" i ")"
13003       (write-buffered *(ebp+8) " *(")
13004       (write-buffered *(ebp+8) %esi)
13005       (write-buffered *(ebp+8) "+")
13006       (print-int32-buffered *(ebp+8) %eax)
13007       (write-buffered *(ebp+8) ")")
13008       # i += 4
13009       05/add-to-eax 4/imm32
13010       #
13011       eb/jump loop/disp8
13012     }
13013 $emit-subx-call-operand-register-indirect:end:
13014     # . restore registers
13015     5e/pop-to-esi
13016     59/pop-to-ecx
13017     58/pop-to-eax
13018     # . epilogue
13019     89/<- %esp 5/r32/ebp
13020     5d/pop-to-ebp
13021     c3/return
13022 
13023 emit-subx-call-operand-stack:  # out: (addr buffered-file), v: (addr var)
13024     # . prologue
13025     55/push-ebp
13026     89/<- %ebp 4/r32/esp
13027     # . save registers
13028     50/push-eax
13029     51/push-ecx
13030     56/push-esi
13031     # esi = v
13032     8b/-> *(ebp+0xc) 6/r32/esi
13033     # var curr/ecx: int = v->offset
13034     8b/-> *(esi+0x14) 1/r32/ecx  # Var-offset
13035     # var max/eax: int = v->offset + size-of(v)
13036     (size-of %esi)  # => eax
13037     # TODO: assert size is a multiple of 4
13038     01/add-to %eax 1/r32/ecx
13039     {
13040 $emit-subx-call-operand-stack:loop:
13041       # if (curr >= max) break
13042       39/compare %ecx 0/r32/eax
13043       7d/jump-if->= break/disp8
13044       # emit " *(ebp+" curr ")"
13045       (write-buffered *(ebp+8) " *(ebp+")
13046       (print-int32-buffered *(ebp+8) %ecx)
13047       (write-buffered *(ebp+8) ")")
13048       # i += 4
13049       81 0/subop/add %ecx 4/imm32
13050       #
13051       eb/jump loop/disp8
13052     }
13053 $emit-subx-call-operand-stack:end:
13054     # . restore registers
13055     5e/pop-to-esi
13056     59/pop-to-ecx
13057     58/pop-to-eax
13058     # . epilogue
13059     89/<- %esp 5/r32/ebp
13060     5d/pop-to-ebp
13061     c3/return
13062 
13063 emit-subx-var-as-rm32:  # out: (addr buffered-file), s: (addr stmt-var)
13064     # . prologue
13065     55/push-ebp
13066     89/<- %ebp 4/r32/esp
13067     # . save registers
13068     50/push-eax
13069     51/push-ecx
13070     56/push-esi
13071     # ecx = s
13072     8b/-> *(ebp+0xc) 1/r32/ecx
13073     # var operand/esi: (addr var) = lookup(s->value)
13074     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
13075     89/<- %esi 0/r32/eax
13076     # if (operand->register && s->is-deref?) emit "*__"
13077     {
13078 $emit-subx-var-as-rm32:check-for-register-indirect:
13079       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
13080       74/jump-if-= break/disp8
13081       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
13082       74/jump-if-= break/disp8
13083 $emit-subx-var-as-rm32:register-indirect:
13084       (write-buffered *(ebp+8) " *")
13085       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
13086       (write-buffered *(ebp+8) %eax)
13087       e9/jump $emit-subx-var-as-rm32:end/disp32
13088     }
13089     # if (operand->register && !s->is-deref?) emit "%__"
13090     {
13091 $emit-subx-var-as-rm32:check-for-register-direct:
13092       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
13093       74/jump-if-= break/disp8
13094       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
13095       75/jump-if-!= break/disp8
13096 $emit-subx-var-as-rm32:register-direct:
13097       (write-buffered *(ebp+8) " %")
13098       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
13099       (write-buffered *(ebp+8) %eax)
13100       e9/jump $emit-subx-var-as-rm32:end/disp32
13101     }
13102     # else if (operand->stack-offset) emit "*(ebp+__)"
13103     {
13104       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
13105       74/jump-if-= break/disp8
13106 $emit-subx-var-as-rm32:stack:
13107       (write-buffered *(ebp+8) Space)
13108       (write-buffered *(ebp+8) "*(ebp+")
13109       (print-int32-buffered *(ebp+8) *(esi+0x14))  # Var-offset
13110       (write-buffered *(ebp+8) ")")
13111     }
13112 $emit-subx-var-as-rm32:end:
13113     # . restore registers
13114     5e/pop-to-esi
13115     59/pop-to-ecx
13116     58/pop-to-eax
13117     # . epilogue
13118     89/<- %esp 5/r32/ebp
13119     5d/pop-to-ebp
13120     c3/return
13121 
13122 find-matching-primitive:  # primitives: (addr primitive), stmt: (addr stmt) -> result/eax: (addr primitive)
13123     # . prologue
13124     55/push-ebp
13125     89/<- %ebp 4/r32/esp
13126     # . save registers
13127     51/push-ecx
13128     # var curr/ecx: (addr primitive) = primitives
13129     8b/-> *(ebp+8) 1/r32/ecx
13130     {
13131 $find-matching-primitive:loop:
13132       # if (curr == null) break
13133       81 7/subop/compare %ecx 0/imm32
13134       0f 84/jump-if-= break/disp32
13135       # if match(curr, stmt) return curr
13136       {
13137         (mu-stmt-matches-primitive? *(ebp+0xc) %ecx)  # => eax
13138         3d/compare-eax-and 0/imm32/false
13139         74/jump-if-= break/disp8
13140         89/<- %eax 1/r32/ecx
13141         eb/jump $find-matching-primitive:end/disp8
13142       }
13143 $find-matching-primitive:next-primitive:
13144       # curr = curr->next
13145       (lookup *(ecx+0x34) *(ecx+0x38))  # Primitive-next Primitive-next => eax
13146       89/<- %ecx 0/r32/eax
13147       #
13148       e9/jump loop/disp32
13149     }
13150     # return null
13151     b8/copy-to-eax 0/imm32
13152 $find-matching-primitive:end:
13153     # . restore registers
13154     59/pop-to-ecx
13155     # . epilogue
13156     89/<- %esp 5/r32/ebp
13157     5d/pop-to-ebp
13158     c3/return
13159 
13160 mu-stmt-matches-primitive?:  # stmt: (addr stmt), primitive: (addr primitive) -> result/eax: boolean
13161     # A mu stmt matches a primitive if the name matches, all the inout vars
13162     # match, and all the output vars match.
13163     # Vars match if types match and registers match.
13164     # In addition, a stmt output matches a primitive's output if types match
13165     # and the primitive has a wildcard register.
13166     # . prologue
13167     55/push-ebp
13168     89/<- %ebp 4/r32/esp
13169     # . save registers
13170     51/push-ecx
13171     52/push-edx
13172     53/push-ebx
13173     56/push-esi
13174     57/push-edi
13175     # ecx = stmt
13176     8b/-> *(ebp+8) 1/r32/ecx
13177     # edx = primitive
13178     8b/-> *(ebp+0xc) 2/r32/edx
13179     {
13180 $mu-stmt-matches-primitive?:check-name:
13181       # if (primitive->name != stmt->operation) return false
13182       # . var esi: (addr array byte) = lookup(stmt->operation)
13183       (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
13184       89/<- %esi 0/r32/eax
13185       # . var edi: (addr array byte) = lookup(primitive->name)
13186       (lookup *edx *(edx+4))  # Primitive-name Primitive-name => eax
13187       89/<- %edi 0/r32/eax
13188       (string-equal? %esi %edi)  # => eax
13189       3d/compare-eax-and 0/imm32/false
13190       75/jump-if-!= break/disp8
13191       b8/copy-to-eax 0/imm32
13192       e9/jump $mu-stmt-matches-primitive?:end/disp32
13193     }
13194     # var curr/esi: (addr stmt-var) = lookup(stmt->inouts)
13195     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13196     89/<- %esi 0/r32/eax
13197     # var curr2/edi: (addr list var) = lookup(primitive->inouts)
13198     (lookup *(edx+8) *(edx+0xc))  # Primitive-inouts Primitive-inouts => eax
13199     89/<- %edi 0/r32/eax
13200     {
13201 $mu-stmt-matches-primitive?:inouts-loop:
13202       # if (curr == 0 && curr2 == 0) move on to check outputs
13203       {
13204 $mu-stmt-matches-primitive?:check-both-inouts-null:
13205         81 7/subop/compare %esi 0/imm32
13206         75/jump-if-!= break/disp8
13207 $mu-stmt-matches-primitive?:stmt-inout-null:
13208         81 7/subop/compare %edi 0/imm32
13209         0f 84/jump-if-= $mu-stmt-matches-primitive?:check-outputs/disp32
13210 $mu-stmt-matches-primitive?:stmt-inout-null-and-prim-inout-not-null:
13211         # return false
13212         b8/copy-to-eax 0/imm32/false
13213         e9/jump $mu-stmt-matches-primitive?:end/disp32
13214       }
13215       # if (curr2 == 0) return false
13216       {
13217 $mu-stmt-matches-primitive?:check-prim-inout-null:
13218         81 7/subop/compare %edi 0/imm32
13219         75/jump-if-!= break/disp8
13220 $mu-stmt-matches-primitive?:prim-inout-null:
13221         b8/copy-to-eax 0/imm32/false
13222         e9/jump $mu-stmt-matches-primitive?:end/disp32
13223       }
13224       # if (curr != curr2) return false
13225       {
13226 $mu-stmt-matches-primitive?:check-inouts-match:
13227         (lookup *edi *(edi+4))  # List-value List-value => eax
13228         (operand-matches-primitive? %esi %eax)  # => eax
13229         3d/compare-eax-and 0/imm32/false
13230         75/jump-if-!= break/disp8
13231 $mu-stmt-matches-primitive?:inouts-match:
13232         b8/copy-to-eax 0/imm32/false
13233         e9/jump $mu-stmt-matches-primitive?:end/disp32
13234       }
13235 $mu-stmt-matches-primitive?:next-inout:
13236       # curr = lookup(curr->next)
13237       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
13238       89/<- %esi 0/r32/eax
13239       # curr2 = lookup(curr2->next)
13240       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
13241       89/<- %edi 0/r32/eax
13242       #
13243       e9/jump loop/disp32
13244     }
13245 $mu-stmt-matches-primitive?:check-outputs:
13246     # var curr/esi: (addr stmt-var) = lookup(stmt->outputs)
13247     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13248     89/<- %esi 0/r32/eax
13249     # var curr2/edi: (addr list var) = lookup(primitive->outputs)
13250     (lookup *(edx+0x10) *(edx+0x14))  # Primitive-outputs Primitive-outputs => eax
13251     89/<- %edi 0/r32/eax
13252     {
13253 $mu-stmt-matches-primitive?:outputs-loop:
13254       # if (curr == 0) return (curr2 == 0)
13255       {
13256 $mu-stmt-matches-primitive?:check-both-outputs-null:
13257         81 7/subop/compare %esi 0/imm32
13258         75/jump-if-!= break/disp8
13259         {
13260 $mu-stmt-matches-primitive?:stmt-output-null:
13261           81 7/subop/compare %edi 0/imm32
13262           75/jump-if-!= break/disp8
13263 $mu-stmt-matches-primitive?:both-outputs-null:
13264           # return true
13265           b8/copy-to-eax 1/imm32
13266           e9/jump $mu-stmt-matches-primitive?:end/disp32
13267         }
13268 $mu-stmt-matches-primitive?:stmt-output-null-and-prim-output-not-null:
13269         # return false
13270         b8/copy-to-eax 0/imm32
13271         e9/jump $mu-stmt-matches-primitive?:end/disp32
13272       }
13273       # if (curr2 == 0) return false
13274       {
13275 $mu-stmt-matches-primitive?:check-prim-output-null:
13276         81 7/subop/compare %edi 0/imm32
13277         75/jump-if-!= break/disp8
13278 $mu-stmt-matches-primitive?:prim-output-is-null:
13279         b8/copy-to-eax 0/imm32
13280         e9/jump $mu-stmt-matches-primitive?:end/disp32
13281       }
13282       # if (curr != curr2) return false
13283       {
13284 $mu-stmt-matches-primitive?:check-outputs-match:
13285         (lookup *edi *(edi+4))  # List-value List-value => eax
13286         (operand-matches-primitive? %esi %eax)  # => eax
13287         3d/compare-eax-and 0/imm32/false
13288         75/jump-if-!= break/disp8
13289 $mu-stmt-matches-primitive?:outputs-match:
13290         b8/copy-to-eax 0/imm32
13291         e9/jump $mu-stmt-matches-primitive?:end/disp32
13292       }
13293 $mu-stmt-matches-primitive?:next-output:
13294       # curr = lookup(curr->next)
13295       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
13296       89/<- %esi 0/r32/eax
13297       # curr2 = lookup(curr2->next)
13298       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
13299       89/<- %edi 0/r32/eax
13300       #
13301       e9/jump loop/disp32
13302     }
13303 $mu-stmt-matches-primitive?:return-true:
13304     b8/copy-to-eax 1/imm32
13305 $mu-stmt-matches-primitive?:end:
13306     # . restore registers
13307     5f/pop-to-edi
13308     5e/pop-to-esi
13309     5b/pop-to-ebx
13310     5a/pop-to-edx
13311     59/pop-to-ecx
13312     # . epilogue
13313     89/<- %esp 5/r32/ebp
13314     5d/pop-to-ebp
13315     c3/return
13316 
13317 operand-matches-primitive?:  # s: (addr stmt-var), prim-var: (addr var) -> result/eax: boolean
13318     # . prologue
13319     55/push-ebp
13320     89/<- %ebp 4/r32/esp
13321     # . save registers
13322     51/push-ecx
13323     52/push-edx
13324     53/push-ebx
13325     56/push-esi
13326     57/push-edi
13327     # ecx = s
13328     8b/-> *(ebp+8) 1/r32/ecx
13329     # var var/esi: (addr var) = lookup(s->value)
13330     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
13331     89/<- %esi 0/r32/eax
13332     # edi = prim-var
13333     8b/-> *(ebp+0xc) 7/r32/edi
13334 $operand-matches-primitive?:check-type:
13335     # if (var->type != prim-var->type) return false
13336     # . var vtype/ebx: (addr tree type-id) = lookup(var->type)
13337     (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
13338     89/<- %ebx 0/r32/eax
13339     # . var ptype/eax: (addr tree type-id) = lookup(prim-var->type)
13340     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
13341     (subx-type-equal? %ebx %eax)  # => eax
13342     3d/compare-eax-and 0/imm32/false
13343     0f 84/jump-if-= $operand-matches-primitive?:return-false/disp32
13344     {
13345 $operand-matches-primitive?:check-register:
13346       # if prim-var is in memory and var is in register but dereference, match
13347       {
13348         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
13349         0f 85/jump-if-!= break/disp32
13350         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
13351         74/jump-if-= break/disp8
13352         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
13353         74/jump-if-= break/disp8
13354 $operand-matches-primitive?:var-deref-match:
13355         e9/jump $operand-matches-primitive?:return-true/disp32
13356       }
13357       # if prim-var is in register and var is in register but dereference, no match
13358       {
13359         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
13360         0f 84/jump-if-= break/disp32
13361         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
13362         0f 84/jump-if-= break/disp32
13363         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
13364         74/jump-if-= break/disp8
13365 $operand-matches-primitive?:var-deref-no-match:
13366         e9/jump $operand-matches-primitive?:return-false/disp32
13367       }
13368       # return false if var->register doesn't match prim-var->register
13369       {
13370         # if register addresses are equal, it's a match
13371         # var vreg/ebx: (addr array byte) = lookup(var->register)
13372         (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
13373         89/<- %ebx 0/r32/eax
13374         # var preg/ecx: (addr array byte) = lookup(prim-var->register)
13375         (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
13376         89/<- %ecx 0/r32/eax
13377         # if (vreg == preg) break
13378         39/compare %ecx 3/r32/ebx
13379         74/jump-if-= break/disp8
13380 $operand-matches-primitive?:var-register-no-match:
13381         # if either address is 0, return false
13382         81 7/subop/compare %ebx 0/imm32
13383         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
13384         81 7/subop/compare %ecx 0/imm32
13385         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
13386         # if prim-var->register is wildcard, it's a match
13387         (string-equal? %ecx "*")  # Any-register => eax
13388         3d/compare-eax-and 0/imm32/false
13389         75/jump-if-!= break/disp8
13390 $operand-matches-primitive?:wildcard-no-match:
13391         # if string contents aren't equal, return false
13392         (string-equal? %ecx %ebx)  # => eax
13393         3d/compare-eax-and 0/imm32/false
13394         74/jump-if-= $operand-matches-primitive?:return-false/disp8
13395       }
13396     }
13397 $operand-matches-primitive?:return-true:
13398     b8/copy-to-eax 1/imm32/true
13399     eb/jump $operand-matches-primitive?:end/disp8
13400 $operand-matches-primitive?:return-false:
13401     b8/copy-to-eax 0/imm32/false
13402 $operand-matches-primitive?:end:
13403     # . restore registers
13404     5f/pop-to-edi
13405     5e/pop-to-esi
13406     5b/pop-to-ebx
13407     5a/pop-to-edx
13408     59/pop-to-ecx
13409     # . epilogue
13410     89/<- %esp 5/r32/ebp
13411     5d/pop-to-ebp
13412     c3/return
13413 
13414 subx-type-equal?:  # a: (addr tree type-id), b: (addr tree type-id) -> result/eax: boolean
13415     # . prologue
13416     55/push-ebp
13417     89/<- %ebp 4/r32/esp
13418     # . save registers
13419     51/push-ecx
13420     # var alit/ecx: boolean = is-literal-type?(a)
13421     (is-simple-mu-type? *(ebp+8) 0)  # => eax
13422     89/<- %ecx 0/r32/eax
13423     # var blit/eax: boolean = is-literal-type?(b)
13424     (is-simple-mu-type? *(ebp+0xc) 0)  # => eax
13425     # return alit == blit
13426     39/compare %eax 1/r32/ecx
13427     0f 94/set-byte-if-= %al
13428     81 4/subop/and %eax 0xff/imm32
13429 $subx-type-equal?:end:
13430     # . restore registers
13431     59/pop-to-ecx
13432     # . epilogue
13433     89/<- %esp 5/r32/ebp
13434     5d/pop-to-ebp
13435     c3/return
13436 
13437 is-simple-mu-type?:  # a: (addr tree type-id), n: type-id -> result/eax: boolean
13438     # . prologue
13439     55/push-ebp
13440     89/<- %ebp 4/r32/esp
13441     # . save registers
13442     51/push-ecx
13443     # ecx = n
13444     8b/-> *(ebp+0xc) 1/r32/ecx
13445     # return (a->value == n)
13446     8b/-> *(ebp+8) 0/r32/eax
13447     39/compare *(eax+4) 1/r32/ecx  # Tree-value
13448     0f 94/set-byte-if-= %al
13449     81 4/subop/and %eax 0xff/imm32
13450 $is-simple-mu-type?:end:
13451     # . restore registers
13452     59/pop-to-ecx
13453     # . epilogue
13454     89/<- %esp 5/r32/ebp
13455     5d/pop-to-ebp
13456     c3/return
13457 
13458 test-emit-subx-stmt-primitive:
13459     # Primitive operation on a variable on the stack.
13460     #   increment foo
13461     # =>
13462     #   ff 0/subop/increment *(ebp-8)
13463     #
13464     # There's a variable on the var stack as follows:
13465     #   name: 'foo'
13466     #   type: int
13467     #   stack-offset: -8
13468     #
13469     # There's a primitive with this info:
13470     #   name: 'increment'
13471     #   inouts: int/mem
13472     #   value: 'ff 0/subop/increment'
13473     #
13474     # . prologue
13475     55/push-ebp
13476     89/<- %ebp 4/r32/esp
13477     # setup
13478     (clear-stream _test-output-stream)
13479     (clear-stream $_test-output-buffered-file->buffer)
13480     # simulate allocated payloads starting with an initial fake alloc-id (0x11)
13481 $test-emit-subx-stmt-primitive:initialize-type:
13482     # var type/ecx: (payload tree type-id) = int
13483     68/push 0/imm32/right:null
13484     68/push 0/imm32/right:null
13485     68/push 0/imm32/left:unused
13486     68/push 1/imm32/value:int
13487     68/push 1/imm32/is-atom?:true
13488     68/push 0x11/imm32/alloc-id:fake:payload
13489     89/<- %ecx 4/r32/esp
13490 $test-emit-subx-stmt-primitive:initialize-var:
13491     # var var-foo/ecx: (payload var) = var(type)
13492     68/push 0/imm32/no-register
13493     68/push 0/imm32/no-register
13494     68/push -8/imm32/stack-offset
13495     68/push 1/imm32/block-depth
13496     51/push-ecx/type
13497     68/push 0x11/imm32/alloc-id:fake
13498     68/push 0/imm32/name
13499     68/push 0/imm32/name
13500     68/push 0x11/imm32/alloc-id:fake:payload
13501     89/<- %ecx 4/r32/esp
13502 $test-emit-subx-stmt-primitive:initialize-var-name:
13503     # var-foo->name = "foo"
13504     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
13505     (copy-array Heap "foo" %eax)
13506 $test-emit-subx-stmt-primitive:initialize-stmt-var:
13507     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
13508     68/push 0/imm32/is-deref:false
13509     68/push 0/imm32/next
13510     68/push 0/imm32/next
13511     51/push-ecx/var-foo
13512     68/push 0x11/imm32/alloc-id:fake
13513     68/push 0x11/imm32/alloc-id:fake:payload
13514     89/<- %ebx 4/r32/esp
13515 $test-emit-subx-stmt-primitive:initialize-stmt:
13516     # var stmt/esi: (addr statement)
13517     68/push 0/imm32/no-outputs
13518     68/push 0/imm32/no-outputs
13519     53/push-ebx/inouts
13520     68/push 0x11/imm32/alloc-id:fake
13521     68/push 0/imm32/operation
13522     68/push 0/imm32/operation
13523     68/push 1/imm32/tag
13524     89/<- %esi 4/r32/esp
13525 $test-emit-subx-stmt-primitive:initialize-stmt-operation:
13526     # stmt->operation = "increment"
13527     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
13528     (copy-array Heap "increment" %eax)
13529 $test-emit-subx-stmt-primitive:initialize-primitive:
13530     # var primitives/ebx: (addr primitive)
13531     68/push 0/imm32/next
13532     68/push 0/imm32/next
13533     68/push 0/imm32/output-is-write-only
13534     68/push 0/imm32/no-disp32
13535     68/push 0/imm32/no-imm32
13536     68/push 0/imm32/no-r32
13537     68/push 1/imm32/rm32-is-first-inout
13538     68/push 0/imm32/subx-name
13539     68/push 0/imm32/subx-name
13540     68/push 0/imm32/no-outputs
13541     68/push 0/imm32/no-outputs
13542     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
13543     68/push 0x11/imm32/alloc-id:fake
13544     68/push 0/imm32/name
13545     68/push 0/imm32/name
13546     89/<- %ebx 4/r32/esp
13547 $test-emit-subx-stmt-primitive:initialize-primitive-name:
13548     # primitives->name = "increment"
13549     (copy-array Heap "increment" %ebx)  # Primitive-name
13550 $test-emit-subx-stmt-primitive:initialize-primitive-subx-name:
13551     # primitives->subx-name = "ff 0/subop/increment"
13552     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
13553     (copy-array Heap "ff 0/subop/increment" %eax)
13554     # convert
13555     c7 0/subop/copy *Curr-block-depth 0/imm32
13556     (emit-subx-stmt _test-output-buffered-file %esi %ebx)
13557     (flush _test-output-buffered-file)
13558 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
13564     # check output
13565     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-stmt-primitive")
13566     # . epilogue
13567     89/<- %esp 5/r32/ebp
13568     5d/pop-to-ebp
13569     c3/return
13570 
13571 test-emit-subx-stmt-primitive-register:
13572     # Primitive operation on a variable in a register.
13573     #   foo <- increment
13574     # =>
13575     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
13576     #
13577     # There's a variable on the var stack as follows:
13578     #   name: 'foo'
13579     #   type: int
13580     #   register: 'eax'
13581     #
13582     # There's a primitive with this info:
13583     #   name: 'increment'
13584     #   out: int/reg
13585     #   value: 'ff 0/subop/increment'
13586     #
13587     # . prologue
13588     55/push-ebp
13589     89/<- %ebp 4/r32/esp
13590     # setup
13591     (clear-stream _test-output-stream)
13592     (clear-stream $_test-output-buffered-file->buffer)
13593 $test-emit-subx-stmt-primitive-register:initialize-type:
13594     # var type/ecx: (payload tree type-id) = int
13595     68/push 0/imm32/right:null
13596     68/push 0/imm32/right:null
13597     68/push 0/imm32/left:unused
13598     68/push 1/imm32/value:int
13599     68/push 1/imm32/is-atom?:true
13600     68/push 0x11/imm32/alloc-id:fake:payload
13601     89/<- %ecx 4/r32/esp
13602 $test-emit-subx-stmt-primitive-register:initialize-var:
13603     # var var-foo/ecx: (payload var)
13604     68/push 0/imm32/register
13605     68/push 0/imm32/register
13606     68/push 0/imm32/no-stack-offset
13607     68/push 1/imm32/block-depth
13608     51/push-ecx
13609     68/push 0x11/imm32/alloc-id:fake
13610     68/push 0/imm32/name
13611     68/push 0/imm32/name
13612     68/push 0x11/imm32/alloc-id:fake:payload
13613     89/<- %ecx 4/r32/esp
13614 $test-emit-subx-stmt-primitive-register:initialize-var-name:
13615     # var-foo->name = "foo"
13616     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
13617     (copy-array Heap "foo" %eax)
13618 $test-emit-subx-stmt-primitive-register:initialize-var-register:
13619     # var-foo->register = "eax"
13620     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
13621     (copy-array Heap "eax" %eax)
13622 $test-emit-subx-stmt-primitive-register:initialize-stmt-var:
13623     # var operand/ebx: (payload stmt-var)
13624     68/push 0/imm32/is-deref:false
13625     68/push 0/imm32/next
13626     68/push 0/imm32/next
13627     51/push-ecx/var-foo
13628     68/push 0x11/imm32/alloc-id:fake
13629     68/push 0x11/imm32/alloc-id:fake:payload
13630     89/<- %ebx 4/r32/esp
13631 $test-emit-subx-stmt-primitive-register:initialize-stmt:
13632     # var stmt/esi: (addr statement)
13633     53/push-ebx/outputs
13634     68/push 0x11/imm32/alloc-id:fake
13635     68/push 0/imm32/no-inouts
13636     68/push 0/imm32/no-inouts
13637     68/push 0/imm32/operation
13638     68/push 0/imm32/operation
13639     68/push 1/imm32
13640     89/<- %esi 4/r32/esp
13641 $test-emit-subx-stmt-primitive-register:initialize-stmt-operation:
13642     # stmt->operation = "increment"
13643     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
13644     (copy-array Heap "increment" %eax)
13645 $test-emit-subx-stmt-primitive-register:initialize-formal-var:
13646     # var formal-var/ebx: (payload var)
13647     68/push 0/imm32/register
13648     68/push 0/imm32/register
13649     68/push 0/imm32/no-stack-offset
13650     68/push 1/imm32/block-depth
13651     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
13652     68/push 0x11/imm32/alloc-id:fake
13653     68/push 0/imm32/name
13654     68/push 0/imm32/name
13655     68/push 0x11/imm32/alloc-id:fake:payload
13656     89/<- %ebx 4/r32/esp
13657 $test-emit-subx-stmt-primitive-register:initialize-formal-var-name:
13658     # formal-var->name = "dummy"
13659     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
13660     (copy-array Heap "dummy" %eax)
13661 $test-emit-subx-stmt-primitive-register:initialize-formal-register:
13662     # formal-var->register = "*"
13663     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
13664     (copy-array Heap "*" %eax)  # Any-register
13665 $test-emit-subx-stmt-primitive-register:initialize-var-list:
13666     # var formal-outputs/ebx: (payload list var)
13667     68/push 0/imm32/next
13668     68/push 0/imm32/next
13669     53/push-ebx/formal-var
13670     68/push 0x11/imm32/alloc-id:fake
13671     68/push 0x11/imm32/alloc-id:fake:payload
13672     89/<- %ebx 4/r32/esp
13673 $test-emit-subx-stmt-primitive-register:initialize-primitive:
13674     # var primitives/ebx: (addr primitive)
13675     68/push 0/imm32/next
13676     68/push 0/imm32/next
13677     68/push 0/imm32/output-is-write-only
13678     68/push 0/imm32/no-disp32
13679     68/push 0/imm32/no-imm32
13680     68/push 0/imm32/no-r32
13681     68/push 3/imm32/rm32-is-first-output
13682     68/push 0/imm32/subx-name
13683     68/push 0/imm32/subx-name
13684     53/push-ebx/outputs
13685     68/push 0x11/imm32/alloc-id:fake
13686     68/push 0/imm32/no-inouts
13687     68/push 0/imm32/no-inouts
13688     68/push 0/imm32/name
13689     68/push 0/imm32/name
13690     89/<- %ebx 4/r32/esp
13691 $test-emit-subx-stmt-primitive-register:initialize-primitive-name:
13692     # primitives->name = "increment"
13693     (copy-array Heap "increment" %ebx)  # Primitive-name
13694 $test-emit-subx-stmt-primitive-register:initialize-primitive-subx-name:
13695     # primitives->subx-name = "ff 0/subop/increment"
13696     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
13697     (copy-array Heap "ff 0/subop/increment" %eax)
13698     # convert
13699     c7 0/subop/copy *Curr-block-depth 0/imm32
13700     (emit-subx-stmt _test-output-buffered-file %esi %ebx)
13701     (flush _test-output-buffered-file)
13702 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
13708     # check output
13709     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-primitive-register")
13710     # . epilogue
13711     89/<- %esp 5/r32/ebp
13712     5d/pop-to-ebp
13713     c3/return
13714 
13715 test-emit-subx-stmt-select-primitive:
13716     # Select the right primitive between overloads.
13717     #   foo <- increment
13718     # =>
13719     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
13720     #
13721     # There's a variable on the var stack as follows:
13722     #   name: 'foo'
13723     #   type: int
13724     #   register: 'eax'
13725     #
13726     # There's two primitives, as follows:
13727     #   - name: 'increment'
13728     #     out: int/reg
13729     #     value: 'ff 0/subop/increment'
13730     #   - name: 'increment'
13731     #     inout: int/mem
13732     #     value: 'ff 0/subop/increment'
13733     #
13734     # . prologue
13735     55/push-ebp
13736     89/<- %ebp 4/r32/esp
13737     # setup
13738     (clear-stream _test-output-stream)
13739     (clear-stream $_test-output-buffered-file->buffer)
13740 $test-emit-subx-stmt-select-primitive:initialize-type:
13741     # var type/ecx: (payload tree type-id) = int
13742     68/push 0/imm32/right:null
13743     68/push 0/imm32/right:null
13744     68/push 0/imm32/left:unused
13745     68/push 1/imm32/value:int
13746     68/push 1/imm32/is-atom?:true
13747     68/push 0x11/imm32/alloc-id:fake:payload
13748     89/<- %ecx 4/r32/esp
13749 $test-emit-subx-stmt-select-primitive:initialize-var:
13750     # var var-foo/ecx: (payload var)
13751     68/push 0/imm32/register
13752     68/push 0/imm32/register
13753     68/push 0/imm32/no-stack-offset
13754     68/push 1/imm32/block-depth
13755     51/push-ecx
13756     68/push 0x11/imm32/alloc-id:fake
13757     68/push 0/imm32/name
13758     68/push 0/imm32/name
13759     68/push 0x11/imm32/alloc-id:fake:payload
13760     89/<- %ecx 4/r32/esp
13761 $test-emit-subx-stmt-select-primitive:initialize-var-name:
13762     # var-foo->name = "foo"
13763     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
13764     (copy-array Heap "foo" %eax)
13765 $test-emit-subx-stmt-select-primitive:initialize-var-register:
13766     # var-foo->register = "eax"
13767     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
13768     (copy-array Heap "eax" %eax)
13769 $test-emit-subx-stmt-select-primitive:initialize-stmt-var:
13770     # var operand/ebx: (payload stmt-var)
13771     68/push 0/imm32/is-deref:false
13772     68/push 0/imm32/next
13773     68/push 0/imm32/next
13774     51/push-ecx/var-foo
13775     68/push 0x11/imm32/alloc-id:fake
13776     68/push 0x11/imm32/alloc-id:fake:payload
13777     89/<- %ebx 4/r32/esp
13778 $test-emit-subx-stmt-select-primitive:initialize-stmt:
13779     # var stmt/esi: (addr statement)
13780     53/push-ebx/outputs
13781     68/push 0x11/imm32/alloc-id:fake
13782     68/push 0/imm32/no-inouts
13783     68/push 0/imm32/no-inouts
13784     68/push 0/imm32/operation
13785     68/push 0/imm32/operation
13786     68/push 1/imm32
13787     89/<- %esi 4/r32/esp
13788 $test-emit-subx-stmt-select-primitive:initialize-stmt-operation:
13789     # stmt->operation = "increment"
13790     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
13791     (copy-array Heap "increment" %eax)
13792 $test-emit-subx-stmt-select-primitive:initialize-formal-var:
13793     # var formal-var/ebx: (payload var)
13794     68/push 0/imm32/register
13795     68/push 0/imm32/register
13796     68/push 0/imm32/no-stack-offset
13797     68/push 1/imm32/block-depth
13798     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
13799     68/push 0x11/imm32/alloc-id:fake
13800     68/push 0/imm32/name
13801     68/push 0/imm32/name
13802     68/push 0x11/imm32/alloc-id:fake:payload
13803     89/<- %ebx 4/r32/esp
13804 $test-emit-subx-stmt-select-primitive:initialize-formal-var-name:
13805     # formal-var->name = "dummy"
13806     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
13807     (copy-array Heap "dummy" %eax)
13808 $test-emit-subx-stmt-select-primitive:initialize-formal-register:
13809     # formal-var->register = "*"
13810     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
13811     (copy-array Heap "*" %eax)  # Any-register
13812 $test-emit-subx-stmt-select-primitive:initialize-var-list:
13813     # var formal-outputs/ebx: (payload list var)
13814     68/push 0/imm32/next
13815     68/push 0/imm32/next
13816     53/push-ebx/formal-var
13817     68/push 0x11/imm32/alloc-id:fake
13818     68/push 0x11/imm32/alloc-id:fake:payload
13819     89/<- %ebx 4/r32/esp
13820 $test-emit-subx-stmt-select-primitive:initialize-primitive2:
13821     # var primitive2/edi: (payload primitive)
13822     68/push 0/imm32/next
13823     68/push 0/imm32/next
13824     68/push 0/imm32/output-is-write-only
13825     68/push 0/imm32/no-disp32
13826     68/push 0/imm32/no-imm32
13827     68/push 0/imm32/no-r32
13828     68/push 3/imm32/rm32-is-first-output
13829     68/push 0/imm32/subx-name
13830     68/push 0/imm32/subx-name
13831     53/push-ebx/outputs
13832     68/push 0x11/imm32/alloc-id:fake
13833     68/push 0/imm32/no-inouts
13834     68/push 0/imm32/no-inouts
13835     68/push 0/imm32/name
13836     68/push 0/imm32/name
13837     68/push 0x11/imm32/alloc-id:fake:payload
13838     89/<- %edi 4/r32/esp
13839 $test-emit-subx-stmt-select-primitive:initialize-primitive2-name:
13840     # primitives->name = "increment"
13841     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
13842     (copy-array Heap "increment" %eax)
13843 $test-emit-subx-stmt-select-primitive:initialize-primitive2-subx-name:
13844     # primitives->subx-name = "ff 0/subop/increment"
13845     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
13846     (copy-array Heap "ff 0/subop/increment" %eax)
13847 $test-emit-subx-stmt-select-primitive:initialize-primitive:
13848     # var primitives/ebx: (addr primitive)
13849     57/push-edi
13850     68/push 0x11/imm32/alloc-id:fake
13851     68/push 0/imm32/output-is-write-only
13852     68/push 0/imm32/no-disp32
13853     68/push 0/imm32/no-imm32
13854     68/push 0/imm32/no-r32
13855     68/push 1/imm32/rm32-is-first-inout
13856     68/push 0/imm32/subx-name
13857     68/push 0/imm32/subx-name
13858     68/push 0/imm32/no-outputs
13859     68/push 0/imm32/no-outputs
13860     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
13861     68/push 0x11/imm32/alloc-id:fake
13862     68/push 0/imm32/name
13863     68/push 0/imm32/name
13864     89/<- %ebx 4/r32/esp
13865 $test-emit-subx-stmt-select-primitive:initialize-primitive-name:
13866     # primitives->name = "increment"
13867     (copy-array Heap "increment" %ebx)  # Primitive-name
13868 $test-emit-subx-stmt-select-primitive:initialize-primitive-subx-name:
13869     # primitives->subx-name = "ff 0/subop/increment"
13870     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
13871     (copy-array Heap "ff 0/subop/increment" %eax)
13872     # convert
13873     c7 0/subop/copy *Curr-block-depth 0/imm32
13874     (emit-subx-stmt _test-output-buffered-file %esi %ebx)
13875     (flush _test-output-buffered-file)
13876 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
13882     # check output
13883     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive")
13884     # . epilogue
13885     89/<- %esp 5/r32/ebp
13886     5d/pop-to-ebp
13887     c3/return
13888 
13889 test-emit-subx-stmt-select-primitive-2:
13890     # Select the right primitive between overloads.
13891     #   increment foo
13892     # =>
13893     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
13894     #
13895     # There's a variable on the var stack as follows:
13896     #   name: 'foo'
13897     #   type: int
13898     #   register: 'eax'
13899     #
13900     # There's two primitives, as follows:
13901     #   - name: 'increment'
13902     #     out: int/reg
13903     #     value: 'ff 0/subop/increment'
13904     #   - name: 'increment'
13905     #     inout: int/mem
13906     #     value: 'ff 0/subop/increment'
13907     #
13908     # . prologue
13909     55/push-ebp
13910     89/<- %ebp 4/r32/esp
13911     # setup
13912     (clear-stream _test-output-stream)
13913     (clear-stream $_test-output-buffered-file->buffer)
13914 $test-emit-subx-stmt-select-primitive-2:initialize-type:
13915     # var type/ecx: (payload tree type-id) = int
13916     68/push 0/imm32/right:null
13917     68/push 0/imm32/right:null
13918     68/push 0/imm32/left:unused
13919     68/push 1/imm32/value:int
13920     68/push 1/imm32/is-atom?:true
13921     68/push 0x11/imm32/alloc-id:fake:payload
13922     89/<- %ecx 4/r32/esp
13923 $test-emit-subx-stmt-select-primitive-2:initialize-var:
13924     # var var-foo/ecx: (payload var)
13925     68/push 0/imm32/register
13926     68/push 0/imm32/register
13927     68/push 0/imm32/no-stack-offset
13928     68/push 1/imm32/block-depth
13929     51/push-ecx
13930     68/push 0x11/imm32/alloc-id:fake
13931     68/push 0/imm32/name
13932     68/push 0/imm32/name
13933     68/push 0x11/imm32/alloc-id:fake:payload
13934     89/<- %ecx 4/r32/esp
13935 $test-emit-subx-stmt-select-primitive-2:initialize-var-name:
13936     # var-foo->name = "foo"
13937     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
13938     (copy-array Heap "foo" %eax)
13939 $test-emit-subx-stmt-select-primitive-2:initialize-var-register:
13940     # var-foo->register = "eax"
13941     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
13942     (copy-array Heap "eax" %eax)
13943 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-var:
13944     # var operand/ebx: (payload stmt-var)
13945     68/push 0/imm32/is-deref:false
13946     68/push 0/imm32/next
13947     68/push 0/imm32/next
13948     51/push-ecx/var-foo
13949     68/push 0x11/imm32/alloc-id:fake
13950     68/push 0x11/imm32/alloc-id:fake:payload
13951     89/<- %ebx 4/r32/esp
13952 $test-emit-subx-stmt-select-primitive-2:initialize-stmt:
13953     # var stmt/esi: (addr statement)
13954     68/push 0/imm32/no-outputs
13955     68/push 0/imm32/no-outputs
13956     53/push-ebx/inouts
13957     68/push 0x11/imm32/alloc-id:fake
13958     68/push 0/imm32/operation
13959     68/push 0/imm32/operation
13960     68/push 1/imm32
13961     89/<- %esi 4/r32/esp
13962 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-operation:
13963     # stmt->operation = "increment"
13964     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
13965     (copy-array Heap "increment" %eax)
13966 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var:
13967     # var formal-var/ebx: (payload var)
13968     68/push 0/imm32/register
13969     68/push 0/imm32/register
13970     68/push 0/imm32/no-stack-offset
13971     68/push 1/imm32/block-depth
13972     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
13973     68/push 0x11/imm32/alloc-id:fake
13974     68/push 0/imm32/name
13975     68/push 0/imm32/name
13976     68/push 0x11/imm32/alloc-id:fake:payload
13977     89/<- %ebx 4/r32/esp
13978 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var-name:
13979     # formal-var->name = "dummy"
13980     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
13981     (copy-array Heap "dummy" %eax)
13982 $test-emit-subx-stmt-select-primitive-2:initialize-formal-register:
13983     # formal-var->register = "*"
13984     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
13985     (copy-array Heap "*" %eax)  # Any-register
13986 $test-emit-subx-stmt-select-primitive-2:initialize-var-list:
13987     # var formal-outputs/ebx: (payload list stmt-var)
13988     68/push 0/imm32/next
13989     68/push 0/imm32/next
13990     53/push-ebx/formal-var
13991     68/push 0x11/imm32/alloc-id:fake
13992     68/push 0x11/imm32/alloc-id:fake:payload
13993     89/<- %ebx 4/r32/esp
13994 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2:
13995     # var primitive2/edi: (payload primitive)
13996     68/push 0/imm32/next
13997     68/push 0/imm32/next
13998     68/push 0/imm32/output-is-write-only
13999     68/push 0/imm32/no-disp32
14000     68/push 0/imm32/no-imm32
14001     68/push 0/imm32/no-r32
14002     68/push 3/imm32/rm32-is-first-output
14003     68/push 0/imm32/subx-name
14004     68/push 0/imm32/subx-name
14005     53/push-ebx/outputs
14006     68/push 0x11/imm32/alloc-id:fake
14007     68/push 0/imm32/no-inouts
14008     68/push 0/imm32/no-inouts
14009     68/push 0/imm32/name
14010     68/push 0/imm32/name
14011     68/push 0x11/imm32/alloc-id:fake:payload
14012     89/<- %edi 4/r32/esp
14013 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-name:
14014     # primitives->name = "increment"
14015     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
14016     (copy-array Heap "increment" %eax)
14017 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-subx-name:
14018     # primitives->subx-name = "ff 0/subop/increment"
14019     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
14020     (copy-array Heap "ff 0/subop/increment" %eax)
14021 $test-emit-subx-stmt-select-primitive-2:initialize-primitive:
14022     # var primitives/ebx: (addr primitive)
14023     57/push-edi
14024     68/push 0x11/imm32/alloc-id:fake
14025     68/push 0/imm32/output-is-write-only
14026     68/push 0/imm32/no-disp32
14027     68/push 0/imm32/no-imm32
14028     68/push 0/imm32/no-r32
14029     68/push 1/imm32/rm32-is-first-inout
14030     68/push 0/imm32/subx-name
14031     68/push 0/imm32/subx-name
14032     68/push 0/imm32/no-outputs
14033     68/push 0/imm32/no-outputs
14034     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
14035     68/push 0x11/imm32/alloc-id:fake
14036     68/push 0/imm32/name
14037     68/push 0/imm32/name
14038     89/<- %ebx 4/r32/esp
14039 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-name:
14040     # primitives->name = "increment"
14041     (copy-array Heap "increment" %ebx)  # Primitive-name
14042 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-subx-name:
14043     # primitives->subx-name = "ff 0/subop/increment"
14044     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
14045     (copy-array Heap "ff 0/subop/increment" %eax)
14046     # convert
14047     c7 0/subop/copy *Curr-block-depth 0/imm32
14048     (emit-subx-stmt _test-output-buffered-file %esi %ebx)
14049     (flush _test-output-buffered-file)
14050 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
14056     # check output
14057     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive-2")
14058     # . epilogue
14059     89/<- %esp 5/r32/ebp
14060     5d/pop-to-ebp
14061     c3/return
14062 
14063 test-increment-register:
14064     # Select the right register between overloads.
14065     #   foo <- increment
14066     # =>
14067     #   50/increment-eax
14068     #
14069     # There's a variable on the var stack as follows:
14070     #   name: 'foo'
14071     #   type: int
14072     #   register: 'eax'
14073     #
14074     # Primitives are the global definitions.
14075     #
14076     # . prologue
14077     55/push-ebp
14078     89/<- %ebp 4/r32/esp
14079     # setup
14080     (clear-stream _test-output-stream)
14081     (clear-stream $_test-output-buffered-file->buffer)
14082 $test-increment-register:initialize-type:
14083     # var type/ecx: (payload tree type-id) = int
14084     68/push 0/imm32/right:null
14085     68/push 0/imm32/right:null
14086     68/push 0/imm32/left:unused
14087     68/push 1/imm32/value:int
14088     68/push 1/imm32/is-atom?:true
14089     68/push 0x11/imm32/alloc-id:fake:payload
14090     89/<- %ecx 4/r32/esp
14091 $test-increment-register:initialize-var:
14092     # var var-foo/ecx: (payload var)
14093     68/push 0/imm32/register
14094     68/push 0/imm32/register
14095     68/push 0/imm32/no-stack-offset
14096     68/push 1/imm32/block-depth
14097     51/push-ecx
14098     68/push 0x11/imm32/alloc-id:fake
14099     68/push 0/imm32/name
14100     68/push 0/imm32/name
14101     68/push 0x11/imm32/alloc-id:fake:payload
14102     89/<- %ecx 4/r32/esp
14103 $test-increment-register:initialize-var-name:
14104     # var-foo->name = "foo"
14105     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14106     (copy-array Heap "foo" %eax)
14107 $test-increment-register:initialize-var-register:
14108     # var-foo->register = "eax"
14109     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
14110     (copy-array Heap "eax" %eax)
14111 $test-increment-register:initialize-stmt-var:
14112     # var operand/ebx: (payload stmt-var)
14113     68/push 0/imm32/is-deref:false
14114     68/push 0/imm32/next
14115     68/push 0/imm32/next
14116     51/push-ecx/var-foo
14117     68/push 0x11/imm32/alloc-id:fake
14118     68/push 0x11/imm32/alloc-id:fake:payload
14119     89/<- %ebx 4/r32/esp
14120 $test-increment-register:initialize-stmt:
14121     # var stmt/esi: (addr statement)
14122     53/push-ebx/outputs
14123     68/push 0x11/imm32/alloc-id:fake
14124     68/push 0/imm32/no-inouts
14125     68/push 0/imm32/no-inouts
14126     68/push 0/imm32/operation
14127     68/push 0/imm32/operation
14128     68/push 1/imm32
14129     89/<- %esi 4/r32/esp
14130 $test-increment-register:initialize-stmt-operation:
14131     # stmt->operation = "increment"
14132     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
14133     (copy-array Heap "increment" %eax)
14134     # convert
14135     c7 0/subop/copy *Curr-block-depth 0/imm32
14136     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
14137     (flush _test-output-buffered-file)
14138 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
14144     # check output
14145     (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register")
14146     # . epilogue
14147     89/<- %esp 5/r32/ebp
14148     5d/pop-to-ebp
14149     c3/return
14150 
14151 test-add-reg-to-reg:
14152     #   var1/reg <- add var2/reg
14153     # =>
14154     #   01/add-to %var1 var2
14155     #
14156     # . prologue
14157     55/push-ebp
14158     89/<- %ebp 4/r32/esp
14159     # setup
14160     (clear-stream _test-output-stream)
14161     (clear-stream $_test-output-buffered-file->buffer)
14162 $test-add-reg-to-reg:initialize-type:
14163     # var type/ecx: (payload tree type-id) = int
14164     68/push 0/imm32/right:null
14165     68/push 0/imm32/right:null
14166     68/push 0/imm32/left:unused
14167     68/push 1/imm32/value:int
14168     68/push 1/imm32/is-atom?:true
14169     68/push 0x11/imm32/alloc-id:fake:payload
14170     89/<- %ecx 4/r32/esp
14171 $test-add-reg-to-reg:initialize-var1:
14172     # var var1/ecx: (payload var)
14173     68/push 0/imm32/register
14174     68/push 0/imm32/register
14175     68/push 0/imm32/no-stack-offset
14176     68/push 1/imm32/block-depth
14177     51/push-ecx
14178     68/push 0x11/imm32/alloc-id:fake
14179     68/push 0/imm32/name
14180     68/push 0/imm32/name
14181     68/push 0x11/imm32/alloc-id:fake:payload
14182     89/<- %ecx 4/r32/esp
14183 $test-add-reg-to-reg:initialize-var1-name:
14184     # var1->name = "var1"
14185     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14186     (copy-array Heap "var1" %eax)
14187 $test-add-reg-to-reg:initialize-var1-register:
14188     # var1->register = "eax"
14189     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
14190     (copy-array Heap "eax" %eax)
14191 $test-add-reg-to-reg:initialize-var2:
14192     # var var2/edx: (payload var)
14193     68/push 0/imm32/register
14194     68/push 0/imm32/register
14195     68/push 0/imm32/no-stack-offset
14196     68/push 1/imm32/block-depth
14197     ff 6/subop/push *(ecx+0x10)
14198     68/push 0x11/imm32/alloc-id:fake
14199     68/push 0/imm32/name
14200     68/push 0/imm32/name
14201     68/push 0x11/imm32/alloc-id:fake:payload
14202     89/<- %edx 4/r32/esp
14203 $test-add-reg-to-reg:initialize-var2-name:
14204     # var2->name = "var2"
14205     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
14206     (copy-array Heap "var2" %eax)
14207 $test-add-reg-to-reg:initialize-var2-register:
14208     # var2->register = "ecx"
14209     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
14210     (copy-array Heap "ecx" %eax)
14211 $test-add-reg-to-reg:initialize-inouts:
14212     # var inouts/esi: (payload stmt-var) = [var2]
14213     68/push 0/imm32/is-deref:false
14214     68/push 0/imm32/next
14215     68/push 0/imm32/next
14216     52/push-edx/var2
14217     68/push 0x11/imm32/alloc-id:fake
14218     68/push 0x11/imm32/alloc-id:fake:payload
14219     89/<- %esi 4/r32/esp
14220 $test-add-reg-to-reg:initialize-outputs:
14221     # var outputs/edi: (payload stmt-var) = [var1]
14222     68/push 0/imm32/is-deref:false
14223     68/push 0/imm32/next
14224     68/push 0/imm32/next
14225     51/push-ecx/var1
14226     68/push 0x11/imm32/alloc-id:fake
14227     68/push 0x11/imm32/alloc-id:fake:payload
14228     89/<- %edi 4/r32/esp
14229 $test-add-reg-to-reg:initialize-stmt:
14230     # var stmt/esi: (addr statement)
14231     68/push 0/imm32/next
14232     68/push 0/imm32/next
14233     57/push-edi/outputs
14234     68/push 0x11/imm32/alloc-id:fake
14235     56/push-esi/inouts
14236     68/push 0x11/imm32/alloc-id:fake
14237     68/push 0/imm32/operation
14238     68/push 0/imm32/operation
14239     68/push 1/imm32/tag:stmt1
14240     89/<- %esi 4/r32/esp
14241 $test-add-reg-to-reg:initialize-stmt-operation:
14242     # stmt->operation = "add"
14243     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
14244     (copy-array Heap "add" %eax)
14245     # convert
14246     c7 0/subop/copy *Curr-block-depth 0/imm32
14247     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
14248     (flush _test-output-buffered-file)
14249 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
14255     # check output
14256     (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg")
14257     # . epilogue
14258     89/<- %esp 5/r32/ebp
14259     5d/pop-to-ebp
14260     c3/return
14261 
14262 test-add-reg-to-mem:
14263     #   add-to var1 var2/reg
14264     # =>
14265     #   01/add-to *(ebp+__) var2
14266     #
14267     # . prologue
14268     55/push-ebp
14269     89/<- %ebp 4/r32/esp
14270     # setup
14271     (clear-stream _test-output-stream)
14272     (clear-stream $_test-output-buffered-file->buffer)
14273 $test-add-reg-to-mem:initialize-type:
14274     # var type/ecx: (payload tree type-id) = int
14275     68/push 0/imm32/right:null
14276     68/push 0/imm32/right:null
14277     68/push 0/imm32/left:unused
14278     68/push 1/imm32/value:int
14279     68/push 1/imm32/is-atom?:true
14280     68/push 0x11/imm32/alloc-id:fake:payload
14281     89/<- %ecx 4/r32/esp
14282 $test-add-reg-to-mem:initialize-var1:
14283     # var var1/ecx: (payload var)
14284     68/push 0/imm32/register
14285     68/push 0/imm32/register
14286     68/push 8/imm32/stack-offset
14287     68/push 1/imm32/block-depth
14288     51/push-ecx
14289     68/push 0x11/imm32/alloc-id:fake
14290     68/push 0/imm32/name
14291     68/push 0/imm32/name
14292     68/push 0x11/imm32/alloc-id:fake:payload
14293     89/<- %ecx 4/r32/esp
14294 $test-add-reg-to-mem:initialize-var1-name:
14295     # var1->name = "var1"
14296     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14297     (copy-array Heap "var1" %eax)
14298 $test-add-reg-to-mem:initialize-var2:
14299     # var var2/edx: (payload var)
14300     68/push 0/imm32/register
14301     68/push 0/imm32/register
14302     68/push 0/imm32/no-stack-offset
14303     68/push 1/imm32/block-depth
14304     ff 6/subop/push *(ecx+0x10)
14305     68/push 0x11/imm32/alloc-id:fake
14306     68/push 0/imm32/name
14307     68/push 0/imm32/name
14308     68/push 0x11/imm32/alloc-id:fake:payload
14309     89/<- %edx 4/r32/esp
14310 $test-add-reg-to-mem:initialize-var2-name:
14311     # var2->name = "var2"
14312     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
14313     (copy-array Heap "var2" %eax)
14314 $test-add-reg-to-mem:initialize-var2-register:
14315     # var2->register = "ecx"
14316     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
14317     (copy-array Heap "ecx" %eax)
14318 $test-add-reg-to-mem:initialize-inouts:
14319     # var inouts/esi: (payload stmt-var) = [var2]
14320     68/push 0/imm32/is-deref:false
14321     68/push 0/imm32/next
14322     68/push 0/imm32/next
14323     52/push-edx/var2
14324     68/push 0x11/imm32/alloc-id:fake
14325     68/push 0x11/imm32/alloc-id:fake:payload
14326     89/<- %esi 4/r32/esp
14327     # inouts = [var1, var2]
14328     68/push 0/imm32/is-deref:false
14329     56/push-esi/next
14330     68/push 0x11/imm32/alloc-id:fake
14331     51/push-ecx/var1
14332     68/push 0x11/imm32/alloc-id:fake
14333     68/push 0x11/imm32/alloc-id:fake:payload
14334     89/<- %esi 4/r32/esp
14335 $test-add-reg-to-mem:initialize-stmt:
14336     # var stmt/esi: (addr statement)
14337     68/push 0/imm32/next
14338     68/push 0/imm32/next
14339     68/push 0/imm32/outputs
14340     68/push 0/imm32/outputs
14341     56/push-esi/inouts
14342     68/push 0x11/imm32/alloc-id:fake
14343     68/push 0/imm32/operation
14344     68/push 0/imm32/operation
14345     68/push 1/imm32/tag:stmt1
14346     89/<- %esi 4/r32/esp
14347 $test-add-reg-to-mem:initialize-stmt-operation:
14348     # stmt->operation = "add-to"
14349     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
14350     (copy-array Heap "add-to" %eax)
14351     # convert
14352     c7 0/subop/copy *Curr-block-depth 0/imm32
14353     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
14354     (flush _test-output-buffered-file)
14355 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
14361     # check output
14362     (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem")
14363     # . epilogue
14364     89/<- %esp 5/r32/ebp
14365     5d/pop-to-ebp
14366     c3/return
14367 
14368 test-add-mem-to-reg:
14369     #   var1/reg <- add var2
14370     # =>
14371     #   03/add *(ebp+__) var1
14372     #
14373     # . prologue
14374     55/push-ebp
14375     89/<- %ebp 4/r32/esp
14376     # setup
14377     (clear-stream _test-output-stream)
14378     (clear-stream $_test-output-buffered-file->buffer)
14379 $test-add-mem-to-reg:initialize-type:
14380     # var type/ecx: (payload tree type-id) = int
14381     68/push 0/imm32/right:null
14382     68/push 0/imm32/right:null
14383     68/push 0/imm32/left:unused
14384     68/push 1/imm32/value:int
14385     68/push 1/imm32/is-atom?:true
14386     68/push 0x11/imm32/alloc-id:fake:payload
14387     89/<- %ecx 4/r32/esp
14388 $test-add-mem-to-reg:initialize-var:
14389     # var var1/ecx: (payload var)
14390     68/push 0/imm32/register
14391     68/push 0/imm32/register
14392     68/push 0/imm32/no-stack-offset
14393     68/push 1/imm32/block-depth
14394     51/push-ecx
14395     68/push 0x11/imm32/alloc-id:fake
14396     68/push 0/imm32/name
14397     68/push 0/imm32/name
14398     68/push 0x11/imm32/alloc-id:fake:payload
14399     89/<- %ecx 4/r32/esp
14400 $test-add-mem-to-reg:initialize-var-name:
14401     # var1->name = "foo"
14402     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14403     (copy-array Heap "var1" %eax)
14404 $test-add-mem-to-reg:initialize-var-register:
14405     # var1->register = "eax"
14406     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
14407     (copy-array Heap "eax" %eax)
14408 $test-add-mem-to-reg:initialize-var2:
14409     # var var2/edx: (payload var)
14410     68/push 0/imm32/register
14411     68/push 0/imm32/register
14412     68/push 8/imm32/stack-offset
14413     68/push 1/imm32/block-depth
14414     ff 6/subop/push *(ecx+0x10)
14415     68/push 0x11/imm32/alloc-id:fake
14416     68/push 0/imm32/name
14417     68/push 0/imm32/name
14418     68/push 0x11/imm32/alloc-id:fake:payload
14419     89/<- %edx 4/r32/esp
14420 $test-add-mem-to-reg:initialize-var2-name:
14421     # var2->name = "var2"
14422     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
14423     (copy-array Heap "var2" %eax)
14424 $test-add-mem-to-reg:initialize-inouts:
14425     # var inouts/esi: (payload stmt-var) = [var2]
14426     68/push 0/imm32/is-deref:false
14427     68/push 0/imm32/next
14428     68/push 0/imm32/next
14429     52/push-edx/var2
14430     68/push 0x11/imm32/alloc-id:fake
14431     68/push 0x11/imm32/alloc-id:fake:payload
14432     89/<- %esi 4/r32/esp
14433 $test-add-mem-to-reg:initialize-outputs:
14434     # var outputs/edi: (payload stmt-var) = [var1]
14435     68/push 0/imm32/is-deref:false
14436     68/push 0/imm32/next
14437     68/push 0/imm32/next
14438     51/push-ecx/var1
14439     68/push 0x11/imm32/alloc-id:fake
14440     68/push 0x11/imm32/alloc-id:fake:payload
14441     89/<- %edi 4/r32/esp
14442 $test-add-mem-to-reg:initialize-stmt:
14443     # var stmt/esi: (addr statement)
14444     68/push 0/imm32/next
14445     68/push 0/imm32/next
14446     57/push-edi/outputs
14447     68/push 0x11/imm32/alloc-id:fake
14448     56/push-esi/inouts
14449     68/push 0x11/imm32/alloc-id:fake
14450     68/push 0/imm32/operation
14451     68/push 0/imm32/operation
14452     68/push 1/imm32/tag:stmt1
14453     89/<- %esi 4/r32/esp
14454 $test-add-mem-to-reg:initialize-stmt-operation:
14455     # stmt->operation = "add"
14456     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
14457     (copy-array Heap "add" %eax)
14458     # convert
14459     c7 0/subop/copy *Curr-block-depth 0/imm32
14460     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
14461     (flush _test-output-buffered-file)
14462 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
14468     # check output
14469     (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg")
14470     # . epilogue
14471     89/<- %esp 5/r32/ebp
14472     5d/pop-to-ebp
14473     c3/return
14474 
14475 test-add-literal-to-eax:
14476     #   var1/eax <- add 0x34
14477     # =>
14478     #   05/add-to-eax 0x34/imm32
14479     #
14480     # . prologue
14481     55/push-ebp
14482     89/<- %ebp 4/r32/esp
14483     # setup
14484     (clear-stream _test-output-stream)
14485     (clear-stream $_test-output-buffered-file->buffer)
14486 $test-add-literal-to-eax:initialize-var-type:
14487     # var type/ecx: (payload tree type-id) = int
14488     68/push 0/imm32/right:null
14489     68/push 0/imm32/right:null
14490     68/push 0/imm32/left:unused
14491     68/push 1/imm32/value:int
14492     68/push 1/imm32/is-atom?:true
14493     68/push 0x11/imm32/alloc-id:fake:payload
14494     89/<- %ecx 4/r32/esp
14495 $test-add-literal-to-eax:initialize-var:
14496     # var v/ecx: (payload var)
14497     68/push 0/imm32/register
14498     68/push 0/imm32/register
14499     68/push 0/imm32/no-stack-offset
14500     68/push 1/imm32/block-depth
14501     51/push-ecx
14502     68/push 0x11/imm32/alloc-id:fake
14503     68/push 0/imm32/name
14504     68/push 0/imm32/name
14505     68/push 0x11/imm32/alloc-id:fake:payload
14506     89/<- %ecx 4/r32/esp
14507 $test-add-literal-to-eax:initialize-var-name:
14508     # v->name = "v"
14509     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14510     (copy-array Heap "v" %eax)
14511 $test-add-literal-to-eax:initialize-var-register:
14512     # v->register = "eax"
14513     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
14514     (copy-array Heap "eax" %eax)
14515 $test-add-literal-to-eax:initialize-literal-type:
14516     # var type/edx: (payload tree type-id) = literal
14517     68/push 0/imm32/right:null
14518     68/push 0/imm32/right:null
14519     68/push 0/imm32/left:unused
14520     68/push 0/imm32/value:literal
14521     68/push 1/imm32/is-atom?:true
14522     68/push 0x11/imm32/alloc-id:fake:payload
14523     89/<- %edx 4/r32/esp
14524 $test-add-literal-to-eax:initialize-literal:
14525     # var l/edx: (payload var)
14526     68/push 0/imm32/register
14527     68/push 0/imm32/register
14528     68/push 0/imm32/no-stack-offset
14529     68/push 1/imm32/block-depth
14530     52/push-edx
14531     68/push 0x11/imm32/alloc-id:fake
14532     68/push 0/imm32/name
14533     68/push 0/imm32/name
14534     68/push 0x11/imm32/alloc-id:fake:payload
14535     89/<- %edx 4/r32/esp
14536 $test-add-literal-to-eax:initialize-literal-value:
14537     # l->name = "0x34"
14538     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
14539     (copy-array Heap "0x34" %eax)
14540 $test-add-literal-to-eax:initialize-inouts:
14541     # var inouts/esi: (payload stmt-var) = [l]
14542     68/push 0/imm32/is-deref:false
14543     68/push 0/imm32/next
14544     68/push 0/imm32/next
14545     52/push-edx/l
14546     68/push 0x11/imm32/alloc-id:fake
14547     68/push 0x11/imm32/alloc-id:fake:payload
14548     89/<- %esi 4/r32/esp
14549 $test-add-literal-to-eax:initialize-outputs:
14550     # var outputs/edi: (payload stmt-var) = [v]
14551     68/push 0/imm32/is-deref:false
14552     68/push 0/imm32/next
14553     68/push 0/imm32/next
14554     51/push-ecx/v
14555     68/push 0x11/imm32/alloc-id:fake
14556     68/push 0x11/imm32/alloc-id:fake:payload
14557     89/<- %edi 4/r32/esp
14558 $test-add-literal-to-eax:initialize-stmt:
14559     # var stmt/esi: (addr statement)
14560     68/push 0/imm32/next
14561     68/push 0/imm32/next
14562     57/push-edi/outputs
14563     68/push 0x11/imm32/alloc-id:fake
14564     56/push-esi/inouts
14565     68/push 0x11/imm32/alloc-id:fake
14566     68/push 0/imm32/operation
14567     68/push 0/imm32/operation
14568     68/push 1/imm32/tag:stmt1
14569     89/<- %esi 4/r32/esp
14570 $test-add-literal-to-eax:initialize-stmt-operation:
14571     # stmt->operation = "add"
14572     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
14573     (copy-array Heap "add" %eax)
14574     # convert
14575     c7 0/subop/copy *Curr-block-depth 0/imm32
14576     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
14577     (flush _test-output-buffered-file)
14578 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
14584     # check output
14585     (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax")
14586     # . epilogue
14587     89/<- %esp 5/r32/ebp
14588     5d/pop-to-ebp
14589     c3/return
14590 
14591 test-add-literal-to-reg:
14592     #   var1/ecx <- add 0x34
14593     # =>
14594     #   81 0/subop/add %ecx 0x34/imm32
14595     #
14596     # . prologue
14597     55/push-ebp
14598     89/<- %ebp 4/r32/esp
14599     # setup
14600     (clear-stream _test-output-stream)
14601     (clear-stream $_test-output-buffered-file->buffer)
14602 $test-add-literal-to-reg:initialize-var-type:
14603     # var type/ecx: (payload tree type-id) = int
14604     68/push 0/imm32/right:null
14605     68/push 0/imm32/right:null
14606     68/push 0/imm32/left:unused
14607     68/push 1/imm32/value:int
14608     68/push 1/imm32/is-atom?:true
14609     68/push 0x11/imm32/alloc-id:fake:payload
14610     89/<- %ecx 4/r32/esp
14611 $test-add-literal-to-reg:initialize-var:
14612     # var v/ecx: (payload var)
14613     68/push 0/imm32/register
14614     68/push 0/imm32/register
14615     68/push 0/imm32/no-stack-offset
14616     68/push 1/imm32/block-depth
14617     51/push-ecx
14618     68/push 0x11/imm32/alloc-id:fake
14619     68/push 0/imm32/name
14620     68/push 0/imm32/name
14621     68/push 0x11/imm32/alloc-id:fake:payload
14622     89/<- %ecx 4/r32/esp
14623 $test-add-literal-to-reg:initialize-var-name:
14624     # v->name = "v"
14625     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14626     (copy-array Heap "v" %eax)
14627 $test-add-literal-to-reg:initialize-var-register:
14628     # v->register = "ecx"
14629     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
14630     (copy-array Heap "ecx" %eax)
14631 $test-add-literal-to-reg:initialize-literal-type:
14632     # var type/edx: (payload tree type-id) = literal
14633     68/push 0/imm32/right:null
14634     68/push 0/imm32/right:null
14635     68/push 0/imm32/left:unused
14636     68/push 0/imm32/value:literal
14637     68/push 1/imm32/is-atom?:true
14638     68/push 0x11/imm32/alloc-id:fake:payload
14639     89/<- %edx 4/r32/esp
14640 $test-add-literal-to-reg:initialize-literal:
14641     # var l/edx: (payload var)
14642     68/push 0/imm32/register
14643     68/push 0/imm32/register
14644     68/push 0/imm32/no-stack-offset
14645     68/push 1/imm32/block-depth
14646     52/push-edx
14647     68/push 0x11/imm32/alloc-id:fake
14648     68/push 0/imm32/name
14649     68/push 0/imm32/name
14650     68/push 0x11/imm32/alloc-id:fake:payload
14651     89/<- %edx 4/r32/esp
14652 $test-add-literal-to-reg:initialize-literal-value:
14653     # l->name = "0x34"
14654     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
14655     (copy-array Heap "0x34" %eax)
14656 $test-add-literal-to-reg:initialize-inouts:
14657     # var inouts/esi: (payload stmt-var) = [l]
14658     68/push 0/imm32/is-deref:false
14659     68/push 0/imm32/next
14660     68/push 0/imm32/next
14661     52/push-edx/l
14662     68/push 0x11/imm32/alloc-id:fake
14663     68/push 0x11/imm32/alloc-id:fake:payload
14664     89/<- %esi 4/r32/esp
14665 $test-add-literal-to-reg:initialize-outputs:
14666     # var outputs/edi: (payload stmt-var) = [v]
14667     68/push 0/imm32/is-deref:false
14668     68/push 0/imm32/next
14669     68/push 0/imm32/next
14670     51/push-ecx/v
14671     68/push 0x11/imm32/alloc-id:fake
14672     68/push 0x11/imm32/alloc-id:fake:payload
14673     89/<- %edi 4/r32/esp
14674 $test-add-literal-to-reg:initialize-stmt:
14675     # var stmt/esi: (addr statement)
14676     68/push 0/imm32/next
14677     68/push 0/imm32/next
14678     57/push-edi/outputs
14679     68/push 0x11/imm32/alloc-id:fake
14680     56/push-esi/inouts
14681     68/push 0x11/imm32/alloc-id:fake
14682     68/push 0/imm32/operation
14683     68/push 0/imm32/operation
14684     68/push 1/imm32/tag:stmt1
14685     89/<- %esi 4/r32/esp
14686 $test-add-literal-to-reg:initialize-stmt-operation:
14687     # stmt->operation = "add"
14688     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
14689     (copy-array Heap "add" %eax)
14690     # convert
14691     c7 0/subop/copy *Curr-block-depth 0/imm32
14692     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
14693     (flush _test-output-buffered-file)
14694 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
14700     # check output
14701     (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg")
14702     # . epilogue
14703     89/<- %esp 5/r32/ebp
14704     5d/pop-to-ebp
14705     c3/return
14706 
14707 test-add-literal-to-mem:
14708     #   add-to var1, 0x34
14709     # =>
14710     #   81 0/subop/add %eax 0x34/imm32
14711     #
14712     # . prologue
14713     55/push-ebp
14714     89/<- %ebp 4/r32/esp
14715     # setup
14716     (clear-stream _test-output-stream)
14717     (clear-stream $_test-output-buffered-file->buffer)
14718 $test-add-literal-to-mem:initialize-type:
14719     # var type/ecx: (payload tree type-id) = int
14720     68/push 0/imm32/right:null
14721     68/push 0/imm32/right:null
14722     68/push 0/imm32/left:unused
14723     68/push 1/imm32/value:int
14724     68/push 1/imm32/is-atom?:true
14725     68/push 0x11/imm32/alloc-id:fake:payload
14726     89/<- %ecx 4/r32/esp
14727 $test-add-literal-to-mem:initialize-var1:
14728     # var var1/ecx: (payload var)
14729     68/push 0/imm32/register
14730     68/push 0/imm32/register
14731     68/push 8/imm32/stack-offset
14732     68/push 1/imm32/block-depth
14733     51/push-ecx
14734     68/push 0x11/imm32/alloc-id:fake
14735     68/push 0/imm32/name
14736     68/push 0/imm32/name
14737     68/push 0x11/imm32/alloc-id:fake:payload
14738     89/<- %ecx 4/r32/esp
14739 $test-add-literal-to-mem:initialize-var1-name:
14740     # var1->name = "var1"
14741     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14742     (copy-array Heap "var1" %eax)
14743 $test-add-literal-to-mem:initialize-literal-type:
14744     # var type/edx: (payload tree type-id) = literal
14745     68/push 0/imm32/right:null
14746     68/push 0/imm32/right:null
14747     68/push 0/imm32/left:unused
14748     68/push 0/imm32/value:literal
14749     68/push 1/imm32/is-atom?:true
14750     68/push 0x11/imm32/alloc-id:fake:payload
14751     89/<- %edx 4/r32/esp
14752 $test-add-literal-to-mem:initialize-literal:
14753     # var l/edx: (payload var)
14754     68/push 0/imm32/register
14755     68/push 0/imm32/register
14756     68/push 0/imm32/no-stack-offset
14757     68/push 1/imm32/block-depth
14758     52/push-edx
14759     68/push 0x11/imm32/alloc-id:fake
14760     68/push 0/imm32/name
14761     68/push 0/imm32/name
14762     68/push 0x11/imm32/alloc-id:fake:payload
14763     89/<- %edx 4/r32/esp
14764 $test-add-literal-to-mem:initialize-literal-value:
14765     # l->name = "0x34"
14766     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
14767     (copy-array Heap "0x34" %eax)
14768 $test-add-literal-to-mem:initialize-inouts:
14769     # var inouts/esi: (payload stmt-var) = [l]
14770     68/push 0/imm32/is-deref:false
14771     68/push 0/imm32/next
14772     68/push 0/imm32/next
14773     52/push-edx/l
14774     68/push 0x11/imm32/alloc-id:fake
14775     68/push 0x11/imm32/alloc-id:fake:payload
14776     89/<- %esi 4/r32/esp
14777     # var inouts = (handle stmt-var) = [var1, var2]
14778     68/push 0/imm32/is-deref:false
14779     56/push-esi/next
14780     68/push 0x11/imm32/alloc-id:fake
14781     51/push-ecx/var1
14782     68/push 0x11/imm32/alloc-id:fake
14783     68/push 0x11/imm32/alloc-id:fake:payload
14784     89/<- %esi 4/r32/esp
14785 $test-add-literal-to-mem:initialize-stmt:
14786     # var stmt/esi: (addr statement)
14787     68/push 0/imm32/next
14788     68/push 0/imm32/next
14789     68/push 0/imm32/outputs
14790     68/push 0/imm32/outputs
14791     56/push-esi/inouts
14792     68/push 0x11/imm32/alloc-id:fake
14793     68/push 0/imm32/operation
14794     68/push 0/imm32/operation
14795     68/push 1/imm32/tag:stmt1
14796     89/<- %esi 4/r32/esp
14797 $test-add-literal-to-mem:initialize-stmt-operation:
14798     # stmt->operation = "add-to"
14799     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
14800     (copy-array Heap "add-to" %eax)
14801     # convert
14802     c7 0/subop/copy *Curr-block-depth 0/imm32
14803     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
14804     (flush _test-output-buffered-file)
14805 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
14811     # check output
14812     (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem")
14813     # . epilogue
14814     89/<- %esp 5/r32/ebp
14815     5d/pop-to-ebp
14816     c3/return
14817 
14818 test-compare-mem-with-reg:
14819     #   compare var1, var2/eax
14820     # =>
14821     #   39/compare *(ebp+___) 0/r32/eax
14822     #
14823     # . prologue
14824     55/push-ebp
14825     89/<- %ebp 4/r32/esp
14826     # setup
14827     (clear-stream _test-output-stream)
14828     (clear-stream $_test-output-buffered-file->buffer)
14829 $test-compare-mem-with-reg:initialize-type:
14830     # var type/ecx: (payload tree type-id) = int
14831     68/push 0/imm32/right:null
14832     68/push 0/imm32/right:null
14833     68/push 0/imm32/left:unused
14834     68/push 1/imm32/value:int
14835     68/push 1/imm32/is-atom?:true
14836     68/push 0x11/imm32/alloc-id:fake:payload
14837     89/<- %ecx 4/r32/esp
14838 $test-compare-mem-with-reg:initialize-var1:
14839     # var var1/ecx: (payload var)
14840     68/push 0/imm32/register
14841     68/push 0/imm32/register
14842     68/push 8/imm32/stack-offset
14843     68/push 1/imm32/block-depth
14844     51/push-ecx
14845     68/push 0x11/imm32/alloc-id:fake
14846     68/push 0/imm32/name
14847     68/push 0/imm32/name
14848     68/push 0x11/imm32/alloc-id:fake:payload
14849     89/<- %ecx 4/r32/esp
14850 $test-compare-mem-with-reg:initialize-var1-name:
14851     # var1->name = "var1"
14852     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14853     (copy-array Heap "var1" %eax)
14854 $test-compare-mem-with-reg:initialize-var2:
14855     # var var2/edx: (payload var)
14856     68/push 0/imm32/register
14857     68/push 0/imm32/register
14858     68/push 0/imm32/no-stack-offset
14859     68/push 1/imm32/block-depth
14860     ff 6/subop/push *(ecx+0x10)
14861     68/push 0x11/imm32/alloc-id:fake
14862     68/push 0/imm32/name
14863     68/push 0/imm32/name
14864     68/push 0x11/imm32/alloc-id:fake:payload
14865     89/<- %edx 4/r32/esp
14866 $test-compare-mem-with-reg:initialize-var2-name:
14867     # var2->name = "var2"
14868     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
14869     (copy-array Heap "var2" %eax)
14870 $test-compare-mem-with-reg:initialize-var2-register:
14871     # var2->register = "eax"
14872     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
14873     (copy-array Heap "eax" %eax)
14874 $test-compare-mem-with-reg:initialize-inouts:
14875     # var inouts/esi: (payload stmt-var) = [var2]
14876     68/push 0/imm32/is-deref:false
14877     68/push 0/imm32/next
14878     68/push 0/imm32/next
14879     52/push-edx/var2
14880     68/push 0x11/imm32/alloc-id:fake
14881     68/push 0x11/imm32/alloc-id:fake:payload
14882     89/<- %esi 4/r32/esp
14883     # inouts = [var1, var2]
14884     68/push 0/imm32/is-deref:false
14885     56/push-esi/next
14886     68/push 0x11/imm32/alloc-id:fake
14887     51/push-ecx/var1
14888     68/push 0x11/imm32/alloc-id:fake
14889     68/push 0x11/imm32/alloc-id:fake:payload
14890     89/<- %esi 4/r32/esp
14891 $test-compare-mem-with-reg:initialize-stmt:
14892     # var stmt/esi: (addr statement)
14893     68/push 0/imm32/next
14894     68/push 0/imm32/next
14895     68/push 0/imm32/outputs
14896     68/push 0/imm32/outputs
14897     56/push-esi/inouts
14898     68/push 0x11/imm32/alloc-id:fake
14899     68/push 0/imm32/operation
14900     68/push 0/imm32/operation
14901     68/push 1/imm32/tag:stmt1
14902     89/<- %esi 4/r32/esp
14903 $test-compare-mem-with-reg:initialize-stmt-operation:
14904     # stmt->operation = "compare"
14905     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
14906     (copy-array Heap "compare" %eax)
14907     # convert
14908     c7 0/subop/copy *Curr-block-depth 0/imm32
14909     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
14910     (flush _test-output-buffered-file)
14911 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
14917     # check output
14918     (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg")
14919     # . epilogue
14920     89/<- %esp 5/r32/ebp
14921     5d/pop-to-ebp
14922     c3/return
14923 
14924 test-compare-reg-with-mem:
14925     #   compare var1/eax, var2
14926     # =>
14927     #   3b/compare<- *(ebp+___) 0/r32/eax
14928     #
14929     # . prologue
14930     55/push-ebp
14931     89/<- %ebp 4/r32/esp
14932     # setup
14933     (clear-stream _test-output-stream)
14934     (clear-stream $_test-output-buffered-file->buffer)
14935 $test-compare-reg-with-mem:initialize-type:
14936     # var type/ecx: (payload tree type-id) = int
14937     68/push 0/imm32/right:null
14938     68/push 0/imm32/right:null
14939     68/push 0/imm32/left:unused
14940     68/push 1/imm32/value:int
14941     68/push 1/imm32/is-atom?:true
14942     68/push 0x11/imm32/alloc-id:fake:payload
14943     89/<- %ecx 4/r32/esp
14944 $test-compare-reg-with-mem:initialize-var1:
14945     # var var1/ecx: (payload var)
14946     68/push 0/imm32/register
14947     68/push 0/imm32/register
14948     68/push 0/imm32/no-stack-offset
14949     68/push 1/imm32/block-depth
14950     51/push-ecx
14951     68/push 0x11/imm32/alloc-id:fake
14952     68/push 0/imm32/name
14953     68/push 0/imm32/name
14954     68/push 0x11/imm32/alloc-id:fake:payload
14955     89/<- %ecx 4/r32/esp
14956 $test-compare-reg-with-mem:initialize-var1-name:
14957     # var1->name = "var1"
14958     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14959     (copy-array Heap "var1" %eax)
14960 $test-compare-reg-with-mem:initialize-var1-register:
14961     # var1->register = "eax"
14962     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
14963     (copy-array Heap "eax" %eax)
14964 $test-compare-reg-with-mem:initialize-var2:
14965     # var var2/edx: (payload var)
14966     68/push 0/imm32/register
14967     68/push 0/imm32/register
14968     68/push 8/imm32/stack-offset
14969     68/push 1/imm32/block-depth
14970     ff 6/subop/push *(ecx+0x10)
14971     68/push 0x11/imm32/alloc-id:fake
14972     68/push 0/imm32/name
14973     68/push 0/imm32/name
14974     68/push 0x11/imm32/alloc-id:fake:payload
14975     89/<- %edx 4/r32/esp
14976 $test-compare-reg-with-mem:initialize-var2-name:
14977     # var2->name = "var2"
14978     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
14979     (copy-array Heap "var2" %eax)
14980 $test-compare-reg-with-mem:initialize-inouts:
14981     # var inouts/esi: (payload stmt-var) = [var2]
14982     68/push 0/imm32/is-deref:false
14983     68/push 0/imm32/next
14984     68/push 0/imm32/next
14985     52/push-edx/var2
14986     68/push 0x11/imm32/alloc-id:fake
14987     68/push 0x11/imm32/alloc-id:fake:payload
14988     89/<- %esi 4/r32/esp
14989     # inouts = [var1, var2]
14990     68/push 0/imm32/is-deref:false
14991     56/push-esi/next
14992     68/push 0x11/imm32/alloc-id:fake
14993     51/push-ecx/var1
14994     68/push 0x11/imm32/alloc-id:fake
14995     68/push 0x11/imm32/alloc-id:fake:payload
14996     89/<- %esi 4/r32/esp
14997 $test-compare-reg-with-mem:initialize-stmt:
14998     # var stmt/esi: (addr statement)
14999     68/push 0/imm32/next
15000     68/push 0/imm32/next
15001     68/push 0/imm32/outputs
15002     68/push 0/imm32/outputs
15003     56/push-esi/inouts
15004     68/push 0x11/imm32/alloc-id:fake
15005     68/push 0/imm32/operation
15006     68/push 0/imm32/operation
15007     68/push 1/imm32/tag:stmt1
15008     89/<- %esi 4/r32/esp
15009 $test-compare-reg-with-mem:initialize-stmt-operation:
15010     # stmt->operation = "compare"
15011     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15012     (copy-array Heap "compare" %eax)
15013     # convert
15014     c7 0/subop/copy *Curr-block-depth 0/imm32
15015     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
15016     (flush _test-output-buffered-file)
15017 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
15023     # check output
15024     (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem")
15025     # . epilogue
15026     89/<- %esp 5/r32/ebp
15027     5d/pop-to-ebp
15028     c3/return
15029 
15030 test-compare-mem-with-literal:
15031     #   compare var1, 0x34
15032     # =>
15033     #   81 7/subop/compare *(ebp+___) 0x34/imm32
15034     #
15035     # . prologue
15036     55/push-ebp
15037     89/<- %ebp 4/r32/esp
15038     # setup
15039     (clear-stream _test-output-stream)
15040     (clear-stream $_test-output-buffered-file->buffer)
15041 $test-compare-mem-with-literal:initialize-type:
15042     # var type/ecx: (payload tree type-id) = int
15043     68/push 0/imm32/right:null
15044     68/push 0/imm32/right:null
15045     68/push 0/imm32/left:unused
15046     68/push 1/imm32/value:int
15047     68/push 1/imm32/is-atom?:true
15048     68/push 0x11/imm32/alloc-id:fake:payload
15049     89/<- %ecx 4/r32/esp
15050 $test-compare-mem-with-literal:initialize-var1:
15051     # var var1/ecx: (payload var)
15052     68/push 0/imm32/register
15053     68/push 0/imm32/register
15054     68/push 8/imm32/stack-offset
15055     68/push 1/imm32/block-depth
15056     51/push-ecx
15057     68/push 0x11/imm32/alloc-id:fake
15058     68/push 0/imm32/name
15059     68/push 0/imm32/name
15060     68/push 0x11/imm32/alloc-id:fake:payload
15061     89/<- %ecx 4/r32/esp
15062 $test-compare-mem-with-literal:initialize-var1-name:
15063     # var1->name = "var1"
15064     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15065     (copy-array Heap "var1" %eax)
15066 $test-compare-mem-with-literal:initialize-literal-type:
15067     # var type/edx: (payload tree type-id) = literal
15068     68/push 0/imm32/right:null
15069     68/push 0/imm32/right:null
15070     68/push 0/imm32/left:unused
15071     68/push 0/imm32/value:literal
15072     68/push 1/imm32/is-atom?:true
15073     68/push 0x11/imm32/alloc-id:fake:payload
15074     89/<- %edx 4/r32/esp
15075 $test-compare-mem-with-literal:initialize-literal:
15076     # var l/edx: (payload var)
15077     68/push 0/imm32/register
15078     68/push 0/imm32/register
15079     68/push 0/imm32/no-stack-offset
15080     68/push 1/imm32/block-depth
15081     52/push-edx
15082     68/push 0x11/imm32/alloc-id:fake
15083     68/push 0/imm32/name
15084     68/push 0/imm32/name
15085     68/push 0x11/imm32/alloc-id:fake:payload
15086     89/<- %edx 4/r32/esp
15087 $test-compare-mem-with-literal:initialize-literal-value:
15088     # l->name = "0x34"
15089     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
15090     (copy-array Heap "0x34" %eax)
15091 $test-compare-mem-with-literal:initialize-inouts:
15092     # var inouts/esi: (payload stmt-var) = [l]
15093     68/push 0/imm32/is-deref:false
15094     68/push 0/imm32/next
15095     68/push 0/imm32/next
15096     52/push-edx/l
15097     68/push 0x11/imm32/alloc-id:fake
15098     68/push 0x11/imm32/alloc-id:fake:payload
15099     89/<- %esi 4/r32/esp
15100     # var inouts = (handle stmt-var) = [var1, var2]
15101     68/push 0/imm32/is-deref:false
15102     56/push-esi/next
15103     68/push 0x11/imm32/alloc-id:fake
15104     51/push-ecx/var1
15105     68/push 0x11/imm32/alloc-id:fake
15106     68/push 0x11/imm32/alloc-id:fake:payload
15107     89/<- %esi 4/r32/esp
15108 $test-compare-mem-with-literal:initialize-stmt:
15109     # var stmt/esi: (addr statement)
15110     68/push 0/imm32/next
15111     68/push 0/imm32/next
15112     68/push 0/imm32/outputs
15113     68/push 0/imm32/outputs
15114     56/push-esi/inouts
15115     68/push 0x11/imm32/alloc-id:fake
15116     68/push 0/imm32/operation
15117     68/push 0/imm32/operation
15118     68/push 1/imm32/tag:stmt1
15119     89/<- %esi 4/r32/esp
15120 $test-compare-mem-with-literal:initialize-stmt-operation:
15121     # stmt->operation = "compare"
15122     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15123     (copy-array Heap "compare" %eax)
15124     # convert
15125     c7 0/subop/copy *Curr-block-depth 0/imm32
15126     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
15127     (flush _test-output-buffered-file)
15128 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
15134     # check output
15135     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal")
15136     # . epilogue
15137     89/<- %esp 5/r32/ebp
15138     5d/pop-to-ebp
15139     c3/return
15140 
15141 test-compare-eax-with-literal:
15142     #   compare var1/eax 0x34
15143     # =>
15144     #   3d/compare-eax-with 0x34/imm32
15145     #
15146     # . prologue
15147     55/push-ebp
15148     89/<- %ebp 4/r32/esp
15149     # setup
15150     (clear-stream _test-output-stream)
15151     (clear-stream $_test-output-buffered-file->buffer)
15152 $test-compare-eax-with-literal:initialize-type:
15153     # var type/ecx: (payload tree type-id) = int
15154     68/push 0/imm32/right:null
15155     68/push 0/imm32/right:null
15156     68/push 0/imm32/left:unused
15157     68/push 1/imm32/value:int
15158     68/push 1/imm32/is-atom?:true
15159     68/push 0x11/imm32/alloc-id:fake:payload
15160     89/<- %ecx 4/r32/esp
15161 $test-compare-eax-with-literal:initialize-var1:
15162     # var var1/ecx: (payload var)
15163     68/push 0/imm32/register
15164     68/push 0/imm32/register
15165     68/push 0/imm32/no-stack-offset
15166     68/push 1/imm32/block-depth
15167     51/push-ecx
15168     68/push 0x11/imm32/alloc-id:fake
15169     68/push 0/imm32/name
15170     68/push 0/imm32/name
15171     68/push 0x11/imm32/alloc-id:fake:payload
15172     89/<- %ecx 4/r32/esp
15173 $test-compare-eax-with-literal:initialize-var1-name:
15174     # var1->name = "var1"
15175     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15176     (copy-array Heap "var1" %eax)
15177 $test-compare-eax-with-literal:initialize-var1-register:
15178     # v->register = "eax"
15179     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
15180     (copy-array Heap "eax" %eax)
15181 $test-compare-eax-with-literal:initialize-literal-type:
15182     # var type/edx: (payload tree type-id) = literal
15183     68/push 0/imm32/right:null
15184     68/push 0/imm32/right:null
15185     68/push 0/imm32/left:unused
15186     68/push 0/imm32/value:literal
15187     68/push 1/imm32/is-atom?:true
15188     68/push 0x11/imm32/alloc-id:fake:payload
15189     89/<- %edx 4/r32/esp
15190 $test-compare-eax-with-literal:initialize-literal:
15191     # var l/edx: (payload var)
15192     68/push 0/imm32/register
15193     68/push 0/imm32/register
15194     68/push 0/imm32/no-stack-offset
15195     68/push 1/imm32/block-depth
15196     52/push-edx
15197     68/push 0x11/imm32/alloc-id:fake
15198     68/push 0/imm32/name
15199     68/push 0/imm32/name
15200     68/push 0x11/imm32/alloc-id:fake:payload
15201     89/<- %edx 4/r32/esp
15202 $test-compare-eax-with-literal:initialize-literal-value:
15203     # l->name = "0x34"
15204     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
15205     (copy-array Heap "0x34" %eax)
15206 $test-compare-eax-with-literal:initialize-inouts:
15207     # var inouts/esi: (payload stmt-var) = [l]
15208     68/push 0/imm32/is-deref:false
15209     68/push 0/imm32/next
15210     68/push 0/imm32/next
15211     52/push-edx/l
15212     68/push 0x11/imm32/alloc-id:fake
15213     68/push 0x11/imm32/alloc-id:fake:payload
15214     89/<- %esi 4/r32/esp
15215     # var inouts = (handle stmt-var) = [var1, var2]
15216     68/push 0/imm32/is-deref:false
15217     56/push-esi/next
15218     68/push 0x11/imm32/alloc-id:fake
15219     51/push-ecx/var1
15220     68/push 0x11/imm32/alloc-id:fake
15221     68/push 0x11/imm32/alloc-id:fake:payload
15222     89/<- %esi 4/r32/esp
15223 $test-compare-eax-with-literal:initialize-stmt:
15224     # var stmt/esi: (addr statement)
15225     68/push 0/imm32/next
15226     68/push 0/imm32/next
15227     68/push 0/imm32/outputs
15228     68/push 0/imm32/outputs
15229     56/push-esi/inouts
15230     68/push 0x11/imm32/alloc-id:fake
15231     68/push 0/imm32/operation
15232     68/push 0/imm32/operation
15233     68/push 1/imm32/tag:stmt1
15234     89/<- %esi 4/r32/esp
15235 $test-compare-eax-with-literal:initialize-stmt-operation:
15236     # stmt->operation = "compare"
15237     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15238     (copy-array Heap "compare" %eax)
15239     # convert
15240     c7 0/subop/copy *Curr-block-depth 0/imm32
15241     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
15242     (flush _test-output-buffered-file)
15243 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
15249     # check output
15250     (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal")
15251     # . epilogue
15252     89/<- %esp 5/r32/ebp
15253     5d/pop-to-ebp
15254     c3/return
15255 
15256 test-compare-reg-with-literal:
15257     #   compare var1/ecx 0x34
15258     # =>
15259     #   81 7/subop/compare %ecx 0x34/imm32
15260     #
15261     # . prologue
15262     55/push-ebp
15263     89/<- %ebp 4/r32/esp
15264     # setup
15265     (clear-stream _test-output-stream)
15266     (clear-stream $_test-output-buffered-file->buffer)
15267 $test-compare-reg-with-literal:initialize-type:
15268     # var type/ecx: (payload tree type-id) = int
15269     68/push 0/imm32/right:null
15270     68/push 0/imm32/right:null
15271     68/push 0/imm32/left:unused
15272     68/push 1/imm32/value:int
15273     68/push 1/imm32/is-atom?:true
15274     68/push 0x11/imm32/alloc-id:fake:payload
15275     89/<- %ecx 4/r32/esp
15276 $test-compare-reg-with-literal:initialize-var1:
15277     # var var1/ecx: (payload var)
15278     68/push 0/imm32/register
15279     68/push 0/imm32/register
15280     68/push 0/imm32/no-stack-offset
15281     68/push 1/imm32/block-depth
15282     51/push-ecx
15283     68/push 0x11/imm32/alloc-id:fake
15284     68/push 0/imm32/name
15285     68/push 0/imm32/name
15286     68/push 0x11/imm32/alloc-id:fake:payload
15287     89/<- %ecx 4/r32/esp
15288 $test-compare-reg-with-literal:initialize-var1-name:
15289     # var1->name = "var1"
15290     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15291     (copy-array Heap "var1" %eax)
15292 $test-compare-reg-with-literal:initialize-var1-register:
15293     # v->register = "ecx"
15294     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
15295     (copy-array Heap "ecx" %eax)
15296 $test-compare-reg-with-literal:initialize-literal-type:
15297     # var type/edx: (payload tree type-id) = literal
15298     68/push 0/imm32/right:null
15299     68/push 0/imm32/right:null
15300     68/push 0/imm32/left:unused
15301     68/push 0/imm32/value:literal
15302     68/push 1/imm32/is-atom?:true
15303     68/push 0x11/imm32/alloc-id:fake:payload
15304     89/<- %edx 4/r32/esp
15305 $test-compare-reg-with-literal:initialize-literal:
15306     # var l/edx: (payload var)
15307     68/push 0/imm32/register
15308     68/push 0/imm32/register
15309     68/push 0/imm32/no-stack-offset
15310     68/push 1/imm32/block-depth
15311     52/push-edx
15312     68/push 0x11/imm32/alloc-id:fake
15313     68/push 0/imm32/name
15314     68/push 0/imm32/name
15315     68/push 0x11/imm32/alloc-id:fake:payload
15316     89/<- %edx 4/r32/esp
15317 $test-compare-reg-with-literal:initialize-literal-value:
15318     # l->name = "0x34"
15319     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
15320     (copy-array Heap "0x34" %eax)
15321 $test-compare-reg-with-literal:initialize-inouts:
15322     # var inouts/esi: (payload stmt-var) = [l]
15323     68/push 0/imm32/is-deref:false
15324     68/push 0/imm32/next
15325     68/push 0/imm32/next
15326     52/push-edx/l
15327     68/push 0x11/imm32/alloc-id:fake
15328     68/push 0x11/imm32/alloc-id:fake:payload
15329     89/<- %esi 4/r32/esp
15330     # var inouts = (handle stmt-var) = [var1, var2]
15331     68/push 0/imm32/is-deref:false
15332     56/push-esi/next
15333     68/push 0x11/imm32/alloc-id:fake
15334     51/push-ecx/var1
15335     68/push 0x11/imm32/alloc-id:fake
15336     68/push 0x11/imm32/alloc-id:fake:payload
15337     89/<- %esi 4/r32/esp
15338 $test-compare-reg-with-literal:initialize-stmt:
15339     # var stmt/esi: (addr statement)
15340     68/push 0/imm32/next
15341     68/push 0/imm32/next
15342     68/push 0/imm32/outputs
15343     68/push 0/imm32/outputs
15344     56/push-esi/inouts
15345     68/push 0x11/imm32/alloc-id:fake
15346     68/push 0/imm32/operation
15347     68/push 0/imm32/operation
15348     68/push 1/imm32/tag:stmt1
15349     89/<- %esi 4/r32/esp
15350 $test-compare-reg-with-literal:initialize-stmt-operation:
15351     # stmt->operation = "compare"
15352     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15353     (copy-array Heap "compare" %eax)
15354     # convert
15355     c7 0/subop/copy *Curr-block-depth 0/imm32
15356     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
15357     (flush _test-output-buffered-file)
15358 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
15364     # check output
15365     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal")
15366     # . epilogue
15367     89/<- %esp 5/r32/ebp
15368     5d/pop-to-ebp
15369     c3/return
15370 
15371 test-emit-subx-stmt-function-call:
15372     # Call a function on a variable on the stack.
15373     #   f foo
15374     # =>
15375     #   (f *(ebp-8))
15376     # (Changing the function name supports overloading in general, but here it
15377     # just serves to help disambiguate things.)
15378     #
15379     # There's a variable on the var stack as follows:
15380     #   name: 'foo'
15381     #   type: int
15382     #   stack-offset: -8
15383     #
15384     # There's nothing in primitives.
15385     #
15386     # We don't perform any checking here on the type of 'f'.
15387     #
15388     # . prologue
15389     55/push-ebp
15390     89/<- %ebp 4/r32/esp
15391     # setup
15392     (clear-stream _test-output-stream)
15393     (clear-stream $_test-output-buffered-file->buffer)
15394 $test-emit-subx-function-call:initialize-type:
15395     # var type/ecx: (payload tree type-id) = int
15396     68/push 0/imm32/right:null
15397     68/push 0/imm32/right:null
15398     68/push 0/imm32/left:unused
15399     68/push 1/imm32/value:int
15400     68/push 1/imm32/is-atom?:true
15401     68/push 0x11/imm32/alloc-id:fake:payload
15402     89/<- %ecx 4/r32/esp
15403 $test-emit-subx-function-call:initialize-var:
15404     # var var-foo/ecx: (payload var) = var(type)
15405     68/push 0/imm32/no-register
15406     68/push 0/imm32/no-register
15407     68/push -8/imm32/stack-offset
15408     68/push 1/imm32/block-depth
15409     51/push-ecx/type
15410     68/push 0x11/imm32/alloc-id:fake
15411     68/push 0/imm32/name
15412     68/push 0/imm32/name
15413     68/push 0x11/imm32/alloc-id:fake:payload
15414     89/<- %ecx 4/r32/esp
15415 $test-emit-subx-function-call:initialize-var-name:
15416     # var-foo->name = "foo"
15417     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15418     (copy-array Heap "foo" %eax)
15419 $test-emit-subx-function-call:initialize-stmt-var:
15420     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
15421     68/push 0/imm32/is-deref:false
15422     68/push 0/imm32/next
15423     68/push 0/imm32/next
15424     51/push-ecx/var-foo
15425     68/push 0x11/imm32/alloc-id:fake
15426     68/push 0x11/imm32/alloc-id:fake:payload
15427     89/<- %ebx 4/r32/esp
15428 $test-emit-subx-function-call:initialize-stmt:
15429     # var stmt/esi: (addr statement)
15430     68/push 0/imm32/no-outputs
15431     68/push 0/imm32/no-outputs
15432     53/push-ebx/inouts
15433     68/push 0x11/imm32/alloc-id:fake
15434     68/push 0/imm32/operation
15435     68/push 0/imm32/operation
15436     68/push 1/imm32/tag
15437     89/<- %esi 4/r32/esp
15438 $test-emit-subx-function-call:initialize-stmt-operation:
15439     # stmt->operation = "f"
15440     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15441     (copy-array Heap "f" %eax)
15442     # convert
15443     c7 0/subop/copy *Curr-block-depth 0/imm32
15444     (emit-subx-stmt _test-output-buffered-file %esi 0)
15445     (flush _test-output-buffered-file)
15446 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
15452     # check output
15453     (check-next-stream-line-equal _test-output-stream "(f *(ebp+0xfffffff8))" "F - test-emit-subx-stmt-function-call")
15454     # . epilogue
15455     89/<- %esp 5/r32/ebp
15456     5d/pop-to-ebp
15457     c3/return
15458 
15459 test-emit-subx-stmt-function-call-with-literal-arg:
15460     # Call a function on a literal.
15461     #   f 0x34
15462     # =>
15463     #   (f2 0x34)
15464     #
15465     # . prologue
15466     55/push-ebp
15467     89/<- %ebp 4/r32/esp
15468     # setup
15469     (clear-stream _test-output-stream)
15470     (clear-stream $_test-output-buffered-file->buffer)
15471 $test-emit-subx-function-call-with-literal-arg:initialize-type:
15472     # var type/ecx: (payload tree type-id) = int
15473     68/push 0/imm32/right:null
15474     68/push 0/imm32/right:null
15475     68/push 0/imm32/left:unused
15476     68/push 0/imm32/value:literal
15477     68/push 1/imm32/is-atom?:true
15478     68/push 0x11/imm32/alloc-id:fake:payload
15479     89/<- %ecx 4/r32/esp
15480 $test-emit-subx-function-call-with-literal-arg:initialize-var:
15481     # var var-foo/ecx: (payload var) = var(lit)
15482     68/push 0/imm32/no-register
15483     68/push 0/imm32/no-register
15484     68/push 0/imm32/no-stack-offset
15485     68/push 1/imm32/block-depth
15486     51/push-ecx/type
15487     68/push 0x11/imm32/alloc-id:fake
15488     68/push 0/imm32/name
15489     68/push 0/imm32/name
15490     68/push 0x11/imm32/alloc-id:fake:payload
15491     89/<- %ecx 4/r32/esp
15492 $test-emit-subx-function-call-with-literal-arg:initialize-var-name:
15493     # var-foo->name = "0x34"
15494     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15495     (copy-array Heap "0x34" %eax)
15496 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-var:
15497     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
15498     68/push 0/imm32/is-deref:false
15499     68/push 0/imm32/next
15500     68/push 0/imm32/next
15501     51/push-ecx/var-foo
15502     68/push 0x11/imm32/alloc-id:fake
15503     68/push 0x11/imm32/alloc-id:fake:payload
15504     89/<- %ebx 4/r32/esp
15505 $test-emit-subx-function-call-with-literal-arg:initialize-stmt:
15506     # var stmt/esi: (addr statement)
15507     68/push 0/imm32/no-outputs
15508     68/push 0/imm32/no-outputs
15509     53/push-ebx/inouts
15510     68/push 0x11/imm32/alloc-id:fake
15511     68/push 0/imm32/operation
15512     68/push 0/imm32/operation
15513     68/push 1/imm32/tag
15514     89/<- %esi 4/r32/esp
15515 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-operation:
15516     # stmt->operation = "f"
15517     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15518     (copy-array Heap "f" %eax)
15519     # convert
15520     c7 0/subop/copy *Curr-block-depth 0/imm32
15521     (emit-subx-stmt _test-output-buffered-file %esi 0 %ebx)
15522     (flush _test-output-buffered-file)
15523 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
15529     # check output
15530     (check-next-stream-line-equal _test-output-stream "(f 0x34)" "F - test-emit-subx-stmt-function-call-with-literal-arg")
15531     # . epilogue
15532     89/<- %esp 5/r32/ebp
15533     5d/pop-to-ebp
15534     c3/return
15535 
15536 emit-indent:  # out: (addr buffered-file), n: int
15537     # . prologue
15538     55/push-ebp
15539     89/<- %ebp 4/r32/esp
15540     # . save registers
15541     50/push-eax
15542     # var i/eax: int = n
15543     8b/-> *(ebp+0xc) 0/r32/eax
15544     {
15545       # if (i <= 0) break
15546       3d/compare-eax-with 0/imm32
15547       7e/jump-if-<= break/disp8
15548       (write-buffered *(ebp+8) "  ")
15549       48/decrement-eax
15550       eb/jump loop/disp8
15551     }
15552 $emit-indent:end:
15553     # . restore registers
15554     58/pop-to-eax
15555     # . epilogue
15556     89/<- %esp 5/r32/ebp
15557     5d/pop-to-ebp
15558     c3/return
15559 
15560 emit-subx-prologue:  # out: (addr buffered-file)
15561     # . prologue
15562     55/push-ebp
15563     89/<- %ebp 4/r32/esp
15564     #
15565     (write-buffered *(ebp+8) "  # . prologue\n")
15566     (write-buffered *(ebp+8) "  55/push-ebp\n")
15567     (write-buffered *(ebp+8) "  89/<- %ebp 4/r32/esp\n")
15568 $emit-subx-prologue:end:
15569     # . epilogue
15570     89/<- %esp 5/r32/ebp
15571     5d/pop-to-ebp
15572     c3/return
15573 
15574 emit-subx-epilogue:  # out: (addr buffered-file)
15575     # . prologue
15576     55/push-ebp
15577     89/<- %ebp 4/r32/esp
15578     #
15579     (write-buffered *(ebp+8) "  # . epilogue\n")
15580     (write-buffered *(ebp+8) "  89/<- %esp 5/r32/ebp\n")
15581     (write-buffered *(ebp+8) "  5d/pop-to-ebp\n")
15582     (write-buffered *(ebp+8) "  c3/return\n")
15583 $emit-subx-epilogue:end:
15584     # . epilogue
15585     89/<- %esp 5/r32/ebp
15586     5d/pop-to-ebp
15587     c3/return