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 #   $ ./a.elf < prog.mu > prog.elf
    7 
    8 # == Goals
    9 # 1. Be memory safe. It should be impossible to corrupt the heap, or to create
   10 # a bad pointer. (Requires strong type safety.)
   11 # 2. Do as little as possible to achieve goal 1. The translator should be
   12 # implementable in machine code.
   13 #   - minimize impedance mismatch between source language and SubX target
   14 #     (e.g. programmer manages registers manually)
   15 #   - checks over syntax
   16 #     (e.g. programmer's register allocation is checked)
   17 #   - runtime checks to avoid complex static analysis
   18 #     (e.g. array indexing always checks bounds)
   19 
   20 # == Language description
   21 # A program is a sequence of function and type definitions.
   22 #
   23 # Function example:
   24 #   fn foo n: int -> result/eax: int {
   25 #     ...
   26 #   }
   27 #
   28 # Functions consist of a name, optional inputs, optional outputs and a block.
   29 #
   30 # Function inputs and outputs are variables. All variables have a type and
   31 # storage specifier. They can be placed either in memory (on the stack) or in
   32 # one of 6 named registers.
   33 #   eax ecx edx ebx esi edi
   34 # Variables in registers must be primitive 32-bit types.
   35 # Variables not explicitly placed in a register are on the stack.
   36 #
   37 # Function inputs are always passed in memory (on the stack), while outputs
   38 # are always returned in registers.
   39 #
   40 # Blocks mostly consist of statements.
   41 #
   42 # Statements mostly consist of a name, optional inputs and optional outputs.
   43 #
   44 # Statement inputs are variables or literals. Variables need to specify type
   45 # (and storage) the first time they're mentioned but not later.
   46 #
   47 # Statement outputs, like function outputs, must be variables in registers.
   48 #
   49 # Statement names must be either primitives or user-defined functions.
   50 #
   51 # Primitives can write to any register.
   52 # User-defined functions only write to hard-coded registers. Outputs of each
   53 # call must have the same registers as in the function definition.
   54 #
   55 # There are some other statement types:
   56 #   - blocks. Multiple statements surrounded by '{...}' and optionally
   57 #     prefixed with a label name and ':'
   58 #       - {
   59 #           ...
   60 #         }
   61 #       - foo: {
   62 #           ...
   63 #         }
   64 #
   65 #   - variable definitions on the stack. E.g.:
   66 #       - var foo: int
   67 #       - var bar: (array int 3)
   68 #     There's no initializer; variables are automatically initialized.
   69 #     The type of a local variable is either word-length (4 bytes) or starts with 'ref'.
   70 #
   71 #   - variables definitions in a register. E.g.:
   72 #       - var foo/eax: int <- add bar 1
   73 #     The initializer is mandatory and must be a valid instruction that writes
   74 #     a single output to the right register. In practice registers will
   75 #     usually be either initialized by primitives or copied from eax.
   76 #       - var eax: int <- foo bar quux
   77 #         var floo/ecx: int <- copy eax
   78 #
   79 # Still todo:
   80 #   global variables
   81 #   union types
   82 #
   83 # Formal types:
   84 #   A program is a linked list of functions
   85 #   A function contains:
   86 #     name: (handle array byte)
   87 #     inouts: linked list of vars  <-- 'inouts' is more precise than 'inputs'
   88 #       data: (handle var)
   89 #       next: (handle list)
   90 #     outputs: linked list of vars
   91 #       data: (handle var)
   92 #       next: (handle list)
   93 #     body: (handle block)
   94 #   A var-type contains:
   95 #     name: (handle array byte)
   96 #     type: (handle type-tree)
   97 #
   98 #   A statement can be:
   99 #     tag 0: a block
  100 #     tag 1: a simple statement (stmt1)
  101 #     tag 2: a variable defined on the stack
  102 #     tag 3: a variable defined in a register
  103 #
  104 #   A block contains:
  105 #     tag: 0
  106 #     statements: (handle list stmt)
  107 #     name: (handle array byte) -- starting with '$'
  108 #
  109 #   A regular statement contains:
  110 #     tag: 1
  111 #     operation: (handle array byte)
  112 #     inouts: (handle list operand)
  113 #     outputs: (handle list var)
  114 #
  115 #   A variable defined on the stack contains:
  116 #     tag: 2
  117 #     name: (handle array byte)
  118 #     type: (handle type-tree)
  119 #
  120 #   A variable defined in a register contains:
  121 #     tag: 3
  122 #     name: (handle array byte)
  123 #     type: (handle type-tree)
  124 #     reg: (handle array byte)
  125 
  126 # == Translation: managing the stack
  127 # Now that we know what the language looks like in the large, let's think
  128 # about how translation happens from the bottom up. One crucial piece of the
  129 # puzzle is how Mu will clean up variables defined on the stack for you.
  130 #
  131 # Assume that we maintain a 'functions' list while parsing source code. And a
  132 # 'primitives' list is a global constant. Both these contain enough information
  133 # to perform type-checking on function calls or primitive statements, respectively.
  134 #
  135 # Defining variables pushes them on a stack with the current block depth and
  136 # enough information about their location (stack offset or register).
  137 # Starting a block increments the current block id.
  138 # Each statement now has enough information to emit code for it.
  139 # Ending a block is where the magic happens:
  140 #   pop all variables at the current block depth
  141 #   emit code to restore all register variables introduced at the current depth
  142 #   emit code to clean up all stack variables at the current depth (just increment esp)
  143 #   decrement the current block depth
  144 #
  145 # Formal types:
  146 #   live-vars: stack of vars
  147 #   var:
  148 #     name: (handle array byte)
  149 #     type: (handle type-tree)
  150 #     block: int
  151 #     stack-offset: int  (added to ebp)
  152 #     register: (handle array byte)
  153 #       either usual register names
  154 #       or '*' to indicate any register
  155 #   At most one of stack-offset or register-index must be non-zero.
  156 #   A register of '*' designates a variable _template_. Only legal in formal
  157 #   parameters for primitives.
  158 
  159 # == Translating a single function call
  160 # This one's easy. Assuming we've already checked things, we just drop the
  161 # outputs (which use hard-coded registers) and emit inputs in a standard format.
  162 #
  163 # out1, out2, out3, ... <- name inout1, inout2, inout3, ...
  164 # =>
  165 # (name inout1 inout2 inout3)
  166 #
  167 # Formal types:
  168 #   functions: linked list of info
  169 #     name: (handle array byte)
  170 #     inouts: linked list of vars
  171 #     outputs: linked list of vars
  172 #     body: block (linked list of statements)
  173 
  174 # == Translating a single primitive instruction
  175 # A second crucial piece of the puzzle is how Mu converts fairly regular
  176 # primitives with their uniform syntax to SubX instructions with their gnarly
  177 # x86 details.
  178 #
  179 # Mu instructions have inputs and outputs. Primitives can have up to 2 of
  180 # them.
  181 # SubX instructions have rm32 and r32 operands.
  182 # The translation between them covers almost all the possibilities.
  183 #   Instructions with 1 inout may turn into ones with 1 rm32
  184 #     (e.g. incrementing a var on the stack)
  185 #   Instructions with 1 output may turn into ones with 1 rm32
  186 #     (e.g. incrementing a var in a register)
  187 #   1 inout and 1 output may turn into 1 rm32 and 1 r32
  188 #     (e.g. adding a var to a reg)
  189 #   2 inouts may turn into 1 rm32 and 1 r32
  190 #     (e.g. adding a reg to a var)
  191 #   1 inout and 1 literal may turn into 1 rm32 and 1 imm32
  192 #     (e.g. adding a constant to a var)
  193 #   1 output and 1 literal may turn into 1 rm32 and 1 imm32
  194 #     (e.g. adding a constant to a reg)
  195 #   2 outputs to hardcoded registers and 1 inout may turn into 1 rm32
  196 #     (special-case: divide edx:eax by a var or reg)
  197 # Observations:
  198 #   We always emit rm32. It may be the first inout or the first output.
  199 #   We may emit r32 or imm32 or neither.
  200 #   When we emit r32 it may come from first inout or second inout or first output.
  201 #
  202 # Accordingly, the formal data structure for a primitive looks like this:
  203 #   primitives: linked list of info
  204 #     name: (handle array byte)
  205 #     mu-inouts: linked list of vars to check
  206 #     mu-outputs: linked list of vars to check; at most a singleton
  207 #     subx-name: (handle array byte)
  208 #     subx-rm32: enum arg-location
  209 #     subx-r32: enum arg-location
  210 #     subx-imm32: enum arg-location
  211 #     subx-imm8: enum arg-location
  212 #     subx-disp32: enum arg-location
  213 #     output-is-write-only: boolean
  214 #   arg-location: enum
  215 #     0 means none
  216 #     1 means first inout
  217 #     2 means second inout
  218 #     3 means first output
  219 
  220 # == Translating a block
  221 # Emit block name if necessary
  222 # Emit '{'
  223 # When you encounter a statement, emit it as above
  224 # When you encounter a variable declaration
  225 #   emit any code needed for it (bzeros)
  226 #   push it on the var stack
  227 #   update register dict if necessary
  228 # When you encounter '}'
  229 #   While popping variables off the var stack until block id changes
  230 #     Emit code needed to clean up the stack
  231 #       either increment esp
  232 #       or pop into appropriate register
  233 
  234 # The rest is straightforward.
  235 
  236 == data
  237 
  238 Program:
  239 _Program-functions:  # (handle function)
  240   0/imm32
  241 _Program-functions->payload:
  242   0/imm32
  243 _Program-types:  # (handle typeinfo)
  244   0/imm32
  245 _Program-types->payload:
  246   0/imm32
  247 _Program-signatures:  # (handle function)
  248   0/imm32
  249 _Program-signatures->payload:
  250   0/imm32
  251 
  252 # Some constants for simulating the data structures described above.
  253 # Many constants here come with a type in a comment.
  254 #
  255 # Sometimes the type is of the value at that offset for the given type. For
  256 # example, if you start at a function record and move forward Function-inouts
  257 # bytes, you'll find a (handle list var).
  258 #
  259 # At other times, the type is of the constant itself. For example, the type of
  260 # the constant Function-size is (addr int). To get the size of a function,
  261 # look in *Function-size.
  262 
  263 Function-name:  # (handle array byte)
  264   0/imm32
  265 Function-inouts:  # (handle list var)
  266   8/imm32
  267 Function-outputs:  # (handle list var)
  268   0x10/imm32
  269 Function-body:  # (handle block)
  270   0x18/imm32
  271 Function-next:  # (handle function)
  272   0x20/imm32
  273 Function-size:  # (addr int)
  274   0x28/imm32/40
  275 
  276 Primitive-name:  # (handle array byte)
  277   0/imm32
  278 Primitive-inouts:  # (handle list var)
  279   8/imm32
  280 Primitive-outputs:  # (handle list var)
  281   0x10/imm32
  282 Primitive-subx-name:  # (handle array byte)
  283   0x18/imm32
  284 Primitive-subx-rm32:  # enum arg-location
  285   0x20/imm32
  286 Primitive-subx-r32:  # enum arg-location
  287   0x24/imm32
  288 Primitive-subx-imm32:  # enum arg-location
  289   0x28/imm32
  290 Primitive-subx-imm8:  # enum arg-location  -- only for bit shifts
  291   0x2c/imm32
  292 Primitive-subx-disp32:  # enum arg-location  -- only for branches
  293   0x30/imm32
  294 Primitive-output-is-write-only:  # boolean
  295   0x34/imm32
  296 Primitive-next:  # (handle function)
  297   0x38/imm32
  298 Primitive-size:  # (addr int)
  299   0x40/imm32/60
  300 
  301 Stmt-tag:  # int
  302   0/imm32
  303 
  304 Block-stmts:  # (handle list stmt)
  305   4/imm32
  306 Block-var:  # (handle var)
  307   0xc/imm32
  308 
  309 Stmt1-operation:  # (handle array byte)
  310   4/imm32
  311 Stmt1-inouts:  # (handle stmt-var)
  312   0xc/imm32
  313 Stmt1-outputs:  # (handle stmt-var)
  314   0x14/imm32
  315 
  316 Vardef-var:  # (handle var)
  317   4/imm32
  318 
  319 Regvardef-operation:  # (handle array byte)
  320   4/imm32
  321 Regvardef-inouts:  # (handle stmt-var)
  322   0xc/imm32
  323 Regvardef-outputs:  # (handle stmt-var)  # will have exactly one element
  324   0x14/imm32
  325 
  326 Stmt-size:  # (addr int)
  327   0x1c/imm32
  328 
  329 Var-name:  # (handle array byte)
  330   0/imm32
  331 Var-type:  # (handle type-tree)
  332   8/imm32
  333 Var-block-depth:  # int -- not available until code-generation time
  334   0x10/imm32
  335 Var-offset:  # int -- not available until code-generation time
  336   0x14/imm32
  337 Var-register:  # (handle array byte) -- name of a register
  338   0x18/imm32
  339 Var-size:  # (addr int)
  340   0x20/imm32
  341 
  342 List-value:  # (handle _)
  343   0/imm32
  344 List-next:  # (handle list _)
  345   8/imm32
  346 List-size:  # (addr int)
  347   0x10/imm32
  348 
  349 # A stmt-var is like a list of vars with call-site specific metadata
  350 Stmt-var-value:  # (handle var)
  351   0/imm32
  352 Stmt-var-next:  # (handle stmt-var)
  353   8/imm32
  354 Stmt-var-is-deref:  # boolean
  355   0x10/imm32
  356 Stmt-var-size:  # (addr int)
  357   0x14/imm32
  358 
  359 # A live-var is a var augmented with information needed for tracking live
  360 # variables.
  361 Live-var-value:  # (handle var)
  362   0/imm32
  363 Live-var-register-spilled:  # boolean; only used if value is in a register, and only during code-gen
  364   8/imm32
  365 Live-var-size:  # (addr int)
  366   0xc/imm32
  367 
  368 # Types are expressed as trees (s-expressions) of type-ids (ints).
  369 
  370 Type-tree-is-atom:  # boolean
  371   0/imm32
  372 # if is-atom?
  373 Type-tree-value:  # type-id
  374   4/imm32
  375 Type-tree-value-size:  # int (for static data structure sizes)
  376   8/imm32
  377 Type-tree-parameter-name:  # (handle array byte) for type parameters
  378   8/imm32
  379 # unless is-atom?
  380 Type-tree-left:  # (addr type-tree)
  381   4/imm32
  382 Type-tree-right:  # (addr type-tree)
  383   0xc/imm32
  384 #
  385 Type-tree-size:  # (addr int)
  386   0x14/imm32
  387 
  388 # Types
  389 
  390 # TODO: Turn this data structure into valid Mu, with (fake) handles rather than addrs.
  391 Type-id:  # (stream (addr array byte))
  392   0/imm32/write  # initialized later from Primitive-type-ids
  393   0/imm32/read
  394   0x100/imm32/size
  395   # data
  396   "literal"/imm32  # 0: value is just the name
  397   "int"/imm32  # 1
  398   "addr"/imm32  # 2
  399   "array"/imm32  # 3
  400   "handle"/imm32  # 4
  401   "boolean"/imm32  # 5
  402   "constant"/imm32  # 6: like a literal, but value is an int in Var-offset
  403   "offset"/imm32  # 7: (offset T) is guaranteed to be a 32-bit multiple of size-of(T)
  404   # 0x20
  405   "byte"/imm32  # 8
  406   0/imm32  # 9 reserved for array-capacity; value is in Type-tree-size.
  407            # Not to be used directly, so we don't include a name here.
  408   0/imm32  # 10 reserved for type parameters; value is (address array byte) in Type-tree-value2.
  409            # Not to be used directly, so we don't include a name here.
  410   # some SubX types deliberately left undefined in Mu; they can only be operated on using SubX primitives
  411   "stream"/imm32  # 11
  412   "slice"/imm32  # 12
  413   # Keep Primitive-type-ids in sync if you add types here.
  414                                           0/imm32 0/imm32 0/imm32
  415   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  416   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  417   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  418   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  419   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  420   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  421 
  422 Primitive-type-ids:  # (addr int)
  423   0x34
  424 
  425 # == Type definitions
  426 # Program->types contains some typeinfo for each type definition.
  427 # Types contain vars with types, but can't specify registers.
  428 Typeinfo-id:  # type-id
  429   0/imm32
  430 Typeinfo-fields:  # (handle table (handle array byte) (handle typeinfo-entry))
  431   4/imm32
  432 # Total size must be >= 0
  433 # During parsing it may take on two additional values:
  434 #   -2: not yet initialized
  435 #   -1: in process of being computed
  436 # See populate-mu-type-sizes for details.
  437 Typeinfo-total-size-in-bytes:  # int
  438   0xc/imm32
  439 Typeinfo-next:  # (handle typeinfo)
  440   0x10/imm32
  441 Typeinfo-size:  # (addr int)
  442   0x18/imm32
  443 
  444 # Each entry in the typeinfo->fields table has a pointer to a string and a
  445 # pointer to a typeinfo-entry.
  446 Typeinfo-fields-row-size:  # (addr int)
  447   0x10/imm32
  448 
  449 # typeinfo-entry objects have information about a field in a single record type
  450 #
  451 # each field of a type is represented using two var's:
  452 #   1. the input var: expected type of the field; convenient for creating using parse-var-with-type
  453 #   2. the output var: a constant containing the byte offset; convenient for code-generation
  454 # computing the output happens after parsing; in the meantime we preserve the
  455 # order of fields in the 'index' field.
  456 Typeinfo-entry-input-var:  # (handle var)
  457   0/imm32
  458 Typeinfo-entry-index:  # int
  459   8/imm32
  460 Typeinfo-entry-output-var:  # (handle var)
  461   0xc/imm32
  462 Typeinfo-entry-size:  # (addr int)
  463   0x14/imm32
  464 
  465 == code
  466 
  467 Entry:
  468     # . prologue
  469     89/<- %ebp 4/r32/esp
  470     (new-segment *Heap-size Heap)
  471     # if (argv[1] == "test') run-tests()
  472     {
  473       # if (argc <= 1) break
  474       81 7/subop/compare *ebp 1/imm32
  475       7e/jump-if-<= break/disp8
  476       # if (argv[1] != "test") break
  477       (kernel-string-equal? *(ebp+8) "test")  # => eax
  478       3d/compare-eax-and 0/imm32/false
  479       74/jump-if-= break/disp8
  480       #
  481       (run-tests)
  482       # syscall(exit, *Num-test-failures)
  483       8b/-> *Num-test-failures 3/r32/ebx
  484       eb/jump $mu-main:end/disp8
  485     }
  486     # otherwise convert Stdin
  487     (convert-mu Stdin Stdout Stderr 0)
  488     (flush Stdout)
  489     # syscall(exit, 0)
  490     bb/copy-to-ebx 0/imm32
  491 $mu-main:end:
  492     e8/call syscall_exit/disp32
  493 
  494 convert-mu:  # in: (addr buffered-file), out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
  495     # . prologue
  496     55/push-ebp
  497     89/<- %ebp 4/r32/esp
  498     # . save registers
  499     50/push-eax
  500     # initialize global data structures
  501     c7 0/subop/copy *Next-block-index 1/imm32
  502     8b/-> *Primitive-type-ids 0/r32/eax
  503     89/<- *Type-id 0/r32/eax  # stream-write
  504     c7 0/subop/copy *_Program-functions 0/imm32
  505     c7 0/subop/copy *_Program-functions->payload 0/imm32
  506     c7 0/subop/copy *_Program-types 0/imm32
  507     c7 0/subop/copy *_Program-types->payload 0/imm32
  508     c7 0/subop/copy *_Program-signatures 0/imm32
  509     c7 0/subop/copy *_Program-signatures->payload 0/imm32
  510     #
  511     (parse-mu *(ebp+8) *(ebp+0x10) *(ebp+0x14))
  512     (populate-mu-type-sizes *(ebp+0x10) *(ebp+0x14))
  513 #?     (dump-typeinfos "=== typeinfos\n")
  514     (check-mu-types *(ebp+0x10) *(ebp+0x14))
  515     (emit-subx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
  516 $convert-mu:end:
  517     # . restore registers
  518     58/pop-to-eax
  519     # . epilogue
  520     89/<- %esp 5/r32/ebp
  521     5d/pop-to-ebp
  522     c3/return
  523 
  524 test-convert-empty-input:
  525     # empty input => empty output
  526     # . prologue
  527     55/push-ebp
  528     89/<- %ebp 4/r32/esp
  529     # setup
  530     (clear-stream _test-input-stream)
  531     (clear-stream $_test-input-buffered-file->buffer)
  532     (clear-stream _test-output-stream)
  533     (clear-stream $_test-output-buffered-file->buffer)
  534     #
  535     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  536     (flush _test-output-buffered-file)
  537     (check-stream-equal _test-output-stream "" "F - test-convert-empty-input")
  538     # . epilogue
  539     89/<- %esp 5/r32/ebp
  540     5d/pop-to-ebp
  541     c3/return
  542 
  543 test-convert-function-skeleton:
  544     # . prologue
  545     55/push-ebp
  546     89/<- %ebp 4/r32/esp
  547     # setup
  548     (clear-stream _test-input-stream)
  549     (clear-stream $_test-input-buffered-file->buffer)
  550     (clear-stream _test-output-stream)
  551     (clear-stream $_test-output-buffered-file->buffer)
  552     #
  553     (write _test-input-stream "fn foo {\n")
  554     (write _test-input-stream "}\n")
  555     # convert
  556     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  557     (flush _test-output-buffered-file)
  558 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  564     # check output
  565     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-skeleton/0")
  566     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-skeleton/1")
  567     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-skeleton/2")
  568     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-skeleton/3")
  569     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-skeleton/4")
  570     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-skeleton/5")
  571     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-skeleton/6")
  572     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-skeleton/7")
  573     # . epilogue
  574     89/<- %esp 5/r32/ebp
  575     5d/pop-to-ebp
  576     c3/return
  577 
  578 test-convert-multiple-function-skeletons:
  579     # . prologue
  580     55/push-ebp
  581     89/<- %ebp 4/r32/esp
  582     # setup
  583     (clear-stream _test-input-stream)
  584     (clear-stream $_test-input-buffered-file->buffer)
  585     (clear-stream _test-output-stream)
  586     (clear-stream $_test-output-buffered-file->buffer)
  587     #
  588     (write _test-input-stream "fn foo {\n")
  589     (write _test-input-stream "}\n")
  590     (write _test-input-stream "fn bar {\n")
  591     (write _test-input-stream "}\n")
  592     # convert
  593     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  594     (flush _test-output-buffered-file)
  595 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  601     # check first function
  602     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-multiple-function-skeletons/0")
  603     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/1")
  604     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/2")
  605     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/3")
  606     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/4")
  607     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/5")
  608     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/6")
  609     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/7")
  610     # check second function
  611     (check-next-stream-line-equal _test-output-stream "bar:"                    "F - test-convert-multiple-function-skeletons/10")
  612     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/11")
  613     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/12")
  614     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/13")
  615     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/14")
  616     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/15")
  617     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/16")
  618     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/17")
  619     # . epilogue
  620     89/<- %esp 5/r32/ebp
  621     5d/pop-to-ebp
  622     c3/return
  623 
  624 test-convert-function-with-arg:
  625     # . prologue
  626     55/push-ebp
  627     89/<- %ebp 4/r32/esp
  628     # setup
  629     (clear-stream _test-input-stream)
  630     (clear-stream $_test-input-buffered-file->buffer)
  631     (clear-stream _test-output-stream)
  632     (clear-stream $_test-output-buffered-file->buffer)
  633     #
  634     (write _test-input-stream "fn foo n: int {\n")
  635     (write _test-input-stream "}\n")
  636     # convert
  637     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  638     (flush _test-output-buffered-file)
  639 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  645     # check output
  646     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg/0")
  647     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg/1")
  648     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg/2")
  649     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg/3")
  650     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg/4")
  651     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg/5")
  652     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg/6")
  653     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg/7")
  654     # . epilogue
  655     89/<- %esp 5/r32/ebp
  656     5d/pop-to-ebp
  657     c3/return
  658 
  659 test-convert-function-with-arg-and-body:
  660     # . prologue
  661     55/push-ebp
  662     89/<- %ebp 4/r32/esp
  663     # setup
  664     (clear-stream _test-input-stream)
  665     (clear-stream $_test-input-buffered-file->buffer)
  666     (clear-stream _test-output-stream)
  667     (clear-stream $_test-output-buffered-file->buffer)
  668     #
  669     (write _test-input-stream "fn foo n: int {\n")
  670     (write _test-input-stream "  increment n\n")
  671     (write _test-input-stream "}\n")
  672     # convert
  673     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  674     (flush _test-output-buffered-file)
  675 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  681     # check output
  682     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg-and-body/0")
  683     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg-and-body/1")
  684     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg-and-body/2")
  685     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg-and-body/3")
  686     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-arg-and-body/4")
  687     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-arg-and-body/5")
  688     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-arg-and-body/6")
  689     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-arg-and-body/7")
  690     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-arg-and-body/8")
  691     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg-and-body/9")
  692     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg-and-body/10")
  693     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg-and-body/11")
  694     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg-and-body/12")
  695     # . epilogue
  696     89/<- %esp 5/r32/ebp
  697     5d/pop-to-ebp
  698     c3/return
  699 
  700 test-convert-function-distinguishes-args:
  701     # . prologue
  702     55/push-ebp
  703     89/<- %ebp 4/r32/esp
  704     # setup
  705     (clear-stream _test-input-stream)
  706     (clear-stream $_test-input-buffered-file->buffer)
  707     (clear-stream _test-output-stream)
  708     (clear-stream $_test-output-buffered-file->buffer)
  709     #
  710     (write _test-input-stream "fn foo a: int, b: int {\n")
  711     (write _test-input-stream "  increment b\n")
  712     (write _test-input-stream "}\n")
  713     # convert
  714     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  715     (flush _test-output-buffered-file)
  716 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  722     # check output
  723     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-distinguishes-args/0")
  724     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-distinguishes-args/1")
  725     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-distinguishes-args/2")
  726     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-distinguishes-args/3")
  727     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-distinguishes-args/4")
  728     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-distinguishes-args/5")
  729     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x0000000c)"  "F - test-convert-function-distinguishes-args/6")
  730     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-distinguishes-args/7")
  731     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-distinguishes-args/8")
  732     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-distinguishes-args/9")
  733     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-distinguishes-args/10")
  734     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-distinguishes-args/11")
  735     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-distinguishes-args/12")
  736     # . epilogue
  737     89/<- %esp 5/r32/ebp
  738     5d/pop-to-ebp
  739     c3/return
  740 
  741 test-convert-function-returns-result:
  742     # . prologue
  743     55/push-ebp
  744     89/<- %ebp 4/r32/esp
  745     # setup
  746     (clear-stream _test-input-stream)
  747     (clear-stream $_test-input-buffered-file->buffer)
  748     (clear-stream _test-output-stream)
  749     (clear-stream $_test-output-buffered-file->buffer)
  750     #
  751     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  752     (write _test-input-stream "  result <- copy a\n")
  753     (write _test-input-stream "  result <- increment\n")
  754     (write _test-input-stream "}\n")
  755     # convert
  756     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  757     (flush _test-output-buffered-file)
  758 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  764     # check output
  765     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-returns-result/0")
  766     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-returns-result/1")
  767     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-returns-result/2")
  768     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-returns-result/3")
  769     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-returns-result/4")
  770     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-returns-result/5")
  771     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-returns-result/6")
  772     (check-next-stream-line-equal _test-output-stream "    40/increment-eax"    "F - test-convert-function-returns-result/7")
  773     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-returns-result/8")
  774     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-returns-result/9")
  775     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-returns-result/10")
  776     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-returns-result/11")
  777     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-returns-result/12")
  778     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-returns-result/13")
  779     # . epilogue
  780     89/<- %esp 5/r32/ebp
  781     5d/pop-to-ebp
  782     c3/return
  783 
  784 test-convert-function-with-literal-arg:
  785     # . prologue
  786     55/push-ebp
  787     89/<- %ebp 4/r32/esp
  788     # setup
  789     (clear-stream _test-input-stream)
  790     (clear-stream $_test-input-buffered-file->buffer)
  791     (clear-stream _test-output-stream)
  792     (clear-stream $_test-output-buffered-file->buffer)
  793     #
  794     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  795     (write _test-input-stream "  result <- copy a\n")
  796     (write _test-input-stream "  result <- add 1\n")
  797     (write _test-input-stream "}\n")
  798     # convert
  799     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  800     (flush _test-output-buffered-file)
  801 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  807     # check output
  808     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg/0")
  809     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg/1")
  810     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg/2")
  811     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg/3")
  812     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg/4")
  813     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg/5")
  814     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-with-literal-arg/6")
  815     (check-next-stream-line-equal _test-output-stream "    05/add-to-eax 1/imm32"  "F - test-convert-function-with-literal-arg/7")
  816     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg/8")
  817     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg/9")
  818     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg/10")
  819     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg/11")
  820     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg/12")
  821     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg/13")
  822     # . epilogue
  823     89/<- %esp 5/r32/ebp
  824     5d/pop-to-ebp
  825     c3/return
  826 
  827 test-convert-function-with-literal-arg-2:
  828     # . prologue
  829     55/push-ebp
  830     89/<- %ebp 4/r32/esp
  831     # setup
  832     (clear-stream _test-input-stream)
  833     (clear-stream $_test-input-buffered-file->buffer)
  834     (clear-stream _test-output-stream)
  835     (clear-stream $_test-output-buffered-file->buffer)
  836     #
  837     (write _test-input-stream "fn foo a: int, b: int -> result/ebx: int {\n")
  838     (write _test-input-stream "  result <- copy a\n")
  839     (write _test-input-stream "  result <- add 1\n")
  840     (write _test-input-stream "}\n")
  841     # convert
  842     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  843     (flush _test-output-buffered-file)
  844 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  850     # check output
  851     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg-2/0")
  852     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg-2/1")
  853     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg-2/2")
  854     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg-2/3")
  855     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg-2/4")
  856     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg-2/5")
  857     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-with-literal-arg-2/6")
  858     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %ebx 1/imm32"  "F - test-convert-function-with-literal-arg-2/7")
  859     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg-2/8")
  860     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg-2/9")
  861     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg-2/10")
  862     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg-2/11")
  863     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg-2/12")
  864     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg-2/13")
  865     # . epilogue
  866     89/<- %esp 5/r32/ebp
  867     5d/pop-to-ebp
  868     c3/return
  869 
  870 test-convert-function-call-with-literal-arg:
  871     # . prologue
  872     55/push-ebp
  873     89/<- %ebp 4/r32/esp
  874     # setup
  875     (clear-stream _test-input-stream)
  876     (clear-stream $_test-input-buffered-file->buffer)
  877     (clear-stream _test-output-stream)
  878     (clear-stream $_test-output-buffered-file->buffer)
  879     #
  880     (write _test-input-stream "fn main -> result/ebx: int {\n")
  881     (write _test-input-stream "  result <- do-add 3 4\n")
  882     (write _test-input-stream "}\n")
  883     (write _test-input-stream "fn do-add a: int, b: int -> result/ebx: int {\n")
  884     (write _test-input-stream "  result <- copy a\n")
  885     (write _test-input-stream "  result <- add b\n")
  886     (write _test-input-stream "}\n")
  887     # convert
  888     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  889     (flush _test-output-buffered-file)
  890 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  896     # check output
  897     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-literal-arg/0")
  898     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/1")
  899     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/2")
  900     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/3")
  901     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/4")
  902     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-literal-arg/5")
  903     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-literal-arg/6")
  904     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/7")
  905     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-literal-arg/8")
  906     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/9")
  907     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/10")
  908     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/11")
  909     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/12")
  910     (check-next-stream-line-equal _test-output-stream "do-add:"                 "F - test-convert-function-call-with-literal-arg/13")
  911     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/14")
  912     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/15")
  913     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/16")
  914     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/17")
  915     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:loop:"  "F - test-convert-function-call-with-literal-arg/18")
  916     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/19")
  917     (check-next-stream-line-equal _test-output-stream "    03/add *(ebp+0x0000000c) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/20")
  918     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/21")
  919     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:break:"  "F - test-convert-function-call-with-literal-arg/22")
  920     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/23")
  921     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/24")
  922     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/25")
  923     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/26")
  924     # . epilogue
  925     89/<- %esp 5/r32/ebp
  926     5d/pop-to-ebp
  927     c3/return
  928 
  929 test-convert-function-call-with-signature:
  930     # . prologue
  931     55/push-ebp
  932     89/<- %ebp 4/r32/esp
  933     # setup
  934     (clear-stream _test-input-stream)
  935     (clear-stream $_test-input-buffered-file->buffer)
  936     (clear-stream _test-output-stream)
  937     (clear-stream $_test-output-buffered-file->buffer)
  938     #
  939     (write _test-input-stream "fn main -> result/ebx: int {\n")
  940     (write _test-input-stream "  result <- do-add 3 4\n")
  941     (write _test-input-stream "}\n")
  942     (write _test-input-stream "sig do-add a: int, b: int -> result/ebx: int\n")
  943     # convert
  944     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  945     (flush _test-output-buffered-file)
  946 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  952     # check output
  953     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-signature/0")
  954     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-signature/1")
  955     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-signature/2")
  956     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-signature/3")
  957     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-signature/4")
  958     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-signature/5")
  959     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-signature/6")
  960     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-signature/7")
  961     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-signature/8")
  962     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-signature/9")
  963     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-signature/10")
  964     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-signature/11")
  965     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-signature/12")
  966     # . epilogue
  967     89/<- %esp 5/r32/ebp
  968     5d/pop-to-ebp
  969     c3/return
  970 
  971 test-convert-function-with-local-var-in-mem:
  972     # . prologue
  973     55/push-ebp
  974     89/<- %ebp 4/r32/esp
  975     # setup
  976     (clear-stream _test-input-stream)
  977     (clear-stream $_test-input-buffered-file->buffer)
  978     (clear-stream _test-output-stream)
  979     (clear-stream $_test-output-buffered-file->buffer)
  980     #
  981     (write _test-input-stream "fn foo {\n")
  982     (write _test-input-stream "  var x: int\n")
  983     (write _test-input-stream "  increment x\n")
  984     (write _test-input-stream "}\n")
  985     # convert
  986     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  987     (flush _test-output-buffered-file)
  988 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  994     # check output
  995     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-mem/0")
  996     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-mem/1")
  997     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-mem/2")
  998     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-mem/3")
  999     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-mem/4")
 1000     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-mem/5")
 1001     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-in-mem/6")
 1002     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-mem/7")
 1003     (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")
 1004     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-mem/9")
 1005     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-mem/10")
 1006     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-mem/11")
 1007     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-mem/12")
 1008     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-mem/13")
 1009     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-mem/14")
 1010     # . epilogue
 1011     89/<- %esp 5/r32/ebp
 1012     5d/pop-to-ebp
 1013     c3/return
 1014 
 1015 test-convert-invalid-literal:
 1016     # . prologue
 1017     55/push-ebp
 1018     89/<- %ebp 4/r32/esp
 1019     # setup
 1020     (clear-stream _test-input-stream)
 1021     (clear-stream $_test-input-buffered-file->buffer)
 1022     (clear-stream _test-output-stream)
 1023     (clear-stream $_test-output-buffered-file->buffer)
 1024     (clear-stream _test-error-stream)
 1025     (clear-stream $_test-error-buffered-file->buffer)
 1026     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1027     68/push 0/imm32
 1028     68/push 0/imm32
 1029     89/<- %edx 4/r32/esp
 1030     (tailor-exit-descriptor %edx 0x10)
 1031     #
 1032     (write _test-input-stream "fn foo {\n")
 1033     (write _test-input-stream "  increment 1n\n")
 1034     (write _test-input-stream "}\n")
 1035     # convert
 1036     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1037     # registers except esp clobbered at this point
 1038     # restore ed
 1039     89/<- %edx 4/r32/esp
 1040     (flush _test-output-buffered-file)
 1041     (flush _test-error-buffered-file)
 1042 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1048     # check output
 1049     (check-stream-equal _test-output-stream  ""  "F - test-convert-invalid-literal: output should be empty")
 1050     (check-next-stream-line-equal _test-error-stream  "fn foo: variable '1n' cannot begin with a digit (or do you have a typo in a number?)"  "F - test-convert-invalid-literal: error message")
 1051     # check that stop(1) was called
 1052     (check-ints-equal *(edx+4) 2 "F - test-convert-invalid-literal: exit status")
 1053     # don't restore from ebp
 1054     81 0/subop/add %esp 8/imm32
 1055     # . epilogue
 1056     5d/pop-to-ebp
 1057     c3/return
 1058 
 1059 test-local-var-in-mem-has-no-initializer:
 1060     # . prologue
 1061     55/push-ebp
 1062     89/<- %ebp 4/r32/esp
 1063     # setup
 1064     (clear-stream _test-input-stream)
 1065     (clear-stream $_test-input-buffered-file->buffer)
 1066     (clear-stream _test-output-stream)
 1067     (clear-stream $_test-output-buffered-file->buffer)
 1068     (clear-stream _test-error-stream)
 1069     (clear-stream $_test-error-buffered-file->buffer)
 1070     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1071     68/push 0/imm32
 1072     68/push 0/imm32
 1073     89/<- %edx 4/r32/esp
 1074     (tailor-exit-descriptor %edx 0x10)
 1075     #
 1076     (write _test-input-stream "fn foo {\n")
 1077     (write _test-input-stream "  var x: int <- copy 0\n")
 1078     (write _test-input-stream "  increment x\n")
 1079     (write _test-input-stream "}\n")
 1080     # convert
 1081     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1082     # registers except esp clobbered at this point
 1083     # restore ed
 1084     89/<- %edx 4/r32/esp
 1085     (flush _test-output-buffered-file)
 1086     (flush _test-error-buffered-file)
 1087 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1093     # check output
 1094     (check-stream-equal _test-output-stream  ""  "F - test-var-in-mem-has-no-initializer: output should be empty")
 1095     (check-next-stream-line-equal _test-error-stream  "fn foo: var x: variables on the stack can't take an initializer"  "F - test-var-in-mem-has-no-initializer: error message")
 1096     # check that stop(1) was called
 1097     (check-ints-equal *(edx+4) 2 "F - test-var-in-mem-has-no-initializer: exit status")
 1098     # don't restore from ebp
 1099     81 0/subop/add %esp 8/imm32
 1100     # . epilogue
 1101     5d/pop-to-ebp
 1102     c3/return
 1103 
 1104 test-convert-function-with-local-var-with-compound-type-in-mem:
 1105     # . prologue
 1106     55/push-ebp
 1107     89/<- %ebp 4/r32/esp
 1108     # setup
 1109     (clear-stream _test-input-stream)
 1110     (clear-stream $_test-input-buffered-file->buffer)
 1111     (clear-stream _test-output-stream)
 1112     (clear-stream $_test-output-buffered-file->buffer)
 1113     #
 1114     (write _test-input-stream "fn foo {\n")
 1115     (write _test-input-stream "  var x: (addr int)\n")
 1116     (write _test-input-stream "  copy-to x, 0\n")
 1117     (write _test-input-stream "}\n")
 1118     # convert
 1119     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1120     (flush _test-output-buffered-file)
 1121 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1127     # check output
 1128     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-compound-type-in-mem/0")
 1129     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/1")
 1130     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-compound-type-in-mem/2")
 1131     (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")
 1132     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/4")
 1133     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-compound-type-in-mem/5")
 1134     (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")
 1135     (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")
 1136     (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")
 1137     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/9")
 1138     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/10")
 1139     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/11")
 1140     (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")
 1141     (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")
 1142     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-compound-type-in-mem/14")
 1143     # . epilogue
 1144     89/<- %esp 5/r32/ebp
 1145     5d/pop-to-ebp
 1146     c3/return
 1147 
 1148 test-convert-function-with-local-var-in-reg:
 1149     # . prologue
 1150     55/push-ebp
 1151     89/<- %ebp 4/r32/esp
 1152     # setup
 1153     (clear-stream _test-input-stream)
 1154     (clear-stream $_test-input-buffered-file->buffer)
 1155     (clear-stream _test-output-stream)
 1156     (clear-stream $_test-output-buffered-file->buffer)
 1157     #
 1158     (write _test-input-stream "fn foo {\n")
 1159     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1160     (write _test-input-stream "  x <- increment\n")
 1161     (write _test-input-stream "}\n")
 1162     # convert
 1163     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1164     (flush _test-output-buffered-file)
 1165 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1171     # check output
 1172     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-reg/0")
 1173     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-reg/1")
 1174     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-reg/2")
 1175     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-reg/3")
 1176     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-reg/4")
 1177     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-reg/5")
 1178     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-in-reg/6")
 1179     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-local-var-in-reg/7")
 1180     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-local-var-in-reg/8")
 1181     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-reg/9")
 1182     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-reg/10")
 1183     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-reg/11")
 1184     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-reg/12")
 1185     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-reg/13")
 1186     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-reg/14")
 1187     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-reg/15")
 1188     # . epilogue
 1189     89/<- %esp 5/r32/ebp
 1190     5d/pop-to-ebp
 1191     c3/return
 1192 
 1193 test-convert-function-with-allocate:
 1194     # . prologue
 1195     55/push-ebp
 1196     89/<- %ebp 4/r32/esp
 1197     # setup
 1198     (clear-stream _test-input-stream)
 1199     (clear-stream $_test-input-buffered-file->buffer)
 1200     (clear-stream _test-output-stream)
 1201     (clear-stream $_test-output-buffered-file->buffer)
 1202     #
 1203     (write _test-input-stream "fn foo {\n")
 1204     (write _test-input-stream "  var x/ecx: (addr handle int) <- copy 0\n")
 1205     (write _test-input-stream "  allocate x\n")
 1206     (write _test-input-stream "}\n")
 1207     # convert
 1208     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1209     (flush _test-output-buffered-file)
 1210 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1216     # check output
 1217     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-allocate/0")
 1218     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-allocate/1")
 1219     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-allocate/2")
 1220     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-allocate/3")
 1221     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-allocate/4")
 1222     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-allocate/5")
 1223     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-allocate/6")
 1224     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-allocate/7")
 1225     (check-next-stream-line-equal _test-output-stream "    (allocate Heap 0x00000004 %ecx)"  "F - test-convert-function-with-allocate/8")  # 4 = size-of(int)
 1226     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-allocate/9")
 1227     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-allocate/10")
 1228     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-allocate/11")
 1229     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-allocate/12")
 1230     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-allocate/13")
 1231     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-allocate/14")
 1232     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-allocate/15")
 1233     # . epilogue
 1234     89/<- %esp 5/r32/ebp
 1235     5d/pop-to-ebp
 1236     c3/return
 1237 
 1238 test-initializer-in-hex:
 1239     # . prologue
 1240     55/push-ebp
 1241     89/<- %ebp 4/r32/esp
 1242     # setup
 1243     (clear-stream _test-input-stream)
 1244     (clear-stream $_test-input-buffered-file->buffer)
 1245     (clear-stream _test-output-stream)
 1246     (clear-stream $_test-output-buffered-file->buffer)
 1247     (clear-stream _test-error-stream)
 1248     (clear-stream $_test-error-buffered-file->buffer)
 1249     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1250     68/push 0/imm32
 1251     68/push 0/imm32
 1252     89/<- %edx 4/r32/esp
 1253     (tailor-exit-descriptor %edx 0x10)
 1254     #
 1255     (write _test-input-stream "fn foo {\n")
 1256     (write _test-input-stream "  var x/ecx: int <- copy 10\n")
 1257     (write _test-input-stream "}\n")
 1258     # convert
 1259     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1260     # registers except esp clobbered at this point
 1261     # restore ed
 1262     89/<- %edx 4/r32/esp
 1263     (flush _test-output-buffered-file)
 1264     (flush _test-error-buffered-file)
 1265 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1271     # check output
 1272     (check-stream-equal _test-output-stream  ""  "F - test-initializer-in-hex: output should be empty")
 1273     (check-next-stream-line-equal _test-error-stream  "literal integers are always hex in Mu; either start '10' with a '0x' to be unambiguous, or convert it to decimal."  "F - test-initializer-in-hex: error message")
 1274     # check that stop(1) was called
 1275     (check-ints-equal *(edx+4) 2 "F - test-initializer-in-hex: exit status")
 1276     # don't restore from ebp
 1277     81 0/subop/add %esp 8/imm32
 1278     # . epilogue
 1279     5d/pop-to-ebp
 1280     c3/return
 1281 
 1282 test-convert-function-with-second-local-var-in-same-reg:
 1283     # . prologue
 1284     55/push-ebp
 1285     89/<- %ebp 4/r32/esp
 1286     # setup
 1287     (clear-stream _test-input-stream)
 1288     (clear-stream $_test-input-buffered-file->buffer)
 1289     (clear-stream _test-output-stream)
 1290     (clear-stream $_test-output-buffered-file->buffer)
 1291     #
 1292     (write _test-input-stream "fn foo {\n")
 1293     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1294     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1295     (write _test-input-stream "  y <- increment\n")
 1296     (write _test-input-stream "}\n")
 1297     # convert
 1298     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1299     (flush _test-output-buffered-file)
 1300 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1306     # check output
 1307     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-second-local-var-in-same-reg/0")
 1308     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-second-local-var-in-same-reg/1")
 1309     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-second-local-var-in-same-reg/2")
 1310     (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")
 1311     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-second-local-var-in-same-reg/4")
 1312     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-second-local-var-in-same-reg/5")
 1313     (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")
 1314     (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")
 1315     (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")
 1316     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-second-local-var-in-same-reg/9")
 1317     (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")
 1318     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-second-local-var-in-same-reg/11")
 1319     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-second-local-var-in-same-reg/12")
 1320     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-second-local-var-in-same-reg/13")
 1321     (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")
 1322     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-second-local-var-in-same-reg/15")
 1323     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-second-local-var-in-same-reg/16")
 1324     # . epilogue
 1325     89/<- %esp 5/r32/ebp
 1326     5d/pop-to-ebp
 1327     c3/return
 1328 
 1329 test-read-clobbered-reg-var:
 1330     # . prologue
 1331     55/push-ebp
 1332     89/<- %ebp 4/r32/esp
 1333     # setup
 1334     (clear-stream _test-input-stream)
 1335     (clear-stream $_test-input-buffered-file->buffer)
 1336     (clear-stream _test-output-stream)
 1337     (clear-stream $_test-output-buffered-file->buffer)
 1338     (clear-stream _test-error-stream)
 1339     (clear-stream $_test-error-buffered-file->buffer)
 1340     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
 1341     68/push 0/imm32
 1342     68/push 0/imm32
 1343     89/<- %edx 4/r32/esp
 1344     (tailor-exit-descriptor %edx 0x10)
 1345     #
 1346     (write _test-input-stream "fn foo {\n")
 1347     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1348     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1349     (write _test-input-stream "  x <- increment\n")
 1350     (write _test-input-stream "}\n")
 1351     # convert
 1352     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1353     # registers except esp clobbered at this point
 1354     # restore ed
 1355     89/<- %edx 4/r32/esp
 1356     (flush _test-output-buffered-file)
 1357     (flush _test-error-buffered-file)
 1358 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1364     # check output
 1365     (check-stream-equal _test-output-stream  ""  "F - test-read-clobbered-reg-var: output should be empty")
 1366     (check-next-stream-line-equal _test-error-stream  "fn foo: register ecx reads var 'x' after writing var 'y'"  "F - test-read-clobbered-reg-var: error message")
 1367     # check that stop(1) was called
 1368     (check-ints-equal *(edx+4) 2 "F - test-read-clobbered-reg-var: exit status")
 1369     # don't restore from ebp
 1370     81 0/subop/add %esp 8/imm32
 1371     # . epilogue
 1372     5d/pop-to-ebp
 1373     c3/return
 1374 
 1375 test-convert-function-call:
 1376     # . prologue
 1377     55/push-ebp
 1378     89/<- %ebp 4/r32/esp
 1379     # setup
 1380     (clear-stream _test-input-stream)
 1381     (clear-stream $_test-input-buffered-file->buffer)
 1382     (clear-stream _test-output-stream)
 1383     (clear-stream $_test-output-buffered-file->buffer)
 1384     #
 1385     (write _test-input-stream "fn main -> result/ebx: int {\n")
 1386     (write _test-input-stream "  result <- foo\n")
 1387     (write _test-input-stream "}\n")
 1388     (write _test-input-stream "fn foo -> result/ebx: int {\n")
 1389     (write _test-input-stream "  result <- copy 3\n")
 1390     (write _test-input-stream "}\n")
 1391     # convert
 1392     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1393     (flush _test-output-buffered-file)
 1394 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1400     # check output
 1401     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call/0")
 1402     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/1")
 1403     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/2")
 1404     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/3")
 1405     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/4")
 1406     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call/5")
 1407     (check-next-stream-line-equal _test-output-stream "    (foo)"               "F - test-convert-function-call/6")
 1408     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/7")
 1409     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call/8")
 1410     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/9")
 1411     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/10")
 1412     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/11")
 1413     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/12")
 1414     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call/13")
 1415     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/14")
 1416     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/15")
 1417     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/16")
 1418     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/17")
 1419     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"  "F - test-convert-function-call/18")
 1420     (check-next-stream-line-equal _test-output-stream "    bb/copy-to-ebx 3/imm32"  "F - test-convert-function-call/19")
 1421     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/20")
 1422     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-call/21")
 1423     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/22")
 1424     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/23")
 1425     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/24")
 1426     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/25")
 1427     # . epilogue
 1428     89/<- %esp 5/r32/ebp
 1429     5d/pop-to-ebp
 1430     c3/return
 1431 
 1432 test-convert-function-call-with-inout-with-compound-type:
 1433     # . prologue
 1434     55/push-ebp
 1435     89/<- %ebp 4/r32/esp
 1436     # setup
 1437     (clear-stream _test-input-stream)
 1438     (clear-stream $_test-input-buffered-file->buffer)
 1439     (clear-stream _test-output-stream)
 1440     (clear-stream $_test-output-buffered-file->buffer)
 1441     #
 1442     (write _test-input-stream "fn f {\n")
 1443     (write _test-input-stream "  var x: (addr int)\n")
 1444     (write _test-input-stream "  g x\n")
 1445     (write _test-input-stream "}\n")
 1446     (write _test-input-stream "fn g a: (addr int) {\n")
 1447     (write _test-input-stream "}\n")
 1448     # convert
 1449     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1450     (flush _test-output-buffered-file)
 1451 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1457     # check output
 1458     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-inout-with-compound-type/0")
 1459     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-inout-with-compound-type/1")
 1460     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-inout-with-compound-type/2")
 1461     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-inout-with-compound-type/3")
 1462     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-inout-with-compound-type/4")
 1463     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-inout-with-compound-type/5")
 1464     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-inout-with-compound-type/6")
 1465     (check-next-stream-line-equal _test-output-stream "    (g *(ebp+0xfffffffc))"  "F - test-convert-function-call-with-inout-with-compound-type/7")
 1466     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-call-with-inout-with-compound-type/8")
 1467     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-inout-with-compound-type/9")
 1468     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-inout-with-compound-type/10")
 1469     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-inout-with-compound-type/11")
 1470     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-inout-with-compound-type/12")
 1471     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-inout-with-compound-type/13")
 1472     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-inout-with-compound-type/14")
 1473     (check-next-stream-line-equal _test-output-stream "g:"                      "F - test-convert-function-call-with-inout-with-compound-type/15")
 1474     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-inout-with-compound-type/16")
 1475     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-inout-with-compound-type/17")
 1476     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-inout-with-compound-type/18")
 1477     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-inout-with-compound-type/19")
 1478     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-inout-with-compound-type/20")
 1479     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-inout-with-compound-type/21")
 1480     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-inout-with-compound-type/22")
 1481     # . epilogue
 1482     89/<- %esp 5/r32/ebp
 1483     5d/pop-to-ebp
 1484     c3/return
 1485 
 1486 test-convert-function-call-with-inout-with-type-parameter:
 1487     # . prologue
 1488     55/push-ebp
 1489     89/<- %ebp 4/r32/esp
 1490     # setup
 1491     (clear-stream _test-input-stream)
 1492     (clear-stream $_test-input-buffered-file->buffer)
 1493     (clear-stream _test-output-stream)
 1494     (clear-stream $_test-output-buffered-file->buffer)
 1495     (clear-stream _test-error-stream)
 1496     (clear-stream $_test-error-buffered-file->buffer)
 1497     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1498     68/push 0/imm32
 1499     68/push 0/imm32
 1500     89/<- %edx 4/r32/esp
 1501     (tailor-exit-descriptor %edx 0x10)
 1502     #
 1503     (write _test-input-stream "fn f {\n")
 1504     (write _test-input-stream "  var x: (addr int)\n")
 1505     (write _test-input-stream "  g x\n")
 1506     (write _test-input-stream "}\n")
 1507     (write _test-input-stream "fn g a: (addr _) {\n")
 1508     (write _test-input-stream "}\n")
 1509     # convert
 1510     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1511     # registers except esp clobbered at this point
 1512     # restore ed
 1513     89/<- %edx 4/r32/esp
 1514     (flush _test-output-buffered-file)
 1515     (flush _test-error-buffered-file)
 1516 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1522     # no error; types matched
 1523     (check-stream-equal _test-error-stream  ""  "F - test-convert-function-call-with-inout-with-type-parameter: error stream should be empty")
 1524     # don't bother checking the generated code; that's in the test 'test-local-clobbered-by-fn-output' below
 1525     # don't restore from ebp
 1526     81 0/subop/add %esp 8/imm32
 1527     # . epilogue
 1528     5d/pop-to-ebp
 1529     c3/return
 1530 
 1531 test-convert-function-call-with-incorrect-inout-type:
 1532     # . prologue
 1533     55/push-ebp
 1534     89/<- %ebp 4/r32/esp
 1535     # setup
 1536     (clear-stream _test-input-stream)
 1537     (clear-stream $_test-input-buffered-file->buffer)
 1538     (clear-stream _test-output-stream)
 1539     (clear-stream $_test-output-buffered-file->buffer)
 1540     (clear-stream _test-error-stream)
 1541     (clear-stream $_test-error-buffered-file->buffer)
 1542     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1543     68/push 0/imm32
 1544     68/push 0/imm32
 1545     89/<- %edx 4/r32/esp
 1546     (tailor-exit-descriptor %edx 0x10)
 1547     #
 1548     (write _test-input-stream "fn f {\n")
 1549     (write _test-input-stream "  var x: int\n")
 1550     (write _test-input-stream "  g x\n")
 1551     (write _test-input-stream "}\n")
 1552     (write _test-input-stream "fn g a: foo {\n")
 1553     (write _test-input-stream "}\n")
 1554     # convert
 1555     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1556     # registers except esp clobbered at this point
 1557     # restore ed
 1558     89/<- %edx 4/r32/esp
 1559     (flush _test-output-buffered-file)
 1560     (flush _test-error-buffered-file)
 1561 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1567     # check output
 1568     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-inout-type: output should be empty")
 1569     (check-next-stream-line-equal _test-error-stream  "fn f: call g: type for inout 'x' is not right"  "F - test-convert-function-call-with-incorrect-inout-type: error message")
 1570     # check that stop(1) was called
 1571     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-inout-type: exit status")
 1572     # don't restore from ebp
 1573     81 0/subop/add %esp 8/imm32
 1574     5d/pop-to-ebp
 1575     c3/return
 1576 
 1577 test-convert-function-call-with-inout-with-incorrect-compound-type:
 1578     # . prologue
 1579     55/push-ebp
 1580     89/<- %ebp 4/r32/esp
 1581     # setup
 1582     (clear-stream _test-input-stream)
 1583     (clear-stream $_test-input-buffered-file->buffer)
 1584     (clear-stream _test-output-stream)
 1585     (clear-stream $_test-output-buffered-file->buffer)
 1586     (clear-stream _test-error-stream)
 1587     (clear-stream $_test-error-buffered-file->buffer)
 1588     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1589     68/push 0/imm32
 1590     68/push 0/imm32
 1591     89/<- %edx 4/r32/esp
 1592     (tailor-exit-descriptor %edx 0x10)
 1593     #
 1594     (write _test-input-stream "fn f {\n")
 1595     (write _test-input-stream "  var x: (addr int)\n")
 1596     (write _test-input-stream "  g x\n")
 1597     (write _test-input-stream "}\n")
 1598     (write _test-input-stream "fn g a: (addr bool) {\n")
 1599     (write _test-input-stream "}\n")
 1600     # convert
 1601     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1602     # registers except esp clobbered at this point
 1603     # restore ed
 1604     89/<- %edx 4/r32/esp
 1605     (flush _test-output-buffered-file)
 1606     (flush _test-error-buffered-file)
 1607 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1613     # check output
 1614     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-inout-with-incorrect-compound-type: output should be empty")
 1615     (check-next-stream-line-equal _test-error-stream  "fn f: call g: type for inout 'x' is not right"  "F - test-convert-function-call-with-inout-with-incorrect-compound-type: error message")
 1616     # don't restore from ebp
 1617     81 0/subop/add %esp 8/imm32
 1618     # . epilogue
 1619     5d/pop-to-ebp
 1620     c3/return
 1621 
 1622 test-convert-function-call-with-inout-with-multiple-type-parameters:
 1623     # . prologue
 1624     55/push-ebp
 1625     89/<- %ebp 4/r32/esp
 1626     # setup
 1627     (clear-stream _test-input-stream)
 1628     (clear-stream $_test-input-buffered-file->buffer)
 1629     (clear-stream _test-output-stream)
 1630     (clear-stream $_test-output-buffered-file->buffer)
 1631     (clear-stream _test-error-stream)
 1632     (clear-stream $_test-error-buffered-file->buffer)
 1633     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1634     68/push 0/imm32
 1635     68/push 0/imm32
 1636     89/<- %edx 4/r32/esp
 1637     (tailor-exit-descriptor %edx 0x10)
 1638     #
 1639     (write _test-input-stream "fn f {\n")
 1640     (write _test-input-stream "  var x: (addr int)\n")
 1641     (write _test-input-stream "  var y: (addr int)\n")
 1642     (write _test-input-stream "  g x, y\n")
 1643     (write _test-input-stream "}\n")
 1644     (write _test-input-stream "fn g a: (addr _), b: (addr _) {\n")
 1645     (write _test-input-stream "}\n")
 1646     # convert
 1647     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1648     # registers except esp clobbered at this point
 1649     # restore ed
 1650     89/<- %edx 4/r32/esp
 1651     (flush _test-output-buffered-file)
 1652     (flush _test-error-buffered-file)
 1653 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1659     # no errors
 1660     (check-stream-equal _test-error-stream  ""  "F - test-convert-function-call-with-inout-with-multiple-type-parameters: error stream should be empty")
 1661     # don't bother checking the generated code
 1662     # don't restore from ebp
 1663     81 0/subop/add %esp 8/imm32
 1664     # . epilogue
 1665     5d/pop-to-ebp
 1666     c3/return
 1667 
 1668 test-type-parameter-matches-rest-of-type:
 1669     # . prologue
 1670     55/push-ebp
 1671     89/<- %ebp 4/r32/esp
 1672     # setup
 1673     (clear-stream _test-input-stream)
 1674     (clear-stream $_test-input-buffered-file->buffer)
 1675     (clear-stream _test-output-stream)
 1676     (clear-stream $_test-output-buffered-file->buffer)
 1677     (clear-stream _test-error-stream)
 1678     (clear-stream $_test-error-buffered-file->buffer)
 1679     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1680     68/push 0/imm32
 1681     68/push 0/imm32
 1682     89/<- %edx 4/r32/esp
 1683     (tailor-exit-descriptor %edx 0x10)
 1684     #
 1685     (write _test-input-stream "fn f {\n")
 1686     (write _test-input-stream "  var x: (addr array int)\n")
 1687     (write _test-input-stream "  g x\n")
 1688     (write _test-input-stream "}\n")
 1689     (write _test-input-stream "fn g a: (addr _) {\n")
 1690     (write _test-input-stream "}\n")
 1691     # convert
 1692     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1693     # registers except esp clobbered at this point
 1694     # restore ed
 1695     89/<- %edx 4/r32/esp
 1696     (flush _test-output-buffered-file)
 1697     (flush _test-error-buffered-file)
 1698 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1704     # no errors
 1705     (check-stream-equal _test-error-stream  ""  "F - test-type-parameter-matches-rest-of-type: error stream should be empty")
 1706     # don't bother checking the generated code
 1707     # don't restore from ebp
 1708     81 0/subop/add %esp 8/imm32
 1709     # . epilogue
 1710     5d/pop-to-ebp
 1711     c3/return
 1712 
 1713 test-convert-function-call-with-inout-with-incompatible-type-parameters:
 1714     # . prologue
 1715     55/push-ebp
 1716     89/<- %ebp 4/r32/esp
 1717     # setup
 1718     (clear-stream _test-input-stream)
 1719     (clear-stream $_test-input-buffered-file->buffer)
 1720     (clear-stream _test-output-stream)
 1721     (clear-stream $_test-output-buffered-file->buffer)
 1722     (clear-stream _test-error-stream)
 1723     (clear-stream $_test-error-buffered-file->buffer)
 1724     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1725     68/push 0/imm32
 1726     68/push 0/imm32
 1727     89/<- %edx 4/r32/esp
 1728     (tailor-exit-descriptor %edx 0x10)
 1729     #
 1730     (write _test-input-stream "fn f {\n")
 1731     (write _test-input-stream "  var x: (addr int)\n")
 1732     (write _test-input-stream "  var y: (addr boolean)\n")
 1733     (write _test-input-stream "  g x, y\n")
 1734     (write _test-input-stream "}\n")
 1735     (write _test-input-stream "fn g a: (addr _T), b: (addr _T) {\n")
 1736     (write _test-input-stream "}\n")
 1737     # convert
 1738     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1739     # registers except esp clobbered at this point
 1740     # restore ed
 1741     89/<- %edx 4/r32/esp
 1742     (flush _test-output-buffered-file)
 1743     (flush _test-error-buffered-file)
 1744 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1750     # check output
 1751     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-inout-with-incompatible-type-parameters: output should be empty")
 1752     (check-next-stream-line-equal _test-error-stream  "fn f: call g: type for inout 'y' is not right"  "F - test-convert-function-call-with-inout-with-incompatible-type-parameters: error message")
 1753     # don't restore from ebp
 1754     81 0/subop/add %esp 8/imm32
 1755     # . epilogue
 1756     5d/pop-to-ebp
 1757     c3/return
 1758 
 1759 test-convert-function-call-with-too-few-inouts:
 1760     # . prologue
 1761     55/push-ebp
 1762     89/<- %ebp 4/r32/esp
 1763     # setup
 1764     (clear-stream _test-input-stream)
 1765     (clear-stream $_test-input-buffered-file->buffer)
 1766     (clear-stream _test-output-stream)
 1767     (clear-stream $_test-output-buffered-file->buffer)
 1768     (clear-stream _test-error-stream)
 1769     (clear-stream $_test-error-buffered-file->buffer)
 1770     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1771     68/push 0/imm32
 1772     68/push 0/imm32
 1773     89/<- %edx 4/r32/esp
 1774     (tailor-exit-descriptor %edx 0x10)
 1775     #
 1776     (write _test-input-stream "fn f {\n")
 1777     (write _test-input-stream "  g\n")
 1778     (write _test-input-stream "}\n")
 1779     (write _test-input-stream "fn g a: int {\n")
 1780     (write _test-input-stream "}\n")
 1781     # convert
 1782     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1783     # registers except esp clobbered at this point
 1784     # restore ed
 1785     89/<- %edx 4/r32/esp
 1786     (flush _test-output-buffered-file)
 1787     (flush _test-error-buffered-file)
 1788 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1794     # check output
 1795     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-inouts: output should be empty")
 1796     (check-next-stream-line-equal _test-error-stream  "fn f: call g: too few inouts"  "F - test-convert-function-call-with-too-few-inouts: error message")
 1797     # check that stop(1) was called
 1798     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-inouts: exit status")
 1799     # don't restore from ebp
 1800     81 0/subop/add %esp 8/imm32
 1801     5d/pop-to-ebp
 1802     c3/return
 1803 
 1804 test-convert-function-call-with-too-many-inouts:
 1805     # . prologue
 1806     55/push-ebp
 1807     89/<- %ebp 4/r32/esp
 1808     # setup
 1809     (clear-stream _test-input-stream)
 1810     (clear-stream $_test-input-buffered-file->buffer)
 1811     (clear-stream _test-output-stream)
 1812     (clear-stream $_test-output-buffered-file->buffer)
 1813     (clear-stream _test-error-stream)
 1814     (clear-stream $_test-error-buffered-file->buffer)
 1815     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1816     68/push 0/imm32
 1817     68/push 0/imm32
 1818     89/<- %edx 4/r32/esp
 1819     (tailor-exit-descriptor %edx 0x10)
 1820     #
 1821     (write _test-input-stream "fn f {\n")
 1822     (write _test-input-stream "  var x: int\n")
 1823     (write _test-input-stream "  g x\n")
 1824     (write _test-input-stream "}\n")
 1825     (write _test-input-stream "fn g {\n")
 1826     (write _test-input-stream "}\n")
 1827     # convert
 1828     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1829     # registers except esp clobbered at this point
 1830     # restore ed
 1831     89/<- %edx 4/r32/esp
 1832     (flush _test-output-buffered-file)
 1833     (flush _test-error-buffered-file)
 1834 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1840     # check output
 1841     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-inouts: output should be empty")
 1842     (check-next-stream-line-equal _test-error-stream  "fn f: call g: too many inouts"  "F - test-convert-function-call-with-too-many-inouts: error message")
 1843     # check that stop(1) was called
 1844     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-inouts: exit status")
 1845     # don't restore from ebp
 1846     81 0/subop/add %esp 8/imm32
 1847     5d/pop-to-ebp
 1848     c3/return
 1849 
 1850 test-convert-function-call-with-incorrect-output-type:
 1851     # . prologue
 1852     55/push-ebp
 1853     89/<- %ebp 4/r32/esp
 1854     # setup
 1855     (clear-stream _test-input-stream)
 1856     (clear-stream $_test-input-buffered-file->buffer)
 1857     (clear-stream _test-output-stream)
 1858     (clear-stream $_test-output-buffered-file->buffer)
 1859     (clear-stream _test-error-stream)
 1860     (clear-stream $_test-error-buffered-file->buffer)
 1861     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1862     68/push 0/imm32
 1863     68/push 0/imm32
 1864     89/<- %edx 4/r32/esp
 1865     (tailor-exit-descriptor %edx 0x10)
 1866     #
 1867     (write _test-input-stream "fn f {\n")
 1868     (write _test-input-stream "  var x/eax: int <- g\n")
 1869     (write _test-input-stream "}\n")
 1870     (write _test-input-stream "fn g -> a/eax: foo {\n")
 1871     (write _test-input-stream "}\n")
 1872     # convert
 1873     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1874     # registers except esp clobbered at this point
 1875     # restore ed
 1876     89/<- %edx 4/r32/esp
 1877     (flush _test-output-buffered-file)
 1878     (flush _test-error-buffered-file)
 1879 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1885     # check output
 1886     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-type: output should be empty")
 1887     (check-next-stream-line-equal _test-error-stream  "fn f: call g: type for output 'x' is not right"  "F - test-convert-function-call-with-incorrect-output-type: error message")
 1888     # check that stop(1) was called
 1889     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-type: exit status")
 1890     # don't restore from ebp
 1891     81 0/subop/add %esp 8/imm32
 1892     5d/pop-to-ebp
 1893     c3/return
 1894 
 1895 test-convert-function-call-with-too-few-outputs:
 1896     # . prologue
 1897     55/push-ebp
 1898     89/<- %ebp 4/r32/esp
 1899     # setup
 1900     (clear-stream _test-input-stream)
 1901     (clear-stream $_test-input-buffered-file->buffer)
 1902     (clear-stream _test-output-stream)
 1903     (clear-stream $_test-output-buffered-file->buffer)
 1904     (clear-stream _test-error-stream)
 1905     (clear-stream $_test-error-buffered-file->buffer)
 1906     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1907     68/push 0/imm32
 1908     68/push 0/imm32
 1909     89/<- %edx 4/r32/esp
 1910     (tailor-exit-descriptor %edx 0x10)
 1911     #
 1912     (write _test-input-stream "fn f {\n")
 1913     (write _test-input-stream "  g\n")
 1914     (write _test-input-stream "}\n")
 1915     (write _test-input-stream "fn g -> a/eax: int {\n")
 1916     (write _test-input-stream "}\n")
 1917     # convert
 1918     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1919     # registers except esp clobbered at this point
 1920     # restore ed
 1921     89/<- %edx 4/r32/esp
 1922     (flush _test-output-buffered-file)
 1923     (flush _test-error-buffered-file)
 1924 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1930     # check output
 1931     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-outputs: output should be empty")
 1932     (check-next-stream-line-equal _test-error-stream  "fn f: call g: too few outputs"  "F - test-convert-function-call-with-too-few-outputs: error message")
 1933     # check that stop(1) was called
 1934     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-outputs: exit status")
 1935     # don't restore from ebp
 1936     81 0/subop/add %esp 8/imm32
 1937     5d/pop-to-ebp
 1938     c3/return
 1939 
 1940 test-convert-function-call-with-too-many-outputs:
 1941     # . prologue
 1942     55/push-ebp
 1943     89/<- %ebp 4/r32/esp
 1944     # setup
 1945     (clear-stream _test-input-stream)
 1946     (clear-stream $_test-input-buffered-file->buffer)
 1947     (clear-stream _test-output-stream)
 1948     (clear-stream $_test-output-buffered-file->buffer)
 1949     (clear-stream _test-error-stream)
 1950     (clear-stream $_test-error-buffered-file->buffer)
 1951     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1952     68/push 0/imm32
 1953     68/push 0/imm32
 1954     89/<- %edx 4/r32/esp
 1955     (tailor-exit-descriptor %edx 0x10)
 1956     #
 1957     (write _test-input-stream "fn f {\n")
 1958     (write _test-input-stream "  var x/eax: int <- g\n")
 1959     (write _test-input-stream "}\n")
 1960     (write _test-input-stream "fn g {\n")
 1961     (write _test-input-stream "}\n")
 1962     # convert
 1963     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1964     # registers except esp clobbered at this point
 1965     # restore ed
 1966     89/<- %edx 4/r32/esp
 1967     (flush _test-output-buffered-file)
 1968     (flush _test-error-buffered-file)
 1969 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1975     # check output
 1976     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-outputs: output should be empty")
 1977     (check-next-stream-line-equal _test-error-stream  "fn f: call g: too many outputs"  "F - test-convert-function-call-with-too-many-outputs: error message")
 1978     # check that stop(1) was called
 1979     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-outputs: exit status")
 1980     # don't restore from ebp
 1981     81 0/subop/add %esp 8/imm32
 1982     5d/pop-to-ebp
 1983     c3/return
 1984 
 1985 test-convert-function-call-with-incorrect-output-register:
 1986     # . prologue
 1987     55/push-ebp
 1988     89/<- %ebp 4/r32/esp
 1989     # setup
 1990     (clear-stream _test-input-stream)
 1991     (clear-stream $_test-input-buffered-file->buffer)
 1992     (clear-stream _test-output-stream)
 1993     (clear-stream $_test-output-buffered-file->buffer)
 1994     (clear-stream _test-error-stream)
 1995     (clear-stream $_test-error-buffered-file->buffer)
 1996     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1997     68/push 0/imm32
 1998     68/push 0/imm32
 1999     89/<- %edx 4/r32/esp
 2000     (tailor-exit-descriptor %edx 0x10)
 2001     #
 2002     (write _test-input-stream "fn f {\n")
 2003     (write _test-input-stream "  var x/ecx: int <- g\n")
 2004     (write _test-input-stream "}\n")
 2005     (write _test-input-stream "fn g -> a/eax: int {\n")
 2006     (write _test-input-stream "}\n")
 2007     # convert
 2008     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2009     # registers except esp clobbered at this point
 2010     # restore ed
 2011     89/<- %edx 4/r32/esp
 2012     (flush _test-output-buffered-file)
 2013     (flush _test-error-buffered-file)
 2014 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 2020     # check output
 2021     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-register: output should be empty")
 2022     (check-next-stream-line-equal _test-error-stream  "fn f: call g: register for output 'x' is not right"  "F - test-convert-function-call-with-incorrect-output-register: error message")
 2023     # check that stop(1) was called
 2024     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-register: exit status")
 2025     # don't restore from ebp
 2026     81 0/subop/add %esp 8/imm32
 2027     5d/pop-to-ebp
 2028     c3/return
 2029 
 2030 test-convert-function-with-local-var-dereferenced:
 2031     # . prologue
 2032     55/push-ebp
 2033     89/<- %ebp 4/r32/esp
 2034     # setup
 2035     (clear-stream _test-input-stream)
 2036     (clear-stream $_test-input-buffered-file->buffer)
 2037     (clear-stream _test-output-stream)
 2038     (clear-stream $_test-output-buffered-file->buffer)
 2039     #
 2040     (write _test-input-stream "fn foo {\n")
 2041     (write _test-input-stream "  var x/ecx: (addr int) <- copy 0\n")
 2042     (write _test-input-stream "  increment *x\n")
 2043     (write _test-input-stream "}\n")
 2044     # convert
 2045     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2046     (flush _test-output-buffered-file)
 2047 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2053     # check output
 2054     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-dereferenced/0")
 2055     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-dereferenced/1")
 2056     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-dereferenced/2")
 2057     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-dereferenced/3")
 2058     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-dereferenced/4")
 2059     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-dereferenced/5")
 2060     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-dereferenced/6")
 2061     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-local-var-dereferenced/7")
 2062     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *ecx"  "F - test-convert-function-with-local-var-dereferenced/8")
 2063     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-dereferenced/9")
 2064     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-dereferenced/10")
 2065     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-dereferenced/11")
 2066     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-dereferenced/12")
 2067     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-dereferenced/13")
 2068     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-dereferenced/14")
 2069     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-dereferenced/15")
 2070     # . epilogue
 2071     89/<- %esp 5/r32/ebp
 2072     5d/pop-to-ebp
 2073     c3/return
 2074 
 2075 # variables of type 'byte' are not allowed on the stack
 2076 test-convert-function-with-byte-operations:
 2077     # . prologue
 2078     55/push-ebp
 2079     89/<- %ebp 4/r32/esp
 2080     # setup
 2081     (clear-stream _test-input-stream)
 2082     (clear-stream $_test-input-buffered-file->buffer)
 2083     (clear-stream _test-output-stream)
 2084     (clear-stream $_test-output-buffered-file->buffer)
 2085     #
 2086     (write _test-input-stream "fn foo {\n")
 2087     (write _test-input-stream "  var x/eax: byte <- copy 0\n")
 2088     (write _test-input-stream "  var y/ecx: byte <- copy 0\n")
 2089     (write _test-input-stream "  y <- copy-byte x\n")
 2090     (write _test-input-stream "  var z/edx: (addr byte) <- copy 0\n")
 2091     (write _test-input-stream "  y <- copy-byte *z\n")
 2092     (write _test-input-stream "  copy-byte-to *z, x\n")
 2093     (write _test-input-stream "}\n")
 2094     # convert
 2095     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2096     (flush _test-output-buffered-file)
 2097 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2103     # check output
 2104     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-function-with-byte-operations/0")
 2105     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-function-with-byte-operations/1")
 2106     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-function-with-byte-operations/2")
 2107     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-function-with-byte-operations/3")
 2108     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-function-with-byte-operations/4")
 2109     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-function-with-byte-operations/5")
 2110     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-function-with-byte-operations/6")
 2111     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-function-with-byte-operations/7")
 2112     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-function-with-byte-operations/8")
 2113     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"                  "F - test-convert-function-with-byte-operations/9")
 2114     (check-next-stream-line-equal _test-output-stream "    8a/byte-> %eax 0x00000001/r32"           "F - test-convert-function-with-byte-operations/10")
 2115     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %edx"                    "F - test-convert-function-with-byte-operations/11")
 2116     (check-next-stream-line-equal _test-output-stream "    ba/copy-to-edx 0/imm32"                  "F - test-convert-function-with-byte-operations/12")
 2117     (check-next-stream-line-equal _test-output-stream "    8a/byte-> *edx 0x00000001/r32"           "F - test-convert-function-with-byte-operations/13")
 2118     (check-next-stream-line-equal _test-output-stream "    88/byte<- *edx 0x00000000/r32"           "F - test-convert-function-with-byte-operations/14")
 2119     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %edx"                     "F - test-convert-function-with-byte-operations/15")
 2120     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-function-with-byte-operations/16")
 2121     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-function-with-byte-operations/17")
 2122     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-function-with-byte-operations/18")
 2123     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-function-with-byte-operations/19")
 2124     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-function-with-byte-operations/20")
 2125     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-function-with-byte-operations/21")
 2126     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-function-with-byte-operations/22")
 2127     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-function-with-byte-operations/23")
 2128     # . epilogue
 2129     89/<- %esp 5/r32/ebp
 2130     5d/pop-to-ebp
 2131     c3/return
 2132 
 2133 # variables of type 'byte' _can_ be function args. They then occupy 4 bytes.
 2134 test-copy-byte-var-from-fn-arg:
 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 x: byte, y: int {\n")
 2145     (write _test-input-stream "  var a/eax: byte <- copy x\n")
 2146     (write _test-input-stream "  var b/eax: int <- copy y\n")
 2147     (write _test-input-stream "}\n")
 2148     # convert
 2149     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2150     (flush _test-output-buffered-file)
 2151 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2157     # check output
 2158     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-copy-byte-from-fn-arg/0")
 2159     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-copy-byte-from-fn-arg/1")
 2160     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-copy-byte-from-fn-arg/2")
 2161     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-copy-byte-from-fn-arg/3")
 2162     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-copy-byte-from-fn-arg/4")
 2163     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-copy-byte-from-fn-arg/5")
 2164     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-copy-byte-from-fn-arg/6")
 2165     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/7")
 2166     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x0000000c) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/8")
 2167     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"   "F - test-copy-byte-from-fn-arg/9")
 2168     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-copy-byte-from-fn-arg/10")
 2169     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-copy-byte-from-fn-arg/11")
 2170     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-copy-byte-from-fn-arg/12")
 2171     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-copy-byte-from-fn-arg/13")
 2172     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-copy-byte-from-fn-arg/14")
 2173     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-copy-byte-from-fn-arg/15")
 2174     # . epilogue
 2175     89/<- %esp 5/r32/ebp
 2176     5d/pop-to-ebp
 2177     c3/return
 2178 
 2179 test-convert-compare-register-with-literal:
 2180     # . prologue
 2181     55/push-ebp
 2182     89/<- %ebp 4/r32/esp
 2183     # setup
 2184     (clear-stream _test-input-stream)
 2185     (clear-stream $_test-input-buffered-file->buffer)
 2186     (clear-stream _test-output-stream)
 2187     (clear-stream $_test-output-buffered-file->buffer)
 2188     #
 2189     (write _test-input-stream "fn foo {\n")
 2190     (write _test-input-stream "  var x/ecx: int <- copy 0\n")
 2191     (write _test-input-stream "  compare x, 0\n")
 2192     (write _test-input-stream "}\n")
 2193     # convert
 2194     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2195     (flush _test-output-buffered-file)
 2196 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2202     # check output
 2203     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-compare-register-with-literal/0")
 2204     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-compare-register-with-literal/1")
 2205     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-compare-register-with-literal/2")
 2206     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-compare-register-with-literal/3")
 2207     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-compare-register-with-literal/4")
 2208     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-compare-register-with-literal/5")
 2209     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 2210     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-compare-register-with-literal/7")
 2211     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0/imm32"  "F - test-convert-compare-register-with-literal/8")
 2212     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 2213     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-compare-register-with-literal/10")
 2214     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-compare-register-with-literal/11")
 2215     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-compare-register-with-literal/12")
 2216     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-compare-register-with-literal/13")
 2217     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-compare-register-with-literal/14")
 2218     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-compare-register-with-literal/15")
 2219     # . epilogue
 2220     89/<- %esp 5/r32/ebp
 2221     5d/pop-to-ebp
 2222     c3/return
 2223 
 2224 test-unknown-variable:
 2225     # . prologue
 2226     55/push-ebp
 2227     89/<- %ebp 4/r32/esp
 2228     # setup
 2229     (clear-stream _test-input-stream)
 2230     (clear-stream $_test-input-buffered-file->buffer)
 2231     (clear-stream _test-output-stream)
 2232     (clear-stream $_test-output-buffered-file->buffer)
 2233     (clear-stream _test-error-stream)
 2234     (clear-stream $_test-error-buffered-file->buffer)
 2235     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2236     68/push 0/imm32
 2237     68/push 0/imm32
 2238     89/<- %edx 4/r32/esp
 2239     (tailor-exit-descriptor %edx 0x10)
 2240     #
 2241     (write _test-input-stream "fn foo {\n")
 2242     (write _test-input-stream "  compare x, 0\n")
 2243     (write _test-input-stream "}\n")
 2244     # convert
 2245     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2246     # registers except esp clobbered at this point
 2247     # restore ed
 2248     89/<- %edx 4/r32/esp
 2249     (flush _test-output-buffered-file)
 2250     (flush _test-error-buffered-file)
 2251 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 2257     # check output
 2258     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable: output should be empty")
 2259     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable: error message")
 2260     # check that stop(1) was called
 2261     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable: exit status")
 2262     # don't restore from ebp
 2263     81 0/subop/add %esp 8/imm32
 2264     # . epilogue
 2265     5d/pop-to-ebp
 2266     c3/return
 2267 
 2268 test-convert-function-with-local-var-in-block:
 2269     # . prologue
 2270     55/push-ebp
 2271     89/<- %ebp 4/r32/esp
 2272     # setup
 2273     (clear-stream _test-input-stream)
 2274     (clear-stream $_test-input-buffered-file->buffer)
 2275     (clear-stream _test-output-stream)
 2276     (clear-stream $_test-output-buffered-file->buffer)
 2277     #
 2278     (write _test-input-stream "fn foo {\n")
 2279     (write _test-input-stream "  {\n")
 2280     (write _test-input-stream "    var x: int\n")
 2281     (write _test-input-stream "    increment x\n")
 2282     (write _test-input-stream "  }\n")
 2283     (write _test-input-stream "}\n")
 2284     # convert
 2285     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2286     (flush _test-output-buffered-file)
 2287 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2293     # check output
 2294     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-block/0")
 2295     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-block/1")
 2296     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-block/2")
 2297     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-block/3")
 2298     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-block/4")
 2299     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-block/5")
 2300     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-block/6")
 2301     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-local-var-in-block/7")
 2302     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-block/8")
 2303     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-block/9")
 2304     (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")
 2305     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-block/11")
 2306     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-local-var-in-block/12")
 2307     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-block/13")
 2308     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-block/14")
 2309     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-block/15")
 2310     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-block/16")
 2311     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-block/17")
 2312     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-block/18")
 2313     # . epilogue
 2314     89/<- %esp 5/r32/ebp
 2315     5d/pop-to-ebp
 2316     c3/return
 2317 
 2318 test-convert-function-with-local-var-in-named-block:
 2319     # . prologue
 2320     55/push-ebp
 2321     89/<- %ebp 4/r32/esp
 2322     # setup
 2323     (clear-stream _test-input-stream)
 2324     (clear-stream $_test-input-buffered-file->buffer)
 2325     (clear-stream _test-output-stream)
 2326     (clear-stream $_test-output-buffered-file->buffer)
 2327     #
 2328     (write _test-input-stream "fn foo {\n")
 2329     (write _test-input-stream "  $bar: {\n")
 2330     (write _test-input-stream "    var x: int\n")
 2331     (write _test-input-stream "    increment x\n")
 2332     (write _test-input-stream "  }\n")
 2333     (write _test-input-stream "}\n")
 2334     # convert
 2335     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2336     (flush _test-output-buffered-file)
 2337 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2343     # check output
 2344     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-named-block/0")
 2345     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-named-block/1")
 2346     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-named-block/2")
 2347     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-named-block/3")
 2348     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-named-block/4")
 2349     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-named-block/5")
 2350     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-named-block/6")
 2351     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-local-var-in-named-block/7")
 2352     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-named-block/8")
 2353     (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")
 2354     (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")
 2355     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-named-block/11")
 2356     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-local-var-in-named-block/12")
 2357     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-named-block/13")
 2358     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-named-block/14")
 2359     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-named-block/15")
 2360     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-named-block/16")
 2361     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-named-block/17")
 2362     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-named-block/18")
 2363     # . epilogue
 2364     89/<- %esp 5/r32/ebp
 2365     5d/pop-to-ebp
 2366     c3/return
 2367 
 2368 test-unknown-variable-in-named-block:
 2369     # . prologue
 2370     55/push-ebp
 2371     89/<- %ebp 4/r32/esp
 2372     # setup
 2373     (clear-stream _test-input-stream)
 2374     (clear-stream $_test-input-buffered-file->buffer)
 2375     (clear-stream _test-output-stream)
 2376     (clear-stream $_test-output-buffered-file->buffer)
 2377     (clear-stream _test-error-stream)
 2378     (clear-stream $_test-error-buffered-file->buffer)
 2379     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2380     68/push 0/imm32
 2381     68/push 0/imm32
 2382     89/<- %edx 4/r32/esp
 2383     (tailor-exit-descriptor %edx 0x10)
 2384     #
 2385     (write _test-input-stream "fn foo {\n")
 2386     (write _test-input-stream "  $a: {\n")
 2387     (write _test-input-stream "    compare x, 0\n")
 2388     (write _test-input-stream "  }\n")
 2389     (write _test-input-stream "}\n")
 2390     # convert
 2391     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2392     # registers except esp clobbered at this point
 2393     # restore ed
 2394     89/<- %edx 4/r32/esp
 2395     (flush _test-output-buffered-file)
 2396     (flush _test-error-buffered-file)
 2397 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 2403     # check output
 2404     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable-in-named-block: output should be empty")
 2405     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable-in-named-block: error message")
 2406     # check that stop(1) was called
 2407     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable-in-named-block: exit status")
 2408     # don't restore from ebp
 2409     81 0/subop/add %esp 8/imm32
 2410     # . epilogue
 2411     5d/pop-to-ebp
 2412     c3/return
 2413 
 2414 test-always-shadow-outermost-reg-vars-in-function:
 2415     # . prologue
 2416     55/push-ebp
 2417     89/<- %ebp 4/r32/esp
 2418     # setup
 2419     (clear-stream _test-input-stream)
 2420     (clear-stream $_test-input-buffered-file->buffer)
 2421     (clear-stream _test-output-stream)
 2422     (clear-stream $_test-output-buffered-file->buffer)
 2423     #
 2424     (write _test-input-stream "fn foo {\n")
 2425     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2426     (write _test-input-stream "}\n")
 2427     # convert
 2428     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2429     (flush _test-output-buffered-file)
 2430 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2436     # check output
 2437     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-always-shadow-outermost-reg-vars-in-function/0")
 2438     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-always-shadow-outermost-reg-vars-in-function/1")
 2439     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-always-shadow-outermost-reg-vars-in-function/2")
 2440     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-always-shadow-outermost-reg-vars-in-function/3")
 2441     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-always-shadow-outermost-reg-vars-in-function/4")
 2442     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-always-shadow-outermost-reg-vars-in-function/5")
 2443     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 2444     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-always-shadow-outermost-reg-vars-in-function/8")
 2445     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 2446     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-always-shadow-outermost-reg-vars-in-function/12")
 2447     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-always-shadow-outermost-reg-vars-in-function/13")
 2448     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-always-shadow-outermost-reg-vars-in-function/14")
 2449     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-always-shadow-outermost-reg-vars-in-function/15")
 2450     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-always-shadow-outermost-reg-vars-in-function/16")
 2451     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-always-shadow-outermost-reg-vars-in-function/17")
 2452     # . epilogue
 2453     89/<- %esp 5/r32/ebp
 2454     5d/pop-to-ebp
 2455     c3/return
 2456 
 2457 _pending-test-clobber-dead-local:
 2458     # . prologue
 2459     55/push-ebp
 2460     89/<- %ebp 4/r32/esp
 2461     # setup
 2462     (clear-stream _test-input-stream)
 2463     (clear-stream $_test-input-buffered-file->buffer)
 2464     (clear-stream _test-output-stream)
 2465     (clear-stream $_test-output-buffered-file->buffer)
 2466     #
 2467     (write _test-input-stream "fn foo {\n")
 2468     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2469     (write _test-input-stream "  {\n")
 2470     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2471     (write _test-input-stream "  }\n")
 2472     (write _test-input-stream "}\n")
 2473     # convert
 2474     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2475     (flush _test-output-buffered-file)
 2476 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2482     # check output
 2483     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-clobber-dead-local/0")
 2484     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-clobber-dead-local/1")
 2485     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-clobber-dead-local/2")
 2486     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-clobber-dead-local/3")
 2487     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-clobber-dead-local/4")
 2488     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-clobber-dead-local/5")
 2489     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-clobber-dead-local/6")
 2490     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-clobber-dead-local/7")
 2491     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-clobber-dead-local/8")
 2492     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-clobber-dead-local/9")
 2493     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-clobber-dead-local/10")  # no push/pop here
 2494     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-clobber-dead-local/11")
 2495     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-clobber-dead-local/12")
 2496     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-clobber-dead-local/13")
 2497     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-clobber-dead-local/14")
 2498     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-clobber-dead-local/15")
 2499     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-clobber-dead-local/16")
 2500     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-clobber-dead-local/17")
 2501     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-clobber-dead-local/18")
 2502     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-clobber-dead-local/19")
 2503     # . epilogue
 2504     89/<- %esp 5/r32/ebp
 2505     5d/pop-to-ebp
 2506     c3/return
 2507 
 2508 test-shadow-live-local:
 2509     # . prologue
 2510     55/push-ebp
 2511     89/<- %ebp 4/r32/esp
 2512     # setup
 2513     (clear-stream _test-input-stream)
 2514     (clear-stream $_test-input-buffered-file->buffer)
 2515     (clear-stream _test-output-stream)
 2516     (clear-stream $_test-output-buffered-file->buffer)
 2517     #
 2518     (write _test-input-stream "fn foo {\n")
 2519     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2520     (write _test-input-stream "  {\n")
 2521     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2522     (write _test-input-stream "  }\n")
 2523     (write _test-input-stream "  x <- increment\n")
 2524     (write _test-input-stream "}\n")
 2525     # convert
 2526     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2527     (flush _test-output-buffered-file)
 2528 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2534     # check output
 2535     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-local/0")
 2536     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-local/1")
 2537     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-local/2")
 2538     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-local/3")
 2539     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-local/4")
 2540     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-local/5")
 2541     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-live-local/6")
 2542     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-live-local/7")
 2543     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-local/8")
 2544     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-local/9")
 2545     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-local/10")
 2546     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-local/11")
 2547     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-local/12")
 2548     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-local/13")
 2549     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-local/14")
 2550     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-local/15")
 2551     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-live-local/16")
 2552     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-local/17")
 2553     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-local/18")
 2554     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-local/19")
 2555     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-local/20")
 2556     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-local/21")
 2557     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-local/22")
 2558     # . epilogue
 2559     89/<- %esp 5/r32/ebp
 2560     5d/pop-to-ebp
 2561     c3/return
 2562 
 2563 test-shadow-name:
 2564     # . prologue
 2565     55/push-ebp
 2566     89/<- %ebp 4/r32/esp
 2567     # setup
 2568     (clear-stream _test-input-stream)
 2569     (clear-stream $_test-input-buffered-file->buffer)
 2570     (clear-stream _test-output-stream)
 2571     (clear-stream $_test-output-buffered-file->buffer)
 2572     #
 2573     (write _test-input-stream "fn foo {\n")
 2574     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2575     (write _test-input-stream "  {\n")
 2576     (write _test-input-stream "    var x/edx: int <- copy 4\n")
 2577     (write _test-input-stream "  }\n")
 2578     (write _test-input-stream "  x <- increment\n")
 2579     (write _test-input-stream "}\n")
 2580     # convert
 2581     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2582     (flush _test-output-buffered-file)
 2583 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2589     # check output
 2590     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name/0")
 2591     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name/1")
 2592     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name/2")
 2593     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name/3")
 2594     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name/4")
 2595     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name/5")
 2596     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name/6")
 2597     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name/7")
 2598     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name/8")
 2599     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name/9")
 2600     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name/10")
 2601     (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name/11")
 2602     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name/12")
 2603     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name/13")
 2604     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name/14")
 2605     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name/15")
 2606     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name/16")
 2607     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name/17")
 2608     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name/18")
 2609     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name/19")
 2610     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name/20")
 2611     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name/21")
 2612     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name/22")
 2613     # . epilogue
 2614     89/<- %esp 5/r32/ebp
 2615     5d/pop-to-ebp
 2616     c3/return
 2617 
 2618 test-shadow-name-2:
 2619     # . prologue
 2620     55/push-ebp
 2621     89/<- %ebp 4/r32/esp
 2622     # setup
 2623     (clear-stream _test-input-stream)
 2624     (clear-stream $_test-input-buffered-file->buffer)
 2625     (clear-stream _test-output-stream)
 2626     (clear-stream $_test-output-buffered-file->buffer)
 2627     #
 2628     (write _test-input-stream "fn foo {\n")
 2629     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2630     (write _test-input-stream "  {\n")
 2631     (write _test-input-stream "    var x/edx: int <- copy 4\n")
 2632     (write _test-input-stream "    var y/ecx: int <- copy 5\n")
 2633     (write _test-input-stream "  }\n")
 2634     (write _test-input-stream "  x <- increment\n")
 2635     (write _test-input-stream "}\n")
 2636     # convert
 2637     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2638     (flush _test-output-buffered-file)
 2639 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2645     # check output
 2646     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name-2/0")
 2647     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name-2/1")
 2648     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name-2/2")
 2649     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name-2/3")
 2650     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name-2/4")
 2651     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name-2/5")
 2652     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name-2/6")
 2653     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name-2/7")
 2654     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name-2/8")
 2655     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name-2/9")
 2656     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name-2/10")
 2657     (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name-2/11")
 2658     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-name-2/12")
 2659     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 5/imm32"  "F - test-shadow-name-2/13")
 2660     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-name-2/14")
 2661     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name-2/15")
 2662     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name-2/16")
 2663     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name-2/17")
 2664     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name-2/18")
 2665     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name-2/19")
 2666     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name-2/20")
 2667     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name-2/21")
 2668     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name-2/22")
 2669     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name-2/23")
 2670     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name-2/24")
 2671     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name-2/25")
 2672     # . epilogue
 2673     89/<- %esp 5/r32/ebp
 2674     5d/pop-to-ebp
 2675     c3/return
 2676 
 2677 test-do-not-spill-same-register-in-block:
 2678     # . prologue
 2679     55/push-ebp
 2680     89/<- %ebp 4/r32/esp
 2681     # setup
 2682     (clear-stream _test-input-stream)
 2683     (clear-stream $_test-input-buffered-file->buffer)
 2684     (clear-stream _test-output-stream)
 2685     (clear-stream $_test-output-buffered-file->buffer)
 2686     #
 2687     (write _test-input-stream "fn foo {\n")
 2688     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2689     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2690     (write _test-input-stream "  y <- increment\n")
 2691     (write _test-input-stream "}\n")
 2692     # convert
 2693     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2694     (flush _test-output-buffered-file)
 2695 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2701     # check output
 2702     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-do-not-spill-same-register-in-block/0")
 2703     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-do-not-spill-same-register-in-block/1")
 2704     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-do-not-spill-same-register-in-block/2")
 2705     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-do-not-spill-same-register-in-block/3")
 2706     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-do-not-spill-same-register-in-block/4")
 2707     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-do-not-spill-same-register-in-block/5")
 2708     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-do-not-spill-same-register-in-block/6")
 2709     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-do-not-spill-same-register-in-block/7")
 2710     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-do-not-spill-same-register-in-block/8")
 2711     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-do-not-spill-same-register-in-block/9")
 2712     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-do-not-spill-same-register-in-block/10")
 2713     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-do-not-spill-same-register-in-block/11")
 2714     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-do-not-spill-same-register-in-block/12")
 2715     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-do-not-spill-same-register-in-block/13")
 2716     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-do-not-spill-same-register-in-block/14")
 2717     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-do-not-spill-same-register-in-block/15")
 2718     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-do-not-spill-same-register-in-block/16")
 2719     # . epilogue
 2720     89/<- %esp 5/r32/ebp
 2721     5d/pop-to-ebp
 2722     c3/return
 2723 
 2724 test-spill-different-register-in-block:
 2725     # . prologue
 2726     55/push-ebp
 2727     89/<- %ebp 4/r32/esp
 2728     # setup
 2729     (clear-stream _test-input-stream)
 2730     (clear-stream $_test-input-buffered-file->buffer)
 2731     (clear-stream _test-output-stream)
 2732     (clear-stream $_test-output-buffered-file->buffer)
 2733     #
 2734     (write _test-input-stream "fn foo {\n")
 2735     (write _test-input-stream "  var x/eax: int <- copy 3\n")
 2736     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2737     (write _test-input-stream "  y <- increment\n")
 2738     (write _test-input-stream "}\n")
 2739     # convert
 2740     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2741     (flush _test-output-buffered-file)
 2742 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2748     # check output
 2749     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-spill-different-register-in-block/0")
 2750     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-spill-different-register-in-block/1")
 2751     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-spill-different-register-in-block/2")
 2752     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-spill-different-register-in-block/3")
 2753     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-spill-different-register-in-block/4")
 2754     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-spill-different-register-in-block/5")
 2755     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-spill-different-register-in-block/6")
 2756     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-spill-different-register-in-block/7")
 2757     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-spill-different-register-in-block/8")
 2758     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-spill-different-register-in-block/9")
 2759     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-spill-different-register-in-block/10")
 2760     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-spill-different-register-in-block/11")
 2761     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-spill-different-register-in-block/12")
 2762     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-spill-different-register-in-block/13")
 2763     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-spill-different-register-in-block/14")
 2764     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-spill-different-register-in-block/15")
 2765     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-spill-different-register-in-block/16")
 2766     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-spill-different-register-in-block/17")
 2767     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-spill-different-register-in-block/18")
 2768     # . epilogue
 2769     89/<- %esp 5/r32/ebp
 2770     5d/pop-to-ebp
 2771     c3/return
 2772 
 2773 test-shadow-live-output:
 2774     # . prologue
 2775     55/push-ebp
 2776     89/<- %ebp 4/r32/esp
 2777     # setup
 2778     (clear-stream _test-input-stream)
 2779     (clear-stream $_test-input-buffered-file->buffer)
 2780     (clear-stream _test-output-stream)
 2781     (clear-stream $_test-output-buffered-file->buffer)
 2782     #
 2783     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2784     (write _test-input-stream "  x <- copy 3\n")
 2785     (write _test-input-stream "  {\n")
 2786     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2787     (write _test-input-stream "  }\n")
 2788     (write _test-input-stream "  x <- increment\n")
 2789     (write _test-input-stream "}\n")
 2790     # convert
 2791     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2792     (flush _test-output-buffered-file)
 2793 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2799     # check output
 2800     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-output/0")
 2801     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-output/1")
 2802     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-output/2")
 2803     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-output/3")
 2804     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-output/4")
 2805     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-output/5")
 2806     (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
 2807     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-output/8")
 2808     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-output/9")
 2809     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-output/10")
 2810     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-output/11")
 2811     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-output/12")
 2812     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-output/13")
 2813     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-output/14")
 2814     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-output/15")
 2815     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-output/17")
 2816     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-output/18")
 2817     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-output/19")
 2818     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-output/20")
 2819     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-output/21")
 2820     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-output/21")
 2821     # . epilogue
 2822     89/<- %esp 5/r32/ebp
 2823     5d/pop-to-ebp
 2824     c3/return
 2825 
 2826 test-stmt-defines-output-in-same-register-as-inout:
 2827     # . prologue
 2828     55/push-ebp
 2829     89/<- %ebp 4/r32/esp
 2830     # setup
 2831     (clear-stream _test-input-stream)
 2832     (clear-stream $_test-input-buffered-file->buffer)
 2833     (clear-stream _test-output-stream)
 2834     (clear-stream $_test-output-buffered-file->buffer)
 2835     (clear-stream _test-error-stream)
 2836     (clear-stream $_test-error-buffered-file->buffer)
 2837     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2838     68/push 0/imm32
 2839     68/push 0/imm32
 2840     89/<- %edx 4/r32/esp
 2841     (tailor-exit-descriptor %edx 0x10)
 2842     #
 2843     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2844     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2845     (write _test-input-stream "  x <- copy y\n")  # writing to a fn output is currently the only way for a statement to define a new var
 2846     (write _test-input-stream "}\n")
 2847     # convert
 2848     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2849     # registers except esp clobbered at this point
 2850     # restore ed
 2851     89/<- %edx 4/r32/esp
 2852     (flush _test-output-buffered-file)
 2853     (flush _test-error-buffered-file)
 2854 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 2860     # no error; we looked up 'y' correctly before pushing the binding for 'x'
 2861     (check-stream-equal _test-error-stream  ""  "F - test-stmt-defines-output-in-same-register-as-inout: error stream should be empty")
 2862     # don't bother checking the generated code; that's in the test 'test-local-clobbered-by-fn-output' below
 2863     # don't restore from ebp
 2864     81 0/subop/add %esp 8/imm32
 2865     # . epilogue
 2866     5d/pop-to-ebp
 2867     c3/return
 2868 
 2869 test-local-clobbered-by-fn-output:
 2870     # . prologue
 2871     55/push-ebp
 2872     89/<- %ebp 4/r32/esp
 2873     # setup
 2874     (clear-stream _test-input-stream)
 2875     (clear-stream $_test-input-buffered-file->buffer)
 2876     (clear-stream _test-output-stream)
 2877     (clear-stream $_test-output-buffered-file->buffer)
 2878     #
 2879     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2880     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2881     (write _test-input-stream "  x <- copy y\n")
 2882     (write _test-input-stream "}\n")
 2883     # convert
 2884     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2885     (flush _test-output-buffered-file)
 2886 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2892     # check output
 2893     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-local-clobbered-by-fn-output/0")
 2894     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-local-clobbered-by-fn-output/1")
 2895     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-local-clobbered-by-fn-output/2")
 2896     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-local-clobbered-by-fn-output/3")
 2897     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-local-clobbered-by-fn-output/4")
 2898     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-local-clobbered-by-fn-output/5")
 2899     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-local-clobbered-by-fn-output/6")  # no push because it's an output reg
 2900     (check-next-stream-line-equal _test-output-stream "    89/<- %ecx 0x00000001/r32"  "F - test-local-clobbered-by-fn-output/7")
 2901     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-local-clobbered-by-fn-output/8")
 2902     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-local-clobbered-by-fn-output/9")
 2903     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-local-clobbered-by-fn-output/10")
 2904     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-local-clobbered-by-fn-output/11")
 2905     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-local-clobbered-by-fn-output/12")
 2906     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-local-clobbered-by-fn-output/13")
 2907     # . epilogue
 2908     89/<- %esp 5/r32/ebp
 2909     5d/pop-to-ebp
 2910     c3/return
 2911 
 2912 test-read-output:
 2913     # . prologue
 2914     55/push-ebp
 2915     89/<- %ebp 4/r32/esp
 2916     # setup
 2917     (clear-stream _test-input-stream)
 2918     (clear-stream $_test-input-buffered-file->buffer)
 2919     (clear-stream _test-output-stream)
 2920     (clear-stream $_test-output-buffered-file->buffer)
 2921     #
 2922     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2923     (write _test-input-stream "  x <- copy 0x34\n")
 2924     (write _test-input-stream "  compare x, 0x35\n")
 2925     (write _test-input-stream "}\n")
 2926     # convert
 2927     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2928     (flush _test-output-buffered-file)
 2929 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2935     # check output
 2936     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-read-output/0")
 2937     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-read-output/1")
 2938     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-read-output/2")
 2939     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-read-output/3")
 2940     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-read-output/4")
 2941     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-read-output/5")
 2942     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x34/imm32"  "F - test-read-output/6")
 2943     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0x35/imm32"  "F - test-read-output/7")
 2944     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-read-output/8")
 2945     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-read-output/9")
 2946     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-read-output/10")
 2947     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-read-output/11")
 2948     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-read-output/12")
 2949     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-read-output/13")
 2950     # . epilogue
 2951     89/<- %esp 5/r32/ebp
 2952     5d/pop-to-ebp
 2953     c3/return
 2954 
 2955 test-fn-output-written-in-inner-block:
 2956     # . prologue
 2957     55/push-ebp
 2958     89/<- %ebp 4/r32/esp
 2959     # setup
 2960     (clear-stream _test-input-stream)
 2961     (clear-stream $_test-input-buffered-file->buffer)
 2962     (clear-stream _test-output-stream)
 2963     (clear-stream $_test-output-buffered-file->buffer)
 2964     #
 2965     (write _test-input-stream "fn foo -> out/edi: int {\n")
 2966     (write _test-input-stream "  var a/eax: int <- copy 3\n")  # define outer local
 2967     (write _test-input-stream "  {\n")
 2968     (write _test-input-stream "    var a/ecx: int <- copy 4\n")  # shadow outer local
 2969     (write _test-input-stream "    out <- copy a\n")  # write to fn output
 2970     (write _test-input-stream "  }\n")
 2971     (write _test-input-stream "  compare a, 0\n")  # use outer local
 2972     (write _test-input-stream "}\n")
 2973     # convert
 2974     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2975     (flush _test-output-buffered-file)
 2976 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2982     # no error; defining 'out' didn't interfere with the reclamation of 'b'
 2983     # check output
 2984     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-fn-output-written-in-inner-block/0")
 2985     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-fn-output-written-in-inner-block/1")
 2986     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-fn-output-written-in-inner-block/2")
 2987     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-fn-output-written-in-inner-block/3")
 2988     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-fn-output-written-in-inner-block/4")
 2989     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-fn-output-written-in-inner-block/5")
 2990     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-fn-output-written-in-inner-block/6")
 2991     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-fn-output-written-in-inner-block/7")
 2992     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-fn-output-written-in-inner-block/8")
 2993     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-fn-output-written-in-inner-block/9")
 2994     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-fn-output-written-in-inner-block/10")
 2995     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-fn-output-written-in-inner-block/10")
 2996     (check-next-stream-line-equal _test-output-stream "      89/<- %edi 0x00000001/r32"  "F - test-fn-output-written-in-inner-block/11")
 2997     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx"  "F - test-fn-output-written-in-inner-block/12")
 2998     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-fn-output-written-in-inner-block/13")
 2999     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-fn-output-written-in-inner-block/14")
 3000     (check-next-stream-line-equal _test-output-stream "    3d/compare-eax-with 0/imm32"  "F - test-fn-output-written-in-inner-block/15")
 3001     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-fn-output-written-in-inner-block/16")
 3002     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-fn-output-written-in-inner-block/17")
 3003     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-fn-output-written-in-inner-block/18")
 3004     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-fn-output-written-in-inner-block/19")
 3005     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-fn-output-written-in-inner-block/20")
 3006     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-fn-output-written-in-inner-block/21")
 3007     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-fn-output-written-in-inner-block/22")
 3008     # . epilogue
 3009     89/<- %esp 5/r32/ebp
 3010     5d/pop-to-ebp
 3011     c3/return
 3012 
 3013 test-convert-function-with-branches-in-block:
 3014     # . prologue
 3015     55/push-ebp
 3016     89/<- %ebp 4/r32/esp
 3017     # setup
 3018     (clear-stream _test-input-stream)
 3019     (clear-stream $_test-input-buffered-file->buffer)
 3020     (clear-stream _test-output-stream)
 3021     (clear-stream $_test-output-buffered-file->buffer)
 3022     #
 3023     (write _test-input-stream "fn foo x: int {\n")
 3024     (write _test-input-stream "  {\n")
 3025     (write _test-input-stream "    break-if->=\n")
 3026     (write _test-input-stream "    loop-if-addr<\n")
 3027     (write _test-input-stream "    increment x\n")
 3028     (write _test-input-stream "    loop\n")
 3029     (write _test-input-stream "  }\n")
 3030     (write _test-input-stream "}\n")
 3031     # convert
 3032     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3033     (flush _test-output-buffered-file)
 3034 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3040     # check output
 3041     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-block/0")
 3042     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-block/1")
 3043     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-block/2")
 3044     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-block/3")
 3045     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-block/4")
 3046     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-block/5")
 3047     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-block/6")
 3048     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-in-block/7")
 3049     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/8")
 3050     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-block/9")
 3051     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-in-block/10")
 3052     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/11")
 3053     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/12")
 3054     (check-next-stream-line-equal _test-output-stream "        0f 83/jump-if-addr>= break/disp32"  "F - test-convert-function-with-branches-in-block/13")
 3055     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:loop/disp32"  "F - test-convert-function-with-branches-in-block/14")
 3056     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/15")
 3057     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-block/16")
 3058     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-in-block/17")
 3059     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-block/18")
 3060     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-in-block/19")
 3061     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-block/20")
 3062     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-block/21")
 3063     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-block/22")
 3064     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-block/23")
 3065     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-block/24")
 3066     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-block/25")
 3067     # . epilogue
 3068     89/<- %esp 5/r32/ebp
 3069     5d/pop-to-ebp
 3070     c3/return
 3071 
 3072 test-convert-function-with-branches-in-named-block:
 3073     # . prologue
 3074     55/push-ebp
 3075     89/<- %ebp 4/r32/esp
 3076     # setup
 3077     (clear-stream _test-input-stream)
 3078     (clear-stream $_test-input-buffered-file->buffer)
 3079     (clear-stream _test-output-stream)
 3080     (clear-stream $_test-output-buffered-file->buffer)
 3081     #
 3082     (write _test-input-stream "fn foo x: int {\n")
 3083     (write _test-input-stream "  $bar: {\n")
 3084     (write _test-input-stream "    break-if->= $bar\n")
 3085     (write _test-input-stream "    loop-if-addr< $bar\n")
 3086     (write _test-input-stream "    increment x\n")
 3087     (write _test-input-stream "    loop\n")
 3088     (write _test-input-stream "  }\n")
 3089     (write _test-input-stream "}\n")
 3090     # convert
 3091     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3092     (flush _test-output-buffered-file)
 3093 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3099     # check output
 3100     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-named-block/0")
 3101     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-named-block/1")
 3102     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-named-block/2")
 3103     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-named-block/3")
 3104     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-named-block/4")
 3105     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-named-block/5")
 3106     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-named-block/6")
 3107     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-branches-in-named-block/7")
 3108     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/8")
 3109     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-named-block/9")
 3110     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:break/disp32"  "F - test-convert-function-with-branches-in-named-block/10")
 3111     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/11")
 3112     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/12")
 3113     (check-next-stream-line-equal _test-output-stream "        0f 83/jump-if-addr>= break/disp32"  "F - test-convert-function-with-branches-in-named-block/13")
 3114     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:loop/disp32"  "F - test-convert-function-with-branches-in-named-block/14")
 3115     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/15")
 3116     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-named-block/16")
 3117     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"   "F - test-convert-function-with-branches-in-named-block/17")
 3118     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-named-block/18")
 3119     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-branches-in-named-block/19")
 3120     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-named-block/20")
 3121     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-named-block/21")
 3122     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-named-block/22")
 3123     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-named-block/23")
 3124     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-named-block/24")
 3125     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-named-block/25")
 3126     # . epilogue
 3127     89/<- %esp 5/r32/ebp
 3128     5d/pop-to-ebp
 3129     c3/return
 3130 
 3131 test-convert-function-with-var-in-nested-block:
 3132     # . prologue
 3133     55/push-ebp
 3134     89/<- %ebp 4/r32/esp
 3135     # setup
 3136     (clear-stream _test-input-stream)
 3137     (clear-stream $_test-input-buffered-file->buffer)
 3138     (clear-stream _test-output-stream)
 3139     (clear-stream $_test-output-buffered-file->buffer)
 3140     #
 3141     (write _test-input-stream "fn foo x: int {\n")
 3142     (write _test-input-stream "  {\n")
 3143     (write _test-input-stream "    {\n")
 3144     (write _test-input-stream "      var x: int\n")
 3145     (write _test-input-stream "      increment x\n")
 3146     (write _test-input-stream "    }\n")
 3147     (write _test-input-stream "  }\n")
 3148     (write _test-input-stream "}\n")
 3149     # convert
 3150     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3151     (flush _test-output-buffered-file)
 3152 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3158     # check output
 3159     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-var-in-nested-block/0")
 3160     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-var-in-nested-block/1")
 3161     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-var-in-nested-block/2")
 3162     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-var-in-nested-block/3")
 3163     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-var-in-nested-block/4")
 3164     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-var-in-nested-block/5")
 3165     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-var-in-nested-block/6")
 3166     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-var-in-nested-block/7")
 3167     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-var-in-nested-block/8")
 3168     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-var-in-nested-block/9")
 3169     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-var-in-nested-block/10")
 3170     (check-next-stream-line-equal _test-output-stream "        ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-var-in-nested-block/11")
 3171     (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")
 3172     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-var-in-nested-block/13")
 3173     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-var-in-nested-block/14")
 3174     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-var-in-nested-block/15")
 3175     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-var-in-nested-block/16")
 3176     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-var-in-nested-block/17")
 3177     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-var-in-nested-block/18")
 3178     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-var-in-nested-block/19")
 3179     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-var-in-nested-block/20")
 3180     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-var-in-nested-block/21")
 3181     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-var-in-nested-block/22")
 3182     # . epilogue
 3183     89/<- %esp 5/r32/ebp
 3184     5d/pop-to-ebp
 3185     c3/return
 3186 
 3187 test-convert-function-with-multiple-vars-in-nested-blocks:
 3188     # . prologue
 3189     55/push-ebp
 3190     89/<- %ebp 4/r32/esp
 3191     # setup
 3192     (clear-stream _test-input-stream)
 3193     (clear-stream $_test-input-buffered-file->buffer)
 3194     (clear-stream _test-output-stream)
 3195     (clear-stream $_test-output-buffered-file->buffer)
 3196     #
 3197     (write _test-input-stream "fn foo x: int {\n")
 3198     (write _test-input-stream "  {\n")
 3199     (write _test-input-stream "    var x/eax: int <- copy 0\n")
 3200     (write _test-input-stream "    {\n")
 3201     (write _test-input-stream "      var y: int\n")
 3202     (write _test-input-stream "      x <- add y\n")
 3203     (write _test-input-stream "    }\n")
 3204     (write _test-input-stream "  }\n")
 3205     (write _test-input-stream "}\n")
 3206     # convert
 3207     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3208     (flush _test-output-buffered-file)
 3209 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3215     # check output
 3216     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-multiple-vars-in-nested-blocks/0")
 3217     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/1")
 3218     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-multiple-vars-in-nested-blocks/2")
 3219     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/3")
 3220     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/4")
 3221     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/5")
 3222     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/6")
 3223     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/7")
 3224     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %eax"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/8")
 3225     (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")
 3226     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/10")
 3227     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/11")
 3228     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/12")
 3229     (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")
 3230     (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")
 3231     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/15")
 3232     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/16")
 3233     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %eax"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/17")
 3234     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/18")
 3235     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/19")
 3236     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/20")
 3237     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/21")
 3238     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/22")
 3239     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/23")
 3240     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-multiple-vars-in-nested-blocks/24")
 3241     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-multiple-vars-in-nested-blocks/25")
 3242     # . epilogue
 3243     89/<- %esp 5/r32/ebp
 3244     5d/pop-to-ebp
 3245     c3/return
 3246 
 3247 test-convert-function-with-branches-and-local-vars:
 3248     # A conditional 'break' after a 'var' in a block is converted into a
 3249     # nested block that performs all necessary cleanup before jumping. This
 3250     # results in some ugly code duplication.
 3251     # . prologue
 3252     55/push-ebp
 3253     89/<- %ebp 4/r32/esp
 3254     # setup
 3255     (clear-stream _test-input-stream)
 3256     (clear-stream $_test-input-buffered-file->buffer)
 3257     (clear-stream _test-output-stream)
 3258     (clear-stream $_test-output-buffered-file->buffer)
 3259     #
 3260     (write _test-input-stream "fn foo {\n")
 3261     (write _test-input-stream "  {\n")
 3262     (write _test-input-stream "    var x: int\n")
 3263     (write _test-input-stream "    break-if->=\n")
 3264     (write _test-input-stream "    increment x\n")
 3265     (write _test-input-stream "  }\n")
 3266     (write _test-input-stream "}\n")
 3267     # convert
 3268     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3269     (flush _test-output-buffered-file)
 3270 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3276     # check output
 3277     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-local-vars/0")
 3278     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-local-vars/1")
 3279     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-local-vars/2")
 3280     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-and-local-vars/3")
 3281     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-local-vars/4")
 3282     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-local-vars/5")
 3283     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-local-vars/6")
 3284     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-local-vars/7")
 3285     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-local-vars/8")
 3286     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-local-vars/9")
 3287     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-and-local-vars/10")
 3288     (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")
 3289     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-and-local-vars/12")
 3290     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-local-vars/13")
 3291     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-branches-and-local-vars/14")
 3292     (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")
 3293     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-local-vars/16")
 3294     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-local-vars/17")
 3295     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-local-vars/18")
 3296     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-local-vars/19")
 3297     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-local-vars/20")
 3298     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-and-local-vars/21")
 3299     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-local-vars/22")
 3300     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-local-vars/23")
 3301     # . epilogue
 3302     89/<- %esp 5/r32/ebp
 3303     5d/pop-to-ebp
 3304     c3/return
 3305 
 3306 test-convert-function-with-conditional-loops-and-local-vars:
 3307     # A conditional 'loop' after a 'var' in a block is converted into a nested
 3308     # block that performs all necessary cleanup before jumping. This results
 3309     # in some ugly code duplication.
 3310     # . prologue
 3311     55/push-ebp
 3312     89/<- %ebp 4/r32/esp
 3313     # setup
 3314     (clear-stream _test-input-stream)
 3315     (clear-stream $_test-input-buffered-file->buffer)
 3316     (clear-stream _test-output-stream)
 3317     (clear-stream $_test-output-buffered-file->buffer)
 3318     #
 3319     (write _test-input-stream "fn foo {\n")
 3320     (write _test-input-stream "  {\n")
 3321     (write _test-input-stream "    var x: int\n")
 3322     (write _test-input-stream "    loop-if->=\n")
 3323     (write _test-input-stream "    increment x\n")
 3324     (write _test-input-stream "  }\n")
 3325     (write _test-input-stream "}\n")
 3326     # convert
 3327     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3328     (flush _test-output-buffered-file)
 3329 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3335     # check output
 3336     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-conditional-loops-and-local-vars/0")
 3337     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-conditional-loops-and-local-vars/1")
 3338     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-conditional-loops-and-local-vars/2")
 3339     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-conditional-loops-and-local-vars/3")
 3340     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-conditional-loops-and-local-vars/4")
 3341     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/5")
 3342     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-conditional-loops-and-local-vars/6")
 3343     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/7")
 3344     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-conditional-loops-and-local-vars/8")
 3345     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-conditional-loops-and-local-vars/9")
 3346     (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")
 3347     (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")
 3348     (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")
 3349     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-conditional-loops-and-local-vars/13")
 3350     (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")
 3351     (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")
 3352     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-conditional-loops-and-local-vars/16")
 3353     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/17")
 3354     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-conditional-loops-and-local-vars/18")
 3355     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/19")
 3356     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-conditional-loops-and-local-vars/20")
 3357     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-conditional-loops-and-local-vars/21")
 3358     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-conditional-loops-and-local-vars/22")
 3359     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-conditional-loops-and-local-vars/23")
 3360     # . epilogue
 3361     89/<- %esp 5/r32/ebp
 3362     5d/pop-to-ebp
 3363     c3/return
 3364 
 3365 test-convert-function-with-unconditional-loops-and-local-vars:
 3366     # An unconditional 'loop' after a 'var' in a block is emitted _after_ the
 3367     # regular block cleanup. Any instructions after 'loop' are dead and
 3368     # therefore skipped.
 3369     # . prologue
 3370     55/push-ebp
 3371     89/<- %ebp 4/r32/esp
 3372     # setup
 3373     (clear-stream _test-input-stream)
 3374     (clear-stream $_test-input-buffered-file->buffer)
 3375     (clear-stream _test-output-stream)
 3376     (clear-stream $_test-output-buffered-file->buffer)
 3377     #
 3378     (write _test-input-stream "fn foo {\n")
 3379     (write _test-input-stream "  {\n")
 3380     (write _test-input-stream "    var x: int\n")
 3381     (write _test-input-stream "    loop\n")
 3382     (write _test-input-stream "    increment x\n")
 3383     (write _test-input-stream "  }\n")
 3384     (write _test-input-stream "}\n")
 3385     # convert
 3386     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3387     (flush _test-output-buffered-file)
 3388 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3394     # check output
 3395     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-loops-and-local-vars/0")
 3396     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/1")
 3397     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-loops-and-local-vars/2")
 3398     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/3")
 3399     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/4")
 3400     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/5")
 3401     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/6")
 3402     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/7")
 3403     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-loops-and-local-vars/8")
 3404     (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")
 3405     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-unconditional-loops-and-local-vars/10")
 3406     # not emitted:                                           ff 0/subop/increment *(ebp+0xfffffffc)
 3407     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/11")
 3408     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/12")
 3409     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/13")
 3410     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/14")
 3411     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/15")
 3412     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/16")
 3413     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-loops-and-local-vars/17")
 3414     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-loops-and-local-vars/18")
 3415     # . epilogue
 3416     89/<- %esp 5/r32/ebp
 3417     5d/pop-to-ebp
 3418     c3/return
 3419 
 3420 test-convert-function-with-branches-and-loops-and-local-vars:
 3421     # . prologue
 3422     55/push-ebp
 3423     89/<- %ebp 4/r32/esp
 3424     # setup
 3425     (clear-stream _test-input-stream)
 3426     (clear-stream $_test-input-buffered-file->buffer)
 3427     (clear-stream _test-output-stream)
 3428     (clear-stream $_test-output-buffered-file->buffer)
 3429     #
 3430     (write _test-input-stream "fn foo {\n")
 3431     (write _test-input-stream "  {\n")
 3432     (write _test-input-stream "    var x: int\n")
 3433     (write _test-input-stream "    break-if->=\n")
 3434     (write _test-input-stream "    increment x\n")
 3435     (write _test-input-stream "    loop\n")
 3436     (write _test-input-stream "  }\n")
 3437     (write _test-input-stream "}\n")
 3438     # convert
 3439     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3440     (flush _test-output-buffered-file)
 3441 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3447     # check output
 3448     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-loops-and-local-vars/0")
 3449     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/1")
 3450     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-loops-and-local-vars/2")
 3451     (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")
 3452     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/4")
 3453     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/5")
 3454     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/6")
 3455     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/7")
 3456     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-loops-and-local-vars/8")
 3457     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/9")
 3458     (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")
 3459     (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")
 3460     (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")
 3461     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/13")
 3462     (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")
 3463     (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")
 3464     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/16")
 3465     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/17")
 3466     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/18")
 3467     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/19")
 3468     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/20")
 3469     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/21")
 3470     (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")
 3471     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-loops-and-local-vars/23")
 3472     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-loops-and-local-vars/24")
 3473     # . epilogue
 3474     89/<- %esp 5/r32/ebp
 3475     5d/pop-to-ebp
 3476     c3/return
 3477 
 3478 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars:
 3479     # . prologue
 3480     55/push-ebp
 3481     89/<- %ebp 4/r32/esp
 3482     # setup
 3483     (clear-stream _test-input-stream)
 3484     (clear-stream $_test-input-buffered-file->buffer)
 3485     (clear-stream _test-output-stream)
 3486     (clear-stream $_test-output-buffered-file->buffer)
 3487     #
 3488     (write _test-input-stream "fn foo {\n")
 3489     (write _test-input-stream "  a: {\n")
 3490     (write _test-input-stream "    var x: int\n")
 3491     (write _test-input-stream "    {\n")
 3492     (write _test-input-stream "      var y: int\n")
 3493     (write _test-input-stream "      break-if->= a\n")
 3494     (write _test-input-stream "      increment x\n")
 3495     (write _test-input-stream "      loop\n")
 3496     (write _test-input-stream "    }\n")
 3497     (write _test-input-stream "  }\n")
 3498     (write _test-input-stream "}\n")
 3499     # convert
 3500     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3501     (flush _test-output-buffered-file)
 3502 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3508     # check output
 3509     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/0")
 3510     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/1")
 3511     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/2")
 3512     (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")
 3513     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/4")
 3514     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/5")
 3515     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/6")
 3516     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/7")
 3517     (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")
 3518     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/9")
 3519     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/10")
 3520     (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")
 3521     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/12")
 3522     (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")
 3523     (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")
 3524     (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")
 3525     (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")
 3526     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/17")
 3527     (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")
 3528     (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")
 3529     (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")
 3530     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/21")
 3531     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/22")
 3532     (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")
 3533     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/24")
 3534     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/25")
 3535     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/26")
 3536     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/27")
 3537     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/28")
 3538     (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")
 3539     (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")
 3540     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/31")
 3541     # . epilogue
 3542     89/<- %esp 5/r32/ebp
 3543     5d/pop-to-ebp
 3544     c3/return
 3545 
 3546 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2:
 3547     # . prologue
 3548     55/push-ebp
 3549     89/<- %ebp 4/r32/esp
 3550     # setup
 3551     (clear-stream _test-input-stream)
 3552     (clear-stream $_test-input-buffered-file->buffer)
 3553     (clear-stream _test-output-stream)
 3554     (clear-stream $_test-output-buffered-file->buffer)
 3555     # non-local conditional branch from a block without a local variable,
 3556     # unwinding a local on the stack
 3557     (write _test-input-stream "fn foo {\n")
 3558     (write _test-input-stream "  a: {\n")
 3559     (write _test-input-stream "    var x: int\n")
 3560     (write _test-input-stream "    {\n")
 3561     (write _test-input-stream "      break-if->= a\n")
 3562     (write _test-input-stream "    }\n")
 3563     (write _test-input-stream "  }\n")
 3564     (write _test-input-stream "}\n")
 3565     # convert
 3566     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3567     (flush _test-output-buffered-file)
 3568 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3574     # check output
 3575     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/0")
 3576     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/1")
 3577     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/2")
 3578     (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-2/3")
 3579     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/4")
 3580     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/5")
 3581     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/6")
 3582     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/7")
 3583     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/8")
 3584     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/9")
 3585     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/10")
 3586     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/11")
 3587     (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-2/12")
 3588     (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-2/13")
 3589     (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-2/14")
 3590     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/15")
 3591     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/16")
 3592     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/17")
 3593     (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-2/18")
 3594     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/19")
 3595     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/20")
 3596     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/21")
 3597     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/22")
 3598     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/23")
 3599     (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-2/24")
 3600     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/25")
 3601     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/26")
 3602     # . epilogue
 3603     89/<- %esp 5/r32/ebp
 3604     5d/pop-to-ebp
 3605     c3/return
 3606 
 3607 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3:
 3608     # . prologue
 3609     55/push-ebp
 3610     89/<- %ebp 4/r32/esp
 3611     # setup
 3612     (clear-stream _test-input-stream)
 3613     (clear-stream $_test-input-buffered-file->buffer)
 3614     (clear-stream _test-output-stream)
 3615     (clear-stream $_test-output-buffered-file->buffer)
 3616     # non-local unconditional branch from a block without a local variable,
 3617     # unwinding a local on the stack
 3618     (write _test-input-stream "fn foo {\n")
 3619     (write _test-input-stream "  a: {\n")
 3620     (write _test-input-stream "    var x: int\n")
 3621     (write _test-input-stream "    {\n")
 3622     (write _test-input-stream "      break a\n")
 3623     (write _test-input-stream "    }\n")
 3624     (write _test-input-stream "  }\n")
 3625     (write _test-input-stream "}\n")
 3626     # convert
 3627     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3628     (flush _test-output-buffered-file)
 3629 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3635     # check output
 3636     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/0")
 3637     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/1")
 3638     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/2")
 3639     (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/3")
 3640     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/4")
 3641     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/5")
 3642     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/6")
 3643     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/7")
 3644     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/8")
 3645     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/9")
 3646     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/10")
 3647     (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-3/11")
 3648     (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-3/12")
 3649     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/14")
 3650     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/15")
 3651     (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-3/16")
 3652     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/17")
 3653     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/18")
 3654     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/19")
 3655     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/20")
 3656     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/21")
 3657     (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-3/22")
 3658     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/23")
 3659     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/24")
 3660     # . epilogue
 3661     89/<- %esp 5/r32/ebp
 3662     5d/pop-to-ebp
 3663     c3/return
 3664 
 3665 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4:
 3666     # . prologue
 3667     55/push-ebp
 3668     89/<- %ebp 4/r32/esp
 3669     # setup
 3670     (clear-stream _test-input-stream)
 3671     (clear-stream $_test-input-buffered-file->buffer)
 3672     (clear-stream _test-output-stream)
 3673     (clear-stream $_test-output-buffered-file->buffer)
 3674     #
 3675     (write _test-input-stream "fn foo {\n")
 3676     (write _test-input-stream "  a: {\n")
 3677     (write _test-input-stream "    var x/esi: int <- copy 0\n")
 3678     (write _test-input-stream "    {\n")
 3679     (write _test-input-stream "      break a\n")
 3680     (write _test-input-stream "    }\n")
 3681     (write _test-input-stream "  }\n")
 3682     (write _test-input-stream "}\n")
 3683     # convert
 3684     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3685     (flush _test-output-buffered-file)
 3686 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3692     # check output
 3693     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/0")
 3694     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/1")
 3695     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/2")
 3696     (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-4/3")
 3697     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/4")
 3698     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/5")
 3699     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/6")
 3700     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/7")
 3701     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %esi"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/8")
 3702     (check-next-stream-line-equal _test-output-stream "      be/copy-to-esi 0/imm32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/9")
 3703     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/10")
 3704     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/11")
 3705     (check-next-stream-line-equal _test-output-stream "        8f 0/subop/pop %esi"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/12")
 3706     (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-4/13")
 3707     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/14")
 3708     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/15")
 3709     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %esi"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/16")
 3710     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/17")
 3711     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/18")
 3712     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/19")
 3713     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/20")
 3714     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/21")
 3715     (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-4/22")
 3716     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/23")
 3717     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/24")
 3718     # . epilogue
 3719     89/<- %esp 5/r32/ebp
 3720     5d/pop-to-ebp
 3721     c3/return
 3722 
 3723 test-convert-function-with-nonlocal-unconditional-break-and-local-vars:
 3724     # . prologue
 3725     55/push-ebp
 3726     89/<- %ebp 4/r32/esp
 3727     # setup
 3728     (clear-stream _test-input-stream)
 3729     (clear-stream $_test-input-buffered-file->buffer)
 3730     (clear-stream _test-output-stream)
 3731     (clear-stream $_test-output-buffered-file->buffer)
 3732     #
 3733     (write _test-input-stream "fn foo {\n")
 3734     (write _test-input-stream "  a: {\n")
 3735     (write _test-input-stream "    var x: int\n")
 3736     (write _test-input-stream "    {\n")
 3737     (write _test-input-stream "      var y: int\n")
 3738     (write _test-input-stream "      break a\n")
 3739     (write _test-input-stream "      increment x\n")
 3740     (write _test-input-stream "    }\n")
 3741     (write _test-input-stream "  }\n")
 3742     (write _test-input-stream "}\n")
 3743     # convert
 3744     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3745     (flush _test-output-buffered-file)
 3746 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3752     # check output
 3753     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/0")
 3754     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/1")
 3755     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/2")
 3756     (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")
 3757     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/4")
 3758     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/5")
 3759     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/6")
 3760     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/7")
 3761     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/8")
 3762     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/9")
 3763     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/10")
 3764     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/11")
 3765     (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")
 3766     (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")
 3767     (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")
 3768     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/15")
 3769     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/16")
 3770     (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")
 3771     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/18")
 3772     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/19")
 3773     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/20")
 3774     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/21")
 3775     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/22")
 3776     (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")
 3777     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/24")
 3778     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/25")
 3779     # . epilogue
 3780     89/<- %esp 5/r32/ebp
 3781     5d/pop-to-ebp
 3782     c3/return
 3783 
 3784 test-convert-function-with-unconditional-break-and-local-vars:
 3785     # . prologue
 3786     55/push-ebp
 3787     89/<- %ebp 4/r32/esp
 3788     # setup
 3789     (clear-stream _test-input-stream)
 3790     (clear-stream $_test-input-buffered-file->buffer)
 3791     (clear-stream _test-output-stream)
 3792     (clear-stream $_test-output-buffered-file->buffer)
 3793     #
 3794     (write _test-input-stream "fn foo {\n")
 3795     (write _test-input-stream "  {\n")
 3796     (write _test-input-stream "    var x: int\n")
 3797     (write _test-input-stream "    {\n")
 3798     (write _test-input-stream "      var y: int\n")
 3799     (write _test-input-stream "      break\n")
 3800     (write _test-input-stream "      increment x\n")
 3801     (write _test-input-stream "    }\n")
 3802     (write _test-input-stream "  }\n")
 3803     (write _test-input-stream "}\n")
 3804     # convert
 3805     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3806     (flush _test-output-buffered-file)
 3807 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3813     # check output
 3814     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-break-and-local-vars/0")
 3815     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-break-and-local-vars/1")
 3816     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-break-and-local-vars/2")
 3817     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-break-and-local-vars/3")
 3818     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-break-and-local-vars/4")
 3819     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/5")
 3820     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-break-and-local-vars/6")
 3821     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/7")
 3822     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-break-and-local-vars/8")
 3823     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-unconditional-break-and-local-vars/9")
 3824     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/10")
 3825     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/11")
 3826     (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")
 3827     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-unconditional-break-and-local-vars/13")
 3828     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/14")
 3829     (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")
 3830     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-break-and-local-vars/16")
 3831     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/17")
 3832     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-break-and-local-vars/18")
 3833     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/19")
 3834     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-break-and-local-vars/20")
 3835     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-break-and-local-vars/21")
 3836     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-break-and-local-vars/22")
 3837     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-break-and-local-vars/23")
 3838     # . epilogue
 3839     89/<- %esp 5/r32/ebp
 3840     5d/pop-to-ebp
 3841     c3/return
 3842 
 3843 test-convert-function-with-nonlocal-unconditional-loop-and-local-vars:
 3844     # . prologue
 3845     55/push-ebp
 3846     89/<- %ebp 4/r32/esp
 3847     # setup
 3848     (clear-stream _test-input-stream)
 3849     (clear-stream $_test-input-buffered-file->buffer)
 3850     (clear-stream _test-output-stream)
 3851     (clear-stream $_test-output-buffered-file->buffer)
 3852     #
 3853     (write _test-input-stream "fn foo {\n")
 3854     (write _test-input-stream "  a: {\n")
 3855     (write _test-input-stream "    var x: int\n")
 3856     (write _test-input-stream "    {\n")
 3857     (write _test-input-stream "      var y: int\n")
 3858     (write _test-input-stream "      loop a\n")
 3859     (write _test-input-stream "      increment x\n")
 3860     (write _test-input-stream "    }\n")
 3861     (write _test-input-stream "  }\n")
 3862     (write _test-input-stream "}\n")
 3863     # convert
 3864     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3865     (flush _test-output-buffered-file)
 3866 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3872     # check output
 3873     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/0")
 3874     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/1")
 3875     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/2")
 3876     (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")
 3877     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/4")
 3878     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/5")
 3879     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/6")
 3880     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/7")
 3881     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/8")
 3882     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/9")
 3883     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/10")
 3884     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/11")
 3885     (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")
 3886     (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")
 3887     (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")
 3888     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/15")
 3889     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/16")
 3890     (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")
 3891     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/18")
 3892     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/19")
 3893     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/20")
 3894     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/21")
 3895     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/22")
 3896     (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")
 3897     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/24")
 3898     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/25")
 3899     # . epilogue
 3900     89/<- %esp 5/r32/ebp
 3901     5d/pop-to-ebp
 3902     c3/return
 3903 
 3904 test-convert-function-with-local-array-var-in-mem:
 3905     # . prologue
 3906     55/push-ebp
 3907     89/<- %ebp 4/r32/esp
 3908     # setup
 3909     (clear-stream _test-input-stream)
 3910     (clear-stream $_test-input-buffered-file->buffer)
 3911     (clear-stream _test-output-stream)
 3912     (clear-stream $_test-output-buffered-file->buffer)
 3913     #
 3914     (write _test-input-stream "fn foo {\n")
 3915     (write _test-input-stream "  var x: (array int 3)\n")
 3916     (write _test-input-stream "}\n")
 3917     # convert
 3918     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3919     (flush _test-output-buffered-file)
 3920 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3926     # check output
 3927     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-var-in-mem/0")
 3928     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-var-in-mem/1")
 3929     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-var-in-mem/2")
 3930     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-array-var-in-mem/3")
 3931     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-var-in-mem/4")
 3932     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-var-in-mem/5")
 3933     # define x
 3934     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-function-with-local-array-var-in-mem/7")
 3935     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-function-with-local-array-var-in-mem/8")
 3936     # reclaim x
 3937     (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")
 3938     #
 3939     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-var-in-mem/10")
 3940     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-var-in-mem/11")
 3941     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-var-in-mem/12")
 3942     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-array-var-in-mem/13")
 3943     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-var-in-mem/14")
 3944     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-var-in-mem/15")
 3945     # . epilogue
 3946     89/<- %esp 5/r32/ebp
 3947     5d/pop-to-ebp
 3948     c3/return
 3949 
 3950 test-array-size-in-hex:
 3951     # . prologue
 3952     55/push-ebp
 3953     89/<- %ebp 4/r32/esp
 3954     # setup
 3955     (clear-stream _test-input-stream)
 3956     (clear-stream $_test-input-buffered-file->buffer)
 3957     (clear-stream _test-output-stream)
 3958     (clear-stream $_test-output-buffered-file->buffer)
 3959     (clear-stream _test-error-stream)
 3960     (clear-stream $_test-error-buffered-file->buffer)
 3961     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 3962     68/push 0/imm32
 3963     68/push 0/imm32
 3964     89/<- %edx 4/r32/esp
 3965     (tailor-exit-descriptor %edx 0x10)
 3966     #
 3967     (write _test-input-stream "fn foo {\n")
 3968     (write _test-input-stream "  var x: (array int 10)\n")
 3969     (write _test-input-stream "}\n")
 3970     # convert
 3971     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 3972     # registers except esp clobbered at this point
 3973     # restore ed
 3974     89/<- %edx 4/r32/esp
 3975     (flush _test-output-buffered-file)
 3976     (flush _test-error-buffered-file)
 3977 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 3983     # check output
 3984     (check-stream-equal _test-output-stream  ""  "F - test-array-size-in-hex: output should be empty")
 3985     (check-next-stream-line-equal _test-error-stream  "literal integers are always hex in Mu; either start '10' with a '0x' to be unambiguous, or convert it to decimal."  "F - test-array-size-in-hex: error message")
 3986     # check that stop(1) was called
 3987     (check-ints-equal *(edx+4) 2 "F - test-array-size-in-hex: exit status")
 3988     # don't restore from ebp
 3989     81 0/subop/add %esp 8/imm32
 3990     # . epilogue
 3991     5d/pop-to-ebp
 3992     c3/return
 3993 
 3994 test-convert-function-with-populate:
 3995     # . prologue
 3996     55/push-ebp
 3997     89/<- %ebp 4/r32/esp
 3998     # setup
 3999     (clear-stream _test-input-stream)
 4000     (clear-stream $_test-input-buffered-file->buffer)
 4001     (clear-stream _test-output-stream)
 4002     (clear-stream $_test-output-buffered-file->buffer)
 4003     #
 4004     (write _test-input-stream "fn foo {\n")
 4005     (write _test-input-stream "  var x/ecx: (addr handle array int) <- copy 0\n")
 4006     (write _test-input-stream "  populate x, 7\n")
 4007     (write _test-input-stream "}\n")
 4008     # convert
 4009     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4010     (flush _test-output-buffered-file)
 4011 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4017     # check output
 4018     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-populate/0")
 4019     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-populate/1")
 4020     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-populate/2")
 4021     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-populate/3")
 4022     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-populate/4")
 4023     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-populate/5")
 4024     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-populate/6")
 4025     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-populate/7")
 4026     (check-next-stream-line-equal _test-output-stream "    (allocate-array2 Heap 0x00000004 7 %ecx)"  "F - test-convert-function-with-populate/8")  # 4 = size-of(int)
 4027     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-populate/9")
 4028     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-populate/10")
 4029     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-populate/11")
 4030     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-populate/12")
 4031     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-populate/13")
 4032     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-populate/14")
 4033     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-populate/15")
 4034     # . epilogue
 4035     89/<- %esp 5/r32/ebp
 4036     5d/pop-to-ebp
 4037     c3/return
 4038 
 4039 # special-case for size(byte) when allocating array
 4040 test-convert-function-with-local-array-of-bytes-in-mem:
 4041     # . prologue
 4042     55/push-ebp
 4043     89/<- %ebp 4/r32/esp
 4044     # setup
 4045     (clear-stream _test-input-stream)
 4046     (clear-stream $_test-input-buffered-file->buffer)
 4047     (clear-stream _test-output-stream)
 4048     (clear-stream $_test-output-buffered-file->buffer)
 4049     #
 4050     (write _test-input-stream "fn foo {\n")
 4051     (write _test-input-stream "  var x: (array byte 3)\n")
 4052     (write _test-input-stream "}\n")
 4053     # convert
 4054     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4055     (flush _test-output-buffered-file)
 4056 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4062     # check output
 4063     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-of-bytes-in-mem/0")
 4064     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/1")
 4065     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-of-bytes-in-mem/2")
 4066     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-array-of-bytes-in-mem/3")
 4067     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/4")
 4068     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-of-bytes-in-mem/5")
 4069     # define x
 4070     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x00000003)"  "F - test-convert-function-with-local-array-of-bytes-in-mem/7")
 4071     (check-next-stream-line-equal _test-output-stream "    68/push 0x00000003/imm32"  "F - test-convert-function-with-local-array-of-bytes-in-mem/8")
 4072     # reclaim x
 4073     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000007/imm32"  "F - test-convert-function-with-local-array-of-bytes-in-mem/9")
 4074     #
 4075     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/10")
 4076     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-of-bytes-in-mem/11")
 4077     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/12")
 4078     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-array-of-bytes-in-mem/13")
 4079     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-of-bytes-in-mem/14")
 4080     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-of-bytes-in-mem/15")
 4081     # . epilogue
 4082     89/<- %esp 5/r32/ebp
 4083     5d/pop-to-ebp
 4084     c3/return
 4085 
 4086 test-convert-address:
 4087     # . prologue
 4088     55/push-ebp
 4089     89/<- %ebp 4/r32/esp
 4090     # setup
 4091     (clear-stream _test-input-stream)
 4092     (clear-stream $_test-input-buffered-file->buffer)
 4093     (clear-stream _test-output-stream)
 4094     (clear-stream $_test-output-buffered-file->buffer)
 4095     #
 4096     (write _test-input-stream "fn foo {\n")
 4097     (write _test-input-stream "  var a: int\n")
 4098     (write _test-input-stream "  var b/eax: (addr int) <- address a\n")
 4099     (write _test-input-stream "}\n")
 4100     # convert
 4101     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4102     (flush _test-output-buffered-file)
 4103 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4109     # check output
 4110     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-address/0")
 4111     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-address/1")
 4112     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-address/2")
 4113     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-address/3")
 4114     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-address/4")
 4115     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-address/5")
 4116     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-address/6")
 4117     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-address/7")
 4118     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000000/r32"  "F - test-convert-address/8")
 4119     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-address/9")
 4120     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-address/10")
 4121     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-address/11")
 4122     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-address/12")
 4123     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-address/13")
 4124     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-address/14")
 4125     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-address/15")
 4126     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-address/16")
 4127     # . epilogue
 4128     89/<- %esp 5/r32/ebp
 4129     5d/pop-to-ebp
 4130     c3/return
 4131 
 4132 test-convert-length-of-array:
 4133     # . prologue
 4134     55/push-ebp
 4135     89/<- %ebp 4/r32/esp
 4136     # setup
 4137     (clear-stream _test-input-stream)
 4138     (clear-stream $_test-input-buffered-file->buffer)
 4139     (clear-stream _test-output-stream)
 4140     (clear-stream $_test-output-buffered-file->buffer)
 4141     #
 4142     (write _test-input-stream "fn foo a: (addr array int) {\n")
 4143     (write _test-input-stream "  var b/eax: (addr array int) <- copy a\n")
 4144     (write _test-input-stream "  var c/eax: int <- length b\n")
 4145     (write _test-input-stream "}\n")
 4146     # convert
 4147     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4148     (flush _test-output-buffered-file)
 4149 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4155     # check output
 4156     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array/0")
 4157     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array/1")
 4158     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array/2")
 4159     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array/3")
 4160     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array/4")
 4161     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array/5")
 4162     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array/6")
 4163     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array/7")
 4164     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array/8")
 4165     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array/9")
 4166     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array/10")
 4167     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array/11")
 4168     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array/12")
 4169     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array/13")
 4170     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array/14")
 4171     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array/15")
 4172     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array/16")
 4173     # . epilogue
 4174     89/<- %esp 5/r32/ebp
 4175     5d/pop-to-ebp
 4176     c3/return
 4177 
 4178 # special-case for size(byte) when computing array length
 4179 test-convert-length-of-array-of-bytes:
 4180     # . prologue
 4181     55/push-ebp
 4182     89/<- %ebp 4/r32/esp
 4183     # setup
 4184     (clear-stream _test-input-stream)
 4185     (clear-stream $_test-input-buffered-file->buffer)
 4186     (clear-stream _test-output-stream)
 4187     (clear-stream $_test-output-buffered-file->buffer)
 4188     #
 4189     (write _test-input-stream "fn foo a: (addr array byte) {\n")
 4190     (write _test-input-stream "  var b/eax: (addr array byte) <- copy a\n")
 4191     (write _test-input-stream "  var c/eax: int <- length b\n")
 4192     (write _test-input-stream "}\n")
 4193     # convert
 4194     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4195     (flush _test-output-buffered-file)
 4196 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4202     # check output
 4203     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-bytes/0")
 4204     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-bytes/1")
 4205     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-bytes/2")
 4206     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-bytes/3")
 4207     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-bytes/4")
 4208     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-bytes/5")
 4209     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-bytes/6")
 4210     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/7")
 4211     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/8")
 4212     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-bytes/9")
 4213     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-bytes/10")
 4214     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-bytes/11")
 4215     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-bytes/12")
 4216     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-bytes/13")
 4217     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-bytes/14")
 4218     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-bytes/15")
 4219     # . epilogue
 4220     89/<- %esp 5/r32/ebp
 4221     5d/pop-to-ebp
 4222     c3/return
 4223 
 4224 test-convert-length-of-array-on-stack:
 4225     # . prologue
 4226     55/push-ebp
 4227     89/<- %ebp 4/r32/esp
 4228     # setup
 4229     (clear-stream _test-input-stream)
 4230     (clear-stream $_test-input-buffered-file->buffer)
 4231     (clear-stream _test-output-stream)
 4232     (clear-stream $_test-output-buffered-file->buffer)
 4233     #
 4234     (write _test-input-stream "fn foo {\n")
 4235     (write _test-input-stream "  var a: (array int 3)\n")
 4236     (write _test-input-stream "  var b/eax: int <- length a\n")
 4237     (write _test-input-stream "}\n")
 4238     # convert
 4239     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4240     (flush _test-output-buffered-file)
 4241 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4247     # check output
 4248     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-on-stack/0")
 4249     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-on-stack/1")
 4250     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-on-stack/2")
 4251     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-on-stack/3")
 4252     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-on-stack/4")
 4253     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-on-stack/5")
 4254     # define x
 4255     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-length-of-array-on-stack/6")
 4256     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-length-of-array-on-stack/7")
 4257     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-on-stack/8")
 4258     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0xfffffff0) 0x00000000/r32"  "F - test-convert-length-of-array-on-stack/9")
 4259     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array-on-stack/10")
 4260     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-on-stack/11")
 4261     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"  "F - test-convert-length-of-array-on-stack/12")
 4262     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-on-stack/13")
 4263     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-on-stack/14")
 4264     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-on-stack/15")
 4265     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-on-stack/16")
 4266     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-on-stack/17")
 4267     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-on-stack/18")
 4268     # . epilogue
 4269     89/<- %esp 5/r32/ebp
 4270     5d/pop-to-ebp
 4271     c3/return
 4272 
 4273 test-reg-var-def-with-read-of-same-register:
 4274     # . prologue
 4275     55/push-ebp
 4276     89/<- %ebp 4/r32/esp
 4277     # setup
 4278     (clear-stream _test-input-stream)
 4279     (clear-stream $_test-input-buffered-file->buffer)
 4280     (clear-stream _test-output-stream)
 4281     (clear-stream $_test-output-buffered-file->buffer)
 4282     (clear-stream _test-error-stream)
 4283     (clear-stream $_test-error-buffered-file->buffer)
 4284     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
 4285     68/push 0/imm32
 4286     68/push 0/imm32
 4287     89/<- %edx 4/r32/esp
 4288     (tailor-exit-descriptor %edx 0x10)
 4289     #
 4290     (write _test-input-stream "fn foo {\n")
 4291     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4292     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4293     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4294     (write _test-input-stream "}\n")
 4295     # convert
 4296     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4297     # registers except esp could be clobbered at this point (though they shouldn't be)
 4298     # restore ed
 4299     89/<- %edx 4/r32/esp
 4300     (flush _test-output-buffered-file)
 4301     (flush _test-error-buffered-file)
 4302 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4308     (check-stream-equal _test-error-stream  ""  "F - test-reg-var-def-with-read-of-same-register: error stream should be empty")
 4309     # check output
 4310     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-reg-var-def-with-read-of-same-register/0")
 4311     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-reg-var-def-with-read-of-same-register/1")
 4312     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-reg-var-def-with-read-of-same-register/2")
 4313     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-reg-var-def-with-read-of-same-register/3")
 4314     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-reg-var-def-with-read-of-same-register/4")
 4315     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-reg-var-def-with-read-of-same-register/5")
 4316     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-reg-var-def-with-read-of-same-register/6")
 4317     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-reg-var-def-with-read-of-same-register/7")
 4318     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-reg-var-def-with-read-of-same-register/8")
 4319     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-reg-var-def-with-read-of-same-register/9")
 4320     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32"  "F - test-reg-var-def-with-read-of-same-register/11")
 4321     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-reg-var-def-with-read-of-same-register/13")
 4322     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-reg-var-def-with-read-of-same-register/14")
 4323     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-reg-var-def-with-read-of-same-register/15")
 4324     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-reg-var-def-with-read-of-same-register/16")
 4325     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-reg-var-def-with-read-of-same-register/17")
 4326     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-reg-var-def-with-read-of-same-register/18")
 4327     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-reg-var-def-with-read-of-same-register/19")
 4328     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-reg-var-def-with-read-of-same-register/20")
 4329     # don't restore from ebp
 4330     81 0/subop/add %esp 8/imm32
 4331     # . epilogue
 4332     5d/pop-to-ebp
 4333     c3/return
 4334 
 4335 test-convert-index-into-array:
 4336     # . prologue
 4337     55/push-ebp
 4338     89/<- %ebp 4/r32/esp
 4339     # setup
 4340     (clear-stream _test-input-stream)
 4341     (clear-stream $_test-input-buffered-file->buffer)
 4342     (clear-stream _test-output-stream)
 4343     (clear-stream $_test-output-buffered-file->buffer)
 4344     #
 4345     (write _test-input-stream "fn foo {\n")
 4346     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4347     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4348     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4349     (write _test-input-stream "}\n")
 4350     # convert
 4351     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4352     (flush _test-output-buffered-file)
 4353 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4359     # check output
 4360     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array/0")
 4361     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array/1")
 4362     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array/2")
 4363     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array/3")
 4364     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array/4")
 4365     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array/5")
 4366     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array/6")
 4367     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array/7")
 4368     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array/8")
 4369     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array/9")
 4370     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32"  "F - test-convert-index-into-array/10")
 4371     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array/11")
 4372     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array/12")
 4373     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array/13")
 4374     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array/14")
 4375     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array/15")
 4376     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array/16")
 4377     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array/17")
 4378     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array/18")
 4379     # . epilogue
 4380     89/<- %esp 5/r32/ebp
 4381     5d/pop-to-ebp
 4382     c3/return
 4383 
 4384 test-convert-index-into-array-of-bytes:
 4385     # . prologue
 4386     55/push-ebp
 4387     89/<- %ebp 4/r32/esp
 4388     # setup
 4389     (clear-stream _test-input-stream)
 4390     (clear-stream $_test-input-buffered-file->buffer)
 4391     (clear-stream _test-output-stream)
 4392     (clear-stream $_test-output-buffered-file->buffer)
 4393     #
 4394     (write _test-input-stream "fn foo {\n")
 4395     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4396     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4397     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, idx\n")
 4398     (write _test-input-stream "}\n")
 4399     # convert
 4400     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4401     (flush _test-output-buffered-file)
 4402 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4408     # check output
 4409     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes/0")
 4410     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes/1")
 4411     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes/2")
 4412     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes/3")
 4413     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes/4")
 4414     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes/5")
 4415     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes/6")
 4416     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes/7")
 4417     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes/8")
 4418     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-of-bytes/9")
 4419     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000000 + 4) 0x00000000/r32"  "F - test-convert-index-into-array-of-bytes/11")
 4420     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes/13")
 4421     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes/14")
 4422     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes/15")
 4423     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes/16")
 4424     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes/17")
 4425     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes/18")
 4426     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes/19")
 4427     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes/20")
 4428     # . epilogue
 4429     89/<- %esp 5/r32/ebp
 4430     5d/pop-to-ebp
 4431     c3/return
 4432 
 4433 test-convert-index-into-array-with-literal:
 4434     # . prologue
 4435     55/push-ebp
 4436     89/<- %ebp 4/r32/esp
 4437     # setup
 4438     (clear-stream _test-input-stream)
 4439     (clear-stream $_test-input-buffered-file->buffer)
 4440     (clear-stream _test-output-stream)
 4441     (clear-stream $_test-output-buffered-file->buffer)
 4442     #
 4443     (write _test-input-stream "fn foo {\n")
 4444     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4445     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 4446     (write _test-input-stream "}\n")
 4447     # convert
 4448     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4449     (flush _test-output-buffered-file)
 4450 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4456     # check output
 4457     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-with-literal/0")
 4458     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-with-literal/1")
 4459     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-with-literal/2")
 4460     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-with-literal/3")
 4461     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-with-literal/4")
 4462     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-with-literal/5")
 4463     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-with-literal/6")
 4464     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-with-literal/7")
 4465                                                                                  # 2 * 4 bytes/elem + 4 bytes for size = offset 12
 4466     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x0000000c) 0x00000000/r32"  "F - test-convert-index-into-array-with-literal/8")
 4467     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-with-literal/9")
 4468     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-with-literal/10")
 4469     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-with-literal/11")
 4470     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-with-literal/12")
 4471     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-with-literal/13")
 4472     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-with-literal/14")
 4473     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-with-literal/15")
 4474     # . epilogue
 4475     89/<- %esp 5/r32/ebp
 4476     5d/pop-to-ebp
 4477     c3/return
 4478 
 4479 test-convert-index-into-array-of-bytes-with-literal:
 4480     # . prologue
 4481     55/push-ebp
 4482     89/<- %ebp 4/r32/esp
 4483     # setup
 4484     (clear-stream _test-input-stream)
 4485     (clear-stream $_test-input-buffered-file->buffer)
 4486     (clear-stream _test-output-stream)
 4487     (clear-stream $_test-output-buffered-file->buffer)
 4488     #
 4489     (write _test-input-stream "fn foo {\n")
 4490     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4491     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 4492     (write _test-input-stream "}\n")
 4493     # convert
 4494     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4495     (flush _test-output-buffered-file)
 4496 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4502     # check output
 4503     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-with-literal/0")
 4504     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-with-literal/1")
 4505     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-with-literal/2")
 4506     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-with-literal/3")
 4507     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-with-literal/4")
 4508     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-with-literal/5")
 4509     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-with-literal/6")
 4510     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes-with-literal/7")
 4511                                                                                  # 2 * 1 byte/elem + 4 bytes for size = offset 6
 4512     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000006) 0x00000000/r32"  "F - test-convert-index-into-array-of-bytes-with-literal/8")
 4513     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-with-literal/9")
 4514     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-with-literal/10")
 4515     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-with-literal/11")
 4516     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-with-literal/12")
 4517     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-with-literal/13")
 4518     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-with-literal/14")
 4519     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-with-literal/15")
 4520     # . epilogue
 4521     89/<- %esp 5/r32/ebp
 4522     5d/pop-to-ebp
 4523     c3/return
 4524 
 4525 test-convert-index-into-array-on-stack:
 4526     # . prologue
 4527     55/push-ebp
 4528     89/<- %ebp 4/r32/esp
 4529     # setup
 4530     (clear-stream _test-input-stream)
 4531     (clear-stream $_test-input-buffered-file->buffer)
 4532     (clear-stream _test-output-stream)
 4533     (clear-stream $_test-output-buffered-file->buffer)
 4534     #
 4535     (write _test-input-stream "fn foo {\n")
 4536     (write _test-input-stream "  var arr: (array int 3)\n")
 4537     (write _test-input-stream "  var idx/eax: int <- copy 2\n")
 4538     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4539     (write _test-input-stream "}\n")
 4540     # convert
 4541     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4542     (flush _test-output-buffered-file)
 4543 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4549     # check output
 4550     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack/0")
 4551     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack/1")
 4552     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack/2")
 4553     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack/3")
 4554     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack/4")
 4555     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack/5")
 4556     # var arr
 4557     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack/6")
 4558     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack/7")
 4559     # var idx
 4560     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack/8")
 4561     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 2/imm32"                  "F - test-convert-index-into-array-on-stack/9")
 4562     # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc
 4563     (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")
 4564     # reclaim idx
 4565     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack/11")
 4566     # reclaim arr
 4567     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"    "F - test-convert-index-into-array-on-stack/12")
 4568     #
 4569     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack/13")
 4570     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack/14")
 4571     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack/15")
 4572     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack/16")
 4573     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack/17")
 4574     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack/18")
 4575     # . epilogue
 4576     89/<- %esp 5/r32/ebp
 4577     5d/pop-to-ebp
 4578     c3/return
 4579 
 4580 test-convert-index-into-array-on-stack-with-literal:
 4581     # . prologue
 4582     55/push-ebp
 4583     89/<- %ebp 4/r32/esp
 4584     # setup
 4585     (clear-stream _test-input-stream)
 4586     (clear-stream $_test-input-buffered-file->buffer)
 4587     (clear-stream _test-output-stream)
 4588     (clear-stream $_test-output-buffered-file->buffer)
 4589     #
 4590     (write _test-input-stream "fn foo {\n")
 4591     (write _test-input-stream "  var arr: (array int 3)\n")
 4592     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 4593     (write _test-input-stream "}\n")
 4594     # convert
 4595     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4596     (flush _test-output-buffered-file)
 4597 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4603     # check output
 4604     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack-with-literal/0")
 4605     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack-with-literal/1")
 4606     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack-with-literal/2")
 4607     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack-with-literal/3")
 4608     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack-with-literal/4")
 4609     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack-with-literal/5")
 4610     # var arr
 4611     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack-with-literal/6")
 4612     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack-with-literal/7")
 4613     # var x
 4614     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack-with-literal/8")
 4615     # x is at (ebp-0x10) + 4 + 2*4 = ebp-4
 4616     (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")
 4617     # reclaim x
 4618     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack-with-literal/10")
 4619     # reclaim arr
 4620     (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")
 4621     #
 4622     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack-with-literal/12")
 4623     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack-with-literal/13")
 4624     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack-with-literal/14")
 4625     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack-with-literal/15")
 4626     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack-with-literal/16")
 4627     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack-with-literal/17")
 4628     # . epilogue
 4629     89/<- %esp 5/r32/ebp
 4630     5d/pop-to-ebp
 4631     c3/return
 4632 
 4633 test-convert-index-into-array-of-bytes-on-stack-with-literal:
 4634     # . prologue
 4635     55/push-ebp
 4636     89/<- %ebp 4/r32/esp
 4637     # setup
 4638     (clear-stream _test-input-stream)
 4639     (clear-stream $_test-input-buffered-file->buffer)
 4640     (clear-stream _test-output-stream)
 4641     (clear-stream $_test-output-buffered-file->buffer)
 4642     #
 4643     (write _test-input-stream "fn foo {\n")
 4644     (write _test-input-stream "  var arr: (array byte 3)\n")
 4645     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 4646     (write _test-input-stream "}\n")
 4647     # convert
 4648     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4649     (flush _test-output-buffered-file)
 4650 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4656     # check output
 4657     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/0")
 4658     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/1")
 4659     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/2")
 4660     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/3")
 4661     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/4")
 4662     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/5")
 4663     # var arr
 4664     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x00000003)"          "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/6")
 4665     (check-next-stream-line-equal _test-output-stream "    68/push 0x00000003/imm32"                "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/7")
 4666     # var x
 4667     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/8")
 4668     # x is at (ebp-7) + 4 + 2 = ebp-1
 4669     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp + 0xffffffff) 0x00000000/r32"  "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/9")
 4670     # reclaim x
 4671     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/10")
 4672     # reclaim arr
 4673     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000007/imm32"    "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/11")
 4674     #
 4675     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/12")
 4676     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/13")
 4677     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/14")
 4678     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/15")
 4679     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/16")
 4680     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/17")
 4681     # . epilogue
 4682     89/<- %esp 5/r32/ebp
 4683     5d/pop-to-ebp
 4684     c3/return
 4685 
 4686 test-convert-index-into-array-using-offset:
 4687     # . prologue
 4688     55/push-ebp
 4689     89/<- %ebp 4/r32/esp
 4690     # setup
 4691     (clear-stream _test-input-stream)
 4692     (clear-stream $_test-input-buffered-file->buffer)
 4693     (clear-stream _test-output-stream)
 4694     (clear-stream $_test-output-buffered-file->buffer)
 4695     #
 4696     (write _test-input-stream "fn foo {\n")
 4697     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4698     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4699     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 4700     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 4701     (write _test-input-stream "}\n")
 4702     # convert
 4703     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4704     (flush _test-output-buffered-file)
 4705 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4711     # check output
 4712     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset/0")
 4713     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset/1")
 4714     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset/2")
 4715     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset/3")
 4716     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset/4")
 4717     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset/5")
 4718     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset/6")
 4719     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-using-offset/7")
 4720     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset/8")
 4721     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-using-offset/9")
 4722     (check-next-stream-line-equal _test-output-stream "    69/multiply %ecx 0x00000004/imm32 0x00000001/r32"  "F - test-convert-index-into-array-using-offset/10")
 4723     (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")
 4724     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset/12")
 4725     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset/13")
 4726     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset/14")
 4727     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset/15")
 4728     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset/16")
 4729     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset/17")
 4730     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset/18")
 4731     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset/19")
 4732     # . epilogue
 4733     89/<- %esp 5/r32/ebp
 4734     5d/pop-to-ebp
 4735     c3/return
 4736 
 4737 test-convert-index-into-array-of-bytes-using-offset:
 4738     # . prologue
 4739     55/push-ebp
 4740     89/<- %ebp 4/r32/esp
 4741     # setup
 4742     (clear-stream _test-input-stream)
 4743     (clear-stream $_test-input-buffered-file->buffer)
 4744     (clear-stream _test-output-stream)
 4745     (clear-stream $_test-output-buffered-file->buffer)
 4746     #
 4747     (write _test-input-stream "fn foo {\n")
 4748     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4749     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4750     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 4751     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
 4752     (write _test-input-stream "}\n")
 4753     # convert
 4754     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4755     (flush _test-output-buffered-file)
 4756 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4762     # check output
 4763     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset/0")
 4764     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset/1")
 4765     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset/2")
 4766     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-using-offset/3")
 4767     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset/4")
 4768     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset/5")
 4769     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-using-offset/6")
 4770     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes-using-offset/7")
 4771     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes-using-offset/8")
 4772     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-of-bytes-using-offset/9")
 4773     (check-next-stream-line-equal _test-output-stream "    69/multiply %ecx 0x00000001/imm32 0x00000001/r32"  "F - test-convert-index-into-array-of-bytes-using-offset/10")
 4774     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx + 4) 0x00000000/r32"  "F - test-convert-index-into-array-of-bytes-using-offset/11")
 4775     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes-using-offset/12")
 4776     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-using-offset/13")
 4777     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset/14")
 4778     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset/15")
 4779     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset/16")
 4780     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-using-offset/17")
 4781     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-using-offset/18")
 4782     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset/19")
 4783     # . epilogue
 4784     89/<- %esp 5/r32/ebp
 4785     5d/pop-to-ebp
 4786     c3/return
 4787 
 4788 test-convert-index-into-array-using-offset-on-stack:
 4789     # . prologue
 4790     55/push-ebp
 4791     89/<- %ebp 4/r32/esp
 4792     # setup
 4793     (clear-stream _test-input-stream)
 4794     (clear-stream $_test-input-buffered-file->buffer)
 4795     (clear-stream _test-output-stream)
 4796     (clear-stream $_test-output-buffered-file->buffer)
 4797     #
 4798     (write _test-input-stream "fn foo {\n")
 4799     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4800     (write _test-input-stream "  var idx: int\n")
 4801     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 4802     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 4803     (write _test-input-stream "}\n")
 4804     # convert
 4805     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4806     (flush _test-output-buffered-file)
 4807 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4813     # check output
 4814     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset-on-stack/0")
 4815     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset-on-stack/1")
 4816     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset-on-stack/2")
 4817     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset-on-stack/3")
 4818     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset-on-stack/4")
 4819     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset-on-stack/5")
 4820     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset-on-stack/6")
 4821     (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")
 4822     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                         "F - test-convert-index-into-array-using-offset-on-stack/8")
 4823     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset-on-stack/9")
 4824     (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")
 4825     (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")
 4826     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset-on-stack/12")
 4827     (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")
 4828     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset-on-stack/14")
 4829     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset-on-stack/15")
 4830     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset-on-stack/16")
 4831     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset-on-stack/17")
 4832     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset-on-stack/18")
 4833     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset-on-stack/19")
 4834     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset-on-stack/20")
 4835     # . epilogue
 4836     89/<- %esp 5/r32/ebp
 4837     5d/pop-to-ebp
 4838     c3/return
 4839 
 4840 test-convert-index-into-array-of-bytes-using-offset-on-stack:
 4841     # . prologue
 4842     55/push-ebp
 4843     89/<- %ebp 4/r32/esp
 4844     # setup
 4845     (clear-stream _test-input-stream)
 4846     (clear-stream $_test-input-buffered-file->buffer)
 4847     (clear-stream _test-output-stream)
 4848     (clear-stream $_test-output-buffered-file->buffer)
 4849     #
 4850     (write _test-input-stream "fn foo {\n")
 4851     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4852     (write _test-input-stream "  var idx: int\n")
 4853     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 4854     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
 4855     (write _test-input-stream "}\n")
 4856     # convert
 4857     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4858     (flush _test-output-buffered-file)
 4859 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4865     # check output
 4866     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/0")
 4867     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/1")
 4868     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/2")
 4869     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/3")
 4870     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/4")
 4871     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/5")
 4872     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/6")
 4873     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/7")
 4874     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/8")
 4875     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/9")
 4876     (check-next-stream-line-equal _test-output-stream "    69/multiply *(ebp+0xfffffff8) 0x00000001/imm32 0x00000001/r32"  "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/10")
 4877     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx + 4) 0x00000000/r32"  "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/11")
 4878     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/12")
 4879     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"    "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/13")
 4880     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/14")
 4881     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/15")
 4882     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/16")
 4883     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/17")
 4884     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/18")
 4885     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/19")
 4886     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/20")
 4887     # . epilogue
 4888     89/<- %esp 5/r32/ebp
 4889     5d/pop-to-ebp
 4890     c3/return
 4891 
 4892 test-convert-function-and-type-definition:
 4893     # . prologue
 4894     55/push-ebp
 4895     89/<- %ebp 4/r32/esp
 4896     # setup
 4897     (clear-stream _test-input-stream)
 4898     (clear-stream $_test-input-buffered-file->buffer)
 4899     (clear-stream _test-output-stream)
 4900     (clear-stream $_test-output-buffered-file->buffer)
 4901     #
 4902     (write _test-input-stream "fn foo a: (addr t) {\n")
 4903     (write _test-input-stream "  var _a/eax: (addr t) <- copy a\n")
 4904     (write _test-input-stream "  var b/ecx: (addr int) <- get _a, x\n")
 4905     (write _test-input-stream "  var c/ecx: (addr int) <- get _a, y\n")
 4906     (write _test-input-stream "}\n")
 4907     (write _test-input-stream "type t {\n")
 4908     (write _test-input-stream "  x: int\n")
 4909     (write _test-input-stream "  y: int\n")
 4910     (write _test-input-stream "}\n")
 4911     # convert
 4912     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4913     (flush _test-output-buffered-file)
 4914 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4920     # check output
 4921     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-and-type-definition/0")
 4922     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-and-type-definition/1")
 4923     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-and-type-definition/2")
 4924     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-and-type-definition/3")
 4925     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-and-type-definition/4")
 4926     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-and-type-definition/5")
 4927     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-and-type-definition/6")
 4928     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-and-type-definition/7")
 4929     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-and-type-definition/8")
 4930     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000000) 0x00000001/r32"  "F - test-convert-function-and-type-definition/9")
 4931     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000004) 0x00000001/r32"  "F - test-convert-function-and-type-definition/11")
 4932     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-and-type-definition/13")
 4933     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-and-type-definition/14")
 4934     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-and-type-definition/15")
 4935     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-and-type-definition/16")
 4936     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-and-type-definition/17")
 4937     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-and-type-definition/18")
 4938     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-and-type-definition/19")
 4939     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-and-type-definition/20")
 4940     # . epilogue
 4941     89/<- %esp 5/r32/ebp
 4942     5d/pop-to-ebp
 4943     c3/return
 4944 
 4945 test-type-definition-with-array:
 4946     # . prologue
 4947     55/push-ebp
 4948     89/<- %ebp 4/r32/esp
 4949     # setup
 4950     (clear-stream _test-input-stream)
 4951     (clear-stream $_test-input-buffered-file->buffer)
 4952     (clear-stream _test-output-stream)
 4953     (clear-stream $_test-output-buffered-file->buffer)
 4954     (clear-stream _test-error-stream)
 4955     (clear-stream $_test-error-buffered-file->buffer)
 4956     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 4957     68/push 0/imm32
 4958     68/push 0/imm32
 4959     89/<- %edx 4/r32/esp
 4960     (tailor-exit-descriptor %edx 0x10)
 4961     #
 4962     (write _test-input-stream "type t {\n")
 4963     (write _test-input-stream "  a: (array int 3)\n")
 4964     (write _test-input-stream "}\n")
 4965     # convert
 4966     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4967     # registers except esp clobbered at this point
 4968     # restore ed
 4969     89/<- %edx 4/r32/esp
 4970     (flush _test-output-buffered-file)
 4971     (flush _test-error-buffered-file)
 4972 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 4978     # check output
 4979     (check-stream-equal _test-output-stream  ""  "F - test-type-definition-with-array: output should be empty")
 4980     (check-next-stream-line-equal _test-error-stream  "type t: 'array' elements not allowed for now"  "F - test-type-definition-with-array: error message")
 4981     # check that stop(1) was called
 4982     (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-array: exit status")
 4983     # don't restore from ebp
 4984     81 0/subop/add %esp 8/imm32
 4985     # . epilogue
 4986     5d/pop-to-ebp
 4987     c3/return
 4988 
 4989 test-type-definition-with-addr:
 4990     # . prologue
 4991     55/push-ebp
 4992     89/<- %ebp 4/r32/esp
 4993     # setup
 4994     (clear-stream _test-input-stream)
 4995     (clear-stream $_test-input-buffered-file->buffer)
 4996     (clear-stream _test-output-stream)
 4997     (clear-stream $_test-output-buffered-file->buffer)
 4998     (clear-stream _test-error-stream)
 4999     (clear-stream $_test-error-buffered-file->buffer)
 5000     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5001     68/push 0/imm32
 5002     68/push 0/imm32
 5003     89/<- %edx 4/r32/esp
 5004     (tailor-exit-descriptor %edx 0x10)
 5005     #
 5006     (write _test-input-stream "type t {\n")
 5007     (write _test-input-stream "  a: (addr int)\n")
 5008     (write _test-input-stream "}\n")
 5009     # convert
 5010     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5011     # registers except esp clobbered at this point
 5012     # restore ed
 5013     89/<- %edx 4/r32/esp
 5014     (flush _test-output-buffered-file)
 5015     (flush _test-error-buffered-file)
 5016 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5022     # check output
 5023     (check-stream-equal _test-output-stream  ""  "F - test-type-definition-with-addr: output should be empty")
 5024     (check-next-stream-line-equal _test-error-stream  "type t: 'addr' elements not allowed"  "F - test-type-definition-with-addr: error message")
 5025     # check that stop(1) was called
 5026     (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-addr: exit status")
 5027     # don't restore from ebp
 5028     81 0/subop/add %esp 8/imm32
 5029     # . epilogue
 5030     5d/pop-to-ebp
 5031     c3/return
 5032 
 5033 test-convert-function-with-local-var-with-user-defined-type:
 5034     # . prologue
 5035     55/push-ebp
 5036     89/<- %ebp 4/r32/esp
 5037     # setup
 5038     (clear-stream _test-input-stream)
 5039     (clear-stream $_test-input-buffered-file->buffer)
 5040     (clear-stream _test-output-stream)
 5041     (clear-stream $_test-output-buffered-file->buffer)
 5042     #
 5043     (write _test-input-stream "fn foo {\n")
 5044     (write _test-input-stream "  var a: t\n")
 5045     (write _test-input-stream "}\n")
 5046     (write _test-input-stream "type t {\n")
 5047     (write _test-input-stream "  x: int\n")
 5048     (write _test-input-stream "  y: int\n")
 5049     (write _test-input-stream "}\n")
 5050     # convert
 5051     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5052     (flush _test-output-buffered-file)
 5053 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5059     # check output
 5060     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-user-defined-type/0")
 5061     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-user-defined-type/1")
 5062     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-user-defined-type/2")
 5063     (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")
 5064     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type/4")
 5065     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-user-defined-type/5")
 5066     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/6")
 5067     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/7")
 5068     (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")
 5069     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type/9")
 5070     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-user-defined-type/10")
 5071     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-user-defined-type/11")
 5072     (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")
 5073     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-user-defined-type/13")
 5074     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-user-defined-type/14")
 5075     # . epilogue
 5076     89/<- %esp 5/r32/ebp
 5077     5d/pop-to-ebp
 5078     c3/return
 5079 
 5080 test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type:
 5081     # . prologue
 5082     55/push-ebp
 5083     89/<- %ebp 4/r32/esp
 5084     # setup
 5085     (clear-stream _test-input-stream)
 5086     (clear-stream $_test-input-buffered-file->buffer)
 5087     (clear-stream _test-output-stream)
 5088     (clear-stream $_test-output-buffered-file->buffer)
 5089     #
 5090     (write _test-input-stream "fn foo {\n")
 5091     (write _test-input-stream "  var a: t\n")
 5092     (write _test-input-stream "}\n")
 5093     (write _test-input-stream "type t {\n")
 5094     (write _test-input-stream "  x: s\n")
 5095     (write _test-input-stream "}\n")
 5096     (write _test-input-stream "type s {\n")
 5097     (write _test-input-stream "  z: int\n")
 5098     (write _test-input-stream "}\n")
 5099     # convert
 5100     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5101     (flush _test-output-buffered-file)
 5102 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5108     # check output
 5109     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/0")
 5110     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/1")
 5111     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/2")
 5112     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/3")
 5113     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/4")
 5114     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/5")
 5115     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/7")
 5116     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/8")
 5117     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/9")
 5118     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/10")
 5119     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/11")
 5120     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/12")
 5121     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/13")
 5122     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/14")
 5123     # . epilogue
 5124     89/<- %esp 5/r32/ebp
 5125     5d/pop-to-ebp
 5126     c3/return
 5127 
 5128 test-convert-function-call-with-arg-of-user-defined-type:
 5129     # . prologue
 5130     55/push-ebp
 5131     89/<- %ebp 4/r32/esp
 5132     # setup
 5133     (clear-stream _test-input-stream)
 5134     (clear-stream $_test-input-buffered-file->buffer)
 5135     (clear-stream _test-output-stream)
 5136     (clear-stream $_test-output-buffered-file->buffer)
 5137     #
 5138     (write _test-input-stream "fn f {\n")
 5139     (write _test-input-stream "  var a: t\n")
 5140     (write _test-input-stream "  foo a\n")
 5141     (write _test-input-stream "}\n")
 5142     (write _test-input-stream "fn foo x: t {\n")
 5143     (write _test-input-stream "}\n")
 5144     (write _test-input-stream "type t {\n")
 5145     (write _test-input-stream "  x: int\n")
 5146     (write _test-input-stream "  y: int\n")
 5147     (write _test-input-stream "}\n")
 5148     # convert
 5149     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5150     (flush _test-output-buffered-file)
 5151 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5157     # check output
 5158     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 5159     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 5160     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 5161     (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")
 5162     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 5163     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 5164     # var a: t
 5165     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/6")
 5166     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/7")
 5167     # foo a
 5168     (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")
 5169     #
 5170     (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")
 5171     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 5172     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 5173     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 5174     (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")
 5175     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 5176     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 5177     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 5178     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 5179     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 5180     (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")
 5181     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 5182     (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")
 5183     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 5184     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 5185     # . epilogue
 5186     89/<- %esp 5/r32/ebp
 5187     5d/pop-to-ebp
 5188     c3/return
 5189 
 5190 test-convert-function-call-with-arg-of-user-defined-type-register-indirect:
 5191     # . prologue
 5192     55/push-ebp
 5193     89/<- %ebp 4/r32/esp
 5194     # setup
 5195     (clear-stream _test-input-stream)
 5196     (clear-stream $_test-input-buffered-file->buffer)
 5197     (clear-stream _test-output-stream)
 5198     (clear-stream $_test-output-buffered-file->buffer)
 5199     #
 5200     (write _test-input-stream "fn f {\n")
 5201     (write _test-input-stream "  var a/eax: (addr t) <- copy 0\n")
 5202     (write _test-input-stream "  foo *a\n")
 5203     (write _test-input-stream "}\n")
 5204     (write _test-input-stream "fn foo x: t {\n")
 5205     (write _test-input-stream "}\n")
 5206     (write _test-input-stream "type t {\n")
 5207     (write _test-input-stream "  x: int\n")
 5208     (write _test-input-stream "  y: int\n")
 5209     (write _test-input-stream "}\n")
 5210     # convert
 5211     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5212     (flush _test-output-buffered-file)
 5213 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5219     # check output
 5220     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 5221     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 5222     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 5223     (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")
 5224     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 5225     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 5226     # var a
 5227     (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")
 5228     (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")
 5229     # foo a
 5230     (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")
 5231     #
 5232     (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")
 5233     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 5234     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 5235     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 5236     (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")
 5237     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 5238     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 5239     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 5240     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 5241     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 5242     (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")
 5243     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 5244     (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")
 5245     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 5246     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 5247     # . epilogue
 5248     89/<- %esp 5/r32/ebp
 5249     5d/pop-to-ebp
 5250     c3/return
 5251 
 5252 # we don't have special support for call-by-reference; just explicitly create
 5253 # a new variable with the address of the arg
 5254 test-convert-function-call-with-arg-of-user-defined-type-by-reference:
 5255     # . prologue
 5256     55/push-ebp
 5257     89/<- %ebp 4/r32/esp
 5258     # setup
 5259     (clear-stream _test-input-stream)
 5260     (clear-stream $_test-input-buffered-file->buffer)
 5261     (clear-stream _test-output-stream)
 5262     (clear-stream $_test-output-buffered-file->buffer)
 5263     #
 5264     (write _test-input-stream "fn f {\n")
 5265     (write _test-input-stream "  var a: t\n")
 5266     (write _test-input-stream "  var b/eax: (addr t) <- address a\n")
 5267     (write _test-input-stream "  foo b\n")
 5268     (write _test-input-stream "}\n")
 5269     (write _test-input-stream "fn foo x: (addr t) {\n")
 5270     (write _test-input-stream "  var x/ecx: (addr int) <- copy x\n")
 5271     (write _test-input-stream "  increment *x\n")
 5272     (write _test-input-stream "}\n")
 5273     (write _test-input-stream "type t {\n")
 5274     (write _test-input-stream "  x: int\n")
 5275     (write _test-input-stream "  y: int\n")
 5276     (write _test-input-stream "}\n")
 5277     # convert
 5278     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5279     (flush _test-output-buffered-file)
 5280 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5286     # check output
 5287     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/0")
 5288     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/1")
 5289     (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")
 5290     (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")
 5291     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/4")
 5292     (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")
 5293     # var a: t
 5294     (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")
 5295     (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")
 5296     # var b/eax: (addr t)
 5297     (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")
 5298     (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")
 5299     # foo a
 5300     (check-next-stream-line-equal _test-output-stream "    (foo %eax)"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/10")
 5301     #
 5302     (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")
 5303     (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")
 5304     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/13")
 5305     (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")
 5306     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/15")
 5307     (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")
 5308     (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")
 5309     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/18")
 5310     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/19")
 5311     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/20")
 5312     (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")
 5313     (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")
 5314     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/23")
 5315     (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")
 5316     (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")
 5317     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000001/r32"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/26")
 5318     (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")
 5319     (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")
 5320     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/29")
 5321     (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")
 5322     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/31")
 5323     (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")
 5324     (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")
 5325     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/34")
 5326     # . epilogue
 5327     89/<- %esp 5/r32/ebp
 5328     5d/pop-to-ebp
 5329     c3/return
 5330 
 5331 test-convert-get-on-local-variable:
 5332     # . prologue
 5333     55/push-ebp
 5334     89/<- %ebp 4/r32/esp
 5335     # setup
 5336     (clear-stream _test-input-stream)
 5337     (clear-stream $_test-input-buffered-file->buffer)
 5338     (clear-stream _test-output-stream)
 5339     (clear-stream $_test-output-buffered-file->buffer)
 5340     #
 5341     (write _test-input-stream "fn foo {\n")
 5342     (write _test-input-stream "  var a: t\n")
 5343     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5344     (write _test-input-stream "}\n")
 5345     (write _test-input-stream "type t {\n")
 5346     (write _test-input-stream "  x: int\n")
 5347     (write _test-input-stream "  y: int\n")
 5348     (write _test-input-stream "}\n")
 5349     # convert
 5350     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5351     (flush _test-output-buffered-file)
 5352 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5358     # check output
 5359     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-local-variable/0")
 5360     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-local-variable/1")
 5361     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-local-variable/2")
 5362     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-local-variable/3")
 5363     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-local-variable/4")
 5364     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-local-variable/5")
 5365     # var a
 5366     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/6")
 5367     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/7")
 5368     # var c
 5369     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-local-variable/8")
 5370     # get
 5371     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32"  "F - test-convert-get-on-local-variable/9")
 5372     # reclaim c
 5373     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-local-variable/10")
 5374     # reclaim a
 5375     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-get-on-local-variable/11")
 5376     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-local-variable/12")
 5377     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-local-variable/13")
 5378     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-local-variable/14")
 5379     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-local-variable/15")
 5380     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-local-variable/16")
 5381     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-local-variable/17")
 5382     # . epilogue
 5383     89/<- %esp 5/r32/ebp
 5384     5d/pop-to-ebp
 5385     c3/return
 5386 
 5387 test-convert-get-on-function-argument:
 5388     # . prologue
 5389     55/push-ebp
 5390     89/<- %ebp 4/r32/esp
 5391     # setup
 5392     (clear-stream _test-input-stream)
 5393     (clear-stream $_test-input-buffered-file->buffer)
 5394     (clear-stream _test-output-stream)
 5395     (clear-stream $_test-output-buffered-file->buffer)
 5396     #
 5397     (write _test-input-stream "fn foo a: t {\n")
 5398     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5399     (write _test-input-stream "}\n")
 5400     (write _test-input-stream "type t {\n")
 5401     (write _test-input-stream "  x: int\n")
 5402     (write _test-input-stream "  y: int\n")
 5403     (write _test-input-stream "}\n")
 5404     # convert
 5405     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5406     (flush _test-output-buffered-file)
 5407 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5413     # check output
 5414     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument/0")
 5415     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument/1")
 5416     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument/2")
 5417     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument/3")
 5418     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument/4")
 5419     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument/5")
 5420     # var c
 5421     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument/6")
 5422     # get
 5423     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0x0000000c) 0x00000001/r32"  "F - test-convert-get-on-function-argument/7")
 5424     # reclaim c
 5425     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument/8")
 5426     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument/9")
 5427     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument/10")
 5428     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument/11")
 5429     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument/12")
 5430     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument/13")
 5431     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument/14")
 5432     # . epilogue
 5433     89/<- %esp 5/r32/ebp
 5434     5d/pop-to-ebp
 5435     c3/return
 5436 
 5437 test-convert-get-on-function-argument-with-known-type:
 5438     # . prologue
 5439     55/push-ebp
 5440     89/<- %ebp 4/r32/esp
 5441     # setup
 5442     (clear-stream _test-input-stream)
 5443     (clear-stream $_test-input-buffered-file->buffer)
 5444     (clear-stream _test-output-stream)
 5445     (clear-stream $_test-output-buffered-file->buffer)
 5446     #
 5447     (write _test-input-stream "type t {\n")
 5448     (write _test-input-stream "  x: int\n")
 5449     (write _test-input-stream "  y: int\n")
 5450     (write _test-input-stream "}\n")
 5451     (write _test-input-stream "fn foo a: t {\n")
 5452     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5453     (write _test-input-stream "}\n")
 5454     # convert
 5455     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5456     (flush _test-output-buffered-file)
 5457 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5463     # check output
 5464     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument-with-known-type/0")
 5465     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument-with-known-type/1")
 5466     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument-with-known-type/2")
 5467     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument-with-known-type/3")
 5468     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument-with-known-type/4")
 5469     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument-with-known-type/5")
 5470     # var c
 5471     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument-with-known-type/6")
 5472     # get
 5473     (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")
 5474     # reclaim c
 5475     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument-with-known-type/8")
 5476     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument-with-known-type/9")
 5477     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument-with-known-type/10")
 5478     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument-with-known-type/11")
 5479     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument-with-known-type/12")
 5480     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument-with-known-type/13")
 5481     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument-with-known-type/14")
 5482     # . epilogue
 5483     89/<- %esp 5/r32/ebp
 5484     5d/pop-to-ebp
 5485     c3/return
 5486 
 5487 test-add-with-too-many-inouts:
 5488     # . prologue
 5489     55/push-ebp
 5490     89/<- %ebp 4/r32/esp
 5491     # setup
 5492     (clear-stream _test-input-stream)
 5493     (clear-stream $_test-input-buffered-file->buffer)
 5494     (clear-stream _test-output-stream)
 5495     (clear-stream $_test-output-buffered-file->buffer)
 5496     (clear-stream _test-error-stream)
 5497     (clear-stream $_test-error-buffered-file->buffer)
 5498     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5499     68/push 0/imm32
 5500     68/push 0/imm32
 5501     89/<- %edx 4/r32/esp
 5502     (tailor-exit-descriptor %edx 0x10)
 5503     #
 5504     (write _test-input-stream "fn foo {\n")
 5505     (write _test-input-stream "  var a: int\n")
 5506     (write _test-input-stream "  var b/ecx: int <- add a, 0\n")
 5507     (write _test-input-stream "}\n")
 5508     # convert
 5509     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5510     # registers except esp clobbered at this point
 5511     # restore ed
 5512     89/<- %edx 4/r32/esp
 5513     (flush _test-output-buffered-file)
 5514     (flush _test-error-buffered-file)
 5515 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5521     # check output
 5522     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts: output should be empty")
 5523     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt add: too many inouts; most primitives support at most two arguments, across inouts and outputs"  "F - test-add-with-too-many-inouts: error message")
 5524     # check that stop(1) was called
 5525     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts: exit status")
 5526     # don't restore from ebp
 5527     81 0/subop/add %esp 8/imm32
 5528     # . epilogue
 5529     5d/pop-to-ebp
 5530     c3/return
 5531 
 5532 test-add-with-too-many-inouts-2:
 5533     # . prologue
 5534     55/push-ebp
 5535     89/<- %ebp 4/r32/esp
 5536     # setup
 5537     (clear-stream _test-input-stream)
 5538     (clear-stream $_test-input-buffered-file->buffer)
 5539     (clear-stream _test-output-stream)
 5540     (clear-stream $_test-output-buffered-file->buffer)
 5541     (clear-stream _test-error-stream)
 5542     (clear-stream $_test-error-buffered-file->buffer)
 5543     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5544     68/push 0/imm32
 5545     68/push 0/imm32
 5546     89/<- %edx 4/r32/esp
 5547     (tailor-exit-descriptor %edx 0x10)
 5548     #
 5549     (write _test-input-stream "fn foo {\n")
 5550     (write _test-input-stream "  var a: int\n")
 5551     (write _test-input-stream "  add-to a, 0, 1\n")
 5552     (write _test-input-stream "}\n")
 5553     # convert
 5554     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5555     # registers except esp clobbered at this point
 5556     # restore ed
 5557     89/<- %edx 4/r32/esp
 5558     (flush _test-output-buffered-file)
 5559     (flush _test-error-buffered-file)
 5560 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5566     # check output
 5567     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts-2: output should be empty")
 5568     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt add-to: too many inouts; most primitives support at most two arguments, across inouts and outputs"  "F - test-add-with-too-many-inouts-2: error message")
 5569     # check that stop(1) was called
 5570     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts-2: exit status")
 5571     # don't restore from ebp
 5572     81 0/subop/add %esp 8/imm32
 5573     # . epilogue
 5574     5d/pop-to-ebp
 5575     c3/return
 5576 
 5577 test-add-with-too-many-outputs:
 5578     # . prologue
 5579     55/push-ebp
 5580     89/<- %ebp 4/r32/esp
 5581     # setup
 5582     (clear-stream _test-input-stream)
 5583     (clear-stream $_test-input-buffered-file->buffer)
 5584     (clear-stream _test-output-stream)
 5585     (clear-stream $_test-output-buffered-file->buffer)
 5586     (clear-stream _test-error-stream)
 5587     (clear-stream $_test-error-buffered-file->buffer)
 5588     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5589     68/push 0/imm32
 5590     68/push 0/imm32
 5591     89/<- %edx 4/r32/esp
 5592     (tailor-exit-descriptor %edx 0x10)
 5593     #
 5594     (write _test-input-stream "fn foo {\n")
 5595     (write _test-input-stream "  var a/eax: int <- copy 0\n")
 5596     (write _test-input-stream "  var b/ebx: int <- copy 0\n")
 5597     (write _test-input-stream "  var c/ecx: int <- copy 0\n")
 5598     (write _test-input-stream "  c, b <- add a\n")
 5599     (write _test-input-stream "}\n")
 5600     # convert
 5601     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5602     # registers except esp clobbered at this point
 5603     # restore ed
 5604     89/<- %edx 4/r32/esp
 5605     (flush _test-output-buffered-file)
 5606     (flush _test-error-buffered-file)
 5607 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5613     # check output
 5614     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-outputs: output should be empty")
 5615     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt add: too many outputs; most primitives support at most one output"  "F - test-add-with-too-many-outputs: error message")
 5616     # check that stop(1) was called
 5617     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-outputs: exit status")
 5618     # don't restore from ebp
 5619     81 0/subop/add %esp 8/imm32
 5620     # . epilogue
 5621     5d/pop-to-ebp
 5622     c3/return
 5623 
 5624 test-add-with-non-number:
 5625     # . prologue
 5626     55/push-ebp
 5627     89/<- %ebp 4/r32/esp
 5628     # setup
 5629     (clear-stream _test-input-stream)
 5630     (clear-stream $_test-input-buffered-file->buffer)
 5631     (clear-stream _test-output-stream)
 5632     (clear-stream $_test-output-buffered-file->buffer)
 5633     (clear-stream _test-error-stream)
 5634     (clear-stream $_test-error-buffered-file->buffer)
 5635     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5636     68/push 0/imm32
 5637     68/push 0/imm32
 5638     89/<- %edx 4/r32/esp
 5639     (tailor-exit-descriptor %edx 0x10)
 5640     #
 5641     (write _test-input-stream "fn foo {\n")
 5642     (write _test-input-stream "  var a: int\n")
 5643     (write _test-input-stream "  var b/ecx: (addr int) <- add a\n")
 5644     (write _test-input-stream "}\n")
 5645     # convert
 5646     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5647     # registers except esp clobbered at this point
 5648     # restore ed
 5649     89/<- %edx 4/r32/esp
 5650     (flush _test-output-buffered-file)
 5651     (flush _test-error-buffered-file)
 5652 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5658     # check output
 5659     (check-stream-equal _test-output-stream  ""  "F - test-add-with-non-number: output should be empty")
 5660     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt add: only non-addr scalar args permitted"  "F - test-add-with-non-number: error message")
 5661     # check that stop(1) was called
 5662     (check-ints-equal *(edx+4) 2 "F - test-add-with-non-number: exit status")
 5663     # don't restore from ebp
 5664     81 0/subop/add %esp 8/imm32
 5665     # . epilogue
 5666     5d/pop-to-ebp
 5667     c3/return
 5668 
 5669 test-add-with-addr-dereferenced:
 5670     # . prologue
 5671     55/push-ebp
 5672     89/<- %ebp 4/r32/esp
 5673     # setup
 5674     (clear-stream _test-input-stream)
 5675     (clear-stream $_test-input-buffered-file->buffer)
 5676     (clear-stream _test-output-stream)
 5677     (clear-stream $_test-output-buffered-file->buffer)
 5678     #
 5679     (write _test-input-stream "fn foo {\n")
 5680     (write _test-input-stream "  var a/eax: (addr int) <- copy 0\n")
 5681     (write _test-input-stream "  add-to *a, 1\n")
 5682     (write _test-input-stream "}\n")
 5683     # convert
 5684     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5685     (flush _test-output-buffered-file)
 5686     # no error
 5687     # . epilogue
 5688     89/<- %esp 5/r32/ebp
 5689     5d/pop-to-ebp
 5690     c3/return
 5691 
 5692 test-get-with-wrong-field:
 5693     # . prologue
 5694     55/push-ebp
 5695     89/<- %ebp 4/r32/esp
 5696     # setup
 5697     (clear-stream _test-input-stream)
 5698     (clear-stream $_test-input-buffered-file->buffer)
 5699     (clear-stream _test-output-stream)
 5700     (clear-stream $_test-output-buffered-file->buffer)
 5701     (clear-stream _test-error-stream)
 5702     (clear-stream $_test-error-buffered-file->buffer)
 5703     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5704     68/push 0/imm32
 5705     68/push 0/imm32
 5706     89/<- %edx 4/r32/esp
 5707     (tailor-exit-descriptor %edx 0x10)
 5708     #
 5709     (write _test-input-stream "fn foo {\n")
 5710     (write _test-input-stream "  var a: t\n")
 5711     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5712     (write _test-input-stream "}\n")
 5713     (write _test-input-stream "type t {\n")
 5714     (write _test-input-stream "  x: int\n")
 5715     (write _test-input-stream "}\n")
 5716     # convert
 5717     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5718     # registers except esp clobbered at this point
 5719     # restore ed
 5720     89/<- %edx 4/r32/esp
 5721     (flush _test-output-buffered-file)
 5722     (flush _test-error-buffered-file)
 5723 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5729     # check output
 5730     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-field: output should be empty")
 5731     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: type 't' has no member called 'y'"  "F - test-get-with-wrong-field: error message")
 5732     # check that stop(1) was called
 5733     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-field: exit status")
 5734     # don't restore from ebp
 5735     81 0/subop/add %esp 8/imm32
 5736     # . epilogue
 5737     5d/pop-to-ebp
 5738     c3/return
 5739 
 5740 test-get-with-wrong-base-type:
 5741     # . prologue
 5742     55/push-ebp
 5743     89/<- %ebp 4/r32/esp
 5744     # setup
 5745     (clear-stream _test-input-stream)
 5746     (clear-stream $_test-input-buffered-file->buffer)
 5747     (clear-stream _test-output-stream)
 5748     (clear-stream $_test-output-buffered-file->buffer)
 5749     (clear-stream _test-error-stream)
 5750     (clear-stream $_test-error-buffered-file->buffer)
 5751     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5752     68/push 0/imm32
 5753     68/push 0/imm32
 5754     89/<- %edx 4/r32/esp
 5755     (tailor-exit-descriptor %edx 0x10)
 5756     #
 5757     (write _test-input-stream "fn foo {\n")
 5758     (write _test-input-stream "  var a: int\n")
 5759     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5760     (write _test-input-stream "}\n")
 5761     # convert
 5762     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5763     # registers except esp clobbered at this point
 5764     # restore ed
 5765     89/<- %edx 4/r32/esp
 5766     (flush _test-output-buffered-file)
 5767     (flush _test-error-buffered-file)
 5768 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5774     # check output
 5775     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type: output should be empty")
 5776     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: var 'a' must have a 'type' definition"  "F - test-get-with-wrong-base-type: error message")
 5777     # check that stop(1) was called
 5778     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type: exit status")
 5779     # don't restore from ebp
 5780     81 0/subop/add %esp 8/imm32
 5781     # . epilogue
 5782     5d/pop-to-ebp
 5783     c3/return
 5784 
 5785 test-get-with-wrong-base-type-2:
 5786     # . prologue
 5787     55/push-ebp
 5788     89/<- %ebp 4/r32/esp
 5789     # setup
 5790     (clear-stream _test-input-stream)
 5791     (clear-stream $_test-input-buffered-file->buffer)
 5792     (clear-stream _test-output-stream)
 5793     (clear-stream $_test-output-buffered-file->buffer)
 5794     (clear-stream _test-error-stream)
 5795     (clear-stream $_test-error-buffered-file->buffer)
 5796     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5797     68/push 0/imm32
 5798     68/push 0/imm32
 5799     89/<- %edx 4/r32/esp
 5800     (tailor-exit-descriptor %edx 0x10)
 5801     #
 5802     (write _test-input-stream "fn foo {\n")
 5803     (write _test-input-stream "  var a: (addr t)\n")
 5804     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5805     (write _test-input-stream "}\n")
 5806     (write _test-input-stream "type t {\n")
 5807     (write _test-input-stream "  x: int\n")
 5808     (write _test-input-stream "}\n")
 5809     # convert
 5810     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5811     # registers except esp clobbered at this point
 5812     # restore ed
 5813     89/<- %edx 4/r32/esp
 5814     (flush _test-output-buffered-file)
 5815     (flush _test-error-buffered-file)
 5816 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5822     # check output
 5823     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type-2: output should be empty")
 5824     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: var 'a' is an 'addr' type, and so must live in a register"  "F - test-get-with-wrong-base-type-2: error message")
 5825     # check that stop(1) was called
 5826     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type-2: exit status")
 5827     # don't restore from ebp
 5828     81 0/subop/add %esp 8/imm32
 5829     # . epilogue
 5830     5d/pop-to-ebp
 5831     c3/return
 5832 
 5833 test-get-with-wrong-offset-type:
 5834     # . prologue
 5835     55/push-ebp
 5836     89/<- %ebp 4/r32/esp
 5837     # setup
 5838     (clear-stream _test-input-stream)
 5839     (clear-stream $_test-input-buffered-file->buffer)
 5840     (clear-stream _test-output-stream)
 5841     (clear-stream $_test-output-buffered-file->buffer)
 5842     (clear-stream _test-error-stream)
 5843     (clear-stream $_test-error-buffered-file->buffer)
 5844     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5845     68/push 0/imm32
 5846     68/push 0/imm32
 5847     89/<- %edx 4/r32/esp
 5848     (tailor-exit-descriptor %edx 0x10)
 5849     #
 5850     (write _test-input-stream "fn foo {\n")
 5851     (write _test-input-stream "  var a: t\n")
 5852     (write _test-input-stream "  var b: int\n")
 5853     (write _test-input-stream "  var c/ecx: (addr int) <- get a, b\n")
 5854     (write _test-input-stream "}\n")
 5855     (write _test-input-stream "type t {\n")
 5856     (write _test-input-stream "  x: int\n")
 5857     (write _test-input-stream "}\n")
 5858     # convert
 5859     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5860     # registers except esp clobbered at this point
 5861     # restore ed
 5862     89/<- %edx 4/r32/esp
 5863     (flush _test-output-buffered-file)
 5864     (flush _test-error-buffered-file)
 5865 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5871     # check output
 5872     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-offset-type: output should be empty")
 5873     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: type 't' has no member called 'b'"  "F - test-get-with-wrong-offset-type: error message")
 5874     # check that stop(1) was called
 5875     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-offset-type: exit status")
 5876     # don't restore from ebp
 5877     81 0/subop/add %esp 8/imm32
 5878     # . epilogue
 5879     5d/pop-to-ebp
 5880     c3/return
 5881 
 5882 test-get-with-wrong-output-type:
 5883     # . prologue
 5884     55/push-ebp
 5885     89/<- %ebp 4/r32/esp
 5886     # setup
 5887     (clear-stream _test-input-stream)
 5888     (clear-stream $_test-input-buffered-file->buffer)
 5889     (clear-stream _test-output-stream)
 5890     (clear-stream $_test-output-buffered-file->buffer)
 5891     (clear-stream _test-error-stream)
 5892     (clear-stream $_test-error-buffered-file->buffer)
 5893     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5894     68/push 0/imm32
 5895     68/push 0/imm32
 5896     89/<- %edx 4/r32/esp
 5897     (tailor-exit-descriptor %edx 0x10)
 5898     #
 5899     (write _test-input-stream "fn foo {\n")
 5900     (write _test-input-stream "  var a: t\n")
 5901     (write _test-input-stream "  var c: (addr int)\n")
 5902     (write _test-input-stream "  c <- get a, x\n")
 5903     (write _test-input-stream "}\n")
 5904     (write _test-input-stream "type t {\n")
 5905     (write _test-input-stream "  x: int\n")
 5906     (write _test-input-stream "}\n")
 5907     # convert
 5908     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5909     # registers except esp clobbered at this point
 5910     # restore ed
 5911     89/<- %edx 4/r32/esp
 5912     (flush _test-output-buffered-file)
 5913     (flush _test-error-buffered-file)
 5914 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5920     # check output
 5921     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type: output should be empty")
 5922     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: output 'c' is not in a register"  "F - test-get-with-wrong-output-type: error message")
 5923     # check that stop(1) was called
 5924     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type: exit status")
 5925     # don't restore from ebp
 5926     81 0/subop/add %esp 8/imm32
 5927     # . epilogue
 5928     5d/pop-to-ebp
 5929     c3/return
 5930 
 5931 test-get-with-wrong-output-type-2:
 5932     # . prologue
 5933     55/push-ebp
 5934     89/<- %ebp 4/r32/esp
 5935     # setup
 5936     (clear-stream _test-input-stream)
 5937     (clear-stream $_test-input-buffered-file->buffer)
 5938     (clear-stream _test-output-stream)
 5939     (clear-stream $_test-output-buffered-file->buffer)
 5940     (clear-stream _test-error-stream)
 5941     (clear-stream $_test-error-buffered-file->buffer)
 5942     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5943     68/push 0/imm32
 5944     68/push 0/imm32
 5945     89/<- %edx 4/r32/esp
 5946     (tailor-exit-descriptor %edx 0x10)
 5947     #
 5948     (write _test-input-stream "fn foo {\n")
 5949     (write _test-input-stream "  var a: t\n")
 5950     (write _test-input-stream "  var c/ecx: int <- get a, x\n")
 5951     (write _test-input-stream "}\n")
 5952     (write _test-input-stream "type t {\n")
 5953     (write _test-input-stream "  x: int\n")
 5954     (write _test-input-stream "}\n")
 5955     # convert
 5956     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5957     # registers except esp clobbered at this point
 5958     # restore ed
 5959     89/<- %edx 4/r32/esp
 5960     (flush _test-output-buffered-file)
 5961     (flush _test-error-buffered-file)
 5962 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5968     # check output
 5969     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-2: output should be empty")
 5970     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: output must be an address"  "F - test-get-with-wrong-output-type-2: error message")
 5971     # check that stop(1) was called
 5972     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-2: exit status")
 5973     # don't restore from ebp
 5974     81 0/subop/add %esp 8/imm32
 5975     # . epilogue
 5976     5d/pop-to-ebp
 5977     c3/return
 5978 
 5979 test-get-with-wrong-output-type-3:
 5980     # . prologue
 5981     55/push-ebp
 5982     89/<- %ebp 4/r32/esp
 5983     # setup
 5984     (clear-stream _test-input-stream)
 5985     (clear-stream $_test-input-buffered-file->buffer)
 5986     (clear-stream _test-output-stream)
 5987     (clear-stream $_test-output-buffered-file->buffer)
 5988     (clear-stream _test-error-stream)
 5989     (clear-stream $_test-error-buffered-file->buffer)
 5990     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5991     68/push 0/imm32
 5992     68/push 0/imm32
 5993     89/<- %edx 4/r32/esp
 5994     (tailor-exit-descriptor %edx 0x10)
 5995     #
 5996     (write _test-input-stream "fn foo {\n")
 5997     (write _test-input-stream "  var a: t\n")
 5998     (write _test-input-stream "  var c/ecx: (array int) <- get a, x\n")
 5999     (write _test-input-stream "}\n")
 6000     (write _test-input-stream "type t {\n")
 6001     (write _test-input-stream "  x: int\n")
 6002     (write _test-input-stream "}\n")
 6003     # convert
 6004     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6005     # registers except esp clobbered at this point
 6006     # restore ed
 6007     89/<- %edx 4/r32/esp
 6008     (flush _test-output-buffered-file)
 6009     (flush _test-error-buffered-file)
 6010 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6016     # check output
 6017     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-3: output should be empty")
 6018     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: output must be an address"  "F - test-get-with-wrong-output-type-3: error message")
 6019     # check that stop(1) was called
 6020     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-3: exit status")
 6021     # don't restore from ebp
 6022     81 0/subop/add %esp 8/imm32
 6023     # . epilogue
 6024     5d/pop-to-ebp
 6025     c3/return
 6026 
 6027 test-get-with-wrong-output-type-4:
 6028     # . prologue
 6029     55/push-ebp
 6030     89/<- %ebp 4/r32/esp
 6031     # setup
 6032     (clear-stream _test-input-stream)
 6033     (clear-stream $_test-input-buffered-file->buffer)
 6034     (clear-stream _test-output-stream)
 6035     (clear-stream $_test-output-buffered-file->buffer)
 6036     (clear-stream _test-error-stream)
 6037     (clear-stream $_test-error-buffered-file->buffer)
 6038     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6039     68/push 0/imm32
 6040     68/push 0/imm32
 6041     89/<- %edx 4/r32/esp
 6042     (tailor-exit-descriptor %edx 0x10)
 6043     #
 6044     (write _test-input-stream "fn foo {\n")
 6045     (write _test-input-stream "  var a: t\n")
 6046     (write _test-input-stream "  var c/ecx: (addr boolean) <- get a, x\n")
 6047     (write _test-input-stream "}\n")
 6048     (write _test-input-stream "type t {\n")
 6049     (write _test-input-stream "  x: int\n")
 6050     (write _test-input-stream "}\n")
 6051     # convert
 6052     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6053     # registers except esp clobbered at this point
 6054     # restore ed
 6055     89/<- %edx 4/r32/esp
 6056     (flush _test-output-buffered-file)
 6057     (flush _test-error-buffered-file)
 6058 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6064     # check output
 6065     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-4: output should be empty")
 6066     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: wrong output type for member 'x' of type 't'"  "F - test-get-with-wrong-output-type-4: error message")
 6067     # check that stop(1) was called
 6068     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-4: exit status")
 6069     # don't restore from ebp
 6070     81 0/subop/add %esp 8/imm32
 6071     # . epilogue
 6072     5d/pop-to-ebp
 6073     c3/return
 6074 
 6075 test-get-with-wrong-output-type-5:
 6076     # . prologue
 6077     55/push-ebp
 6078     89/<- %ebp 4/r32/esp
 6079     # setup
 6080     (clear-stream _test-input-stream)
 6081     (clear-stream $_test-input-buffered-file->buffer)
 6082     (clear-stream _test-output-stream)
 6083     (clear-stream $_test-output-buffered-file->buffer)
 6084     #
 6085     (write _test-input-stream "fn foo {\n")
 6086     (write _test-input-stream "  var a: t\n")
 6087     (write _test-input-stream "  var c/ecx: (addr handle int) <- get a, x\n")
 6088     (write _test-input-stream "}\n")
 6089     (write _test-input-stream "type t {\n")
 6090     (write _test-input-stream "  x: (handle int)\n")
 6091     (write _test-input-stream "}\n")
 6092     # convert
 6093     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6094     (flush _test-output-buffered-file)
 6095     # no errors
 6096     # . epilogue
 6097     89/<- %esp 5/r32/ebp
 6098     5d/pop-to-ebp
 6099     c3/return
 6100 
 6101 test-get-with-too-few-inouts:
 6102     # . prologue
 6103     55/push-ebp
 6104     89/<- %ebp 4/r32/esp
 6105     # setup
 6106     (clear-stream _test-input-stream)
 6107     (clear-stream $_test-input-buffered-file->buffer)
 6108     (clear-stream _test-output-stream)
 6109     (clear-stream $_test-output-buffered-file->buffer)
 6110     (clear-stream _test-error-stream)
 6111     (clear-stream $_test-error-buffered-file->buffer)
 6112     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6113     68/push 0/imm32
 6114     68/push 0/imm32
 6115     89/<- %edx 4/r32/esp
 6116     (tailor-exit-descriptor %edx 0x10)
 6117     #
 6118     (write _test-input-stream "fn foo {\n")
 6119     (write _test-input-stream "  var a: t\n")
 6120     (write _test-input-stream "  var c/ecx: (addr int) <- get a\n")
 6121     (write _test-input-stream "}\n")
 6122     (write _test-input-stream "type t {\n")
 6123     (write _test-input-stream "  x: int\n")
 6124     (write _test-input-stream "}\n")
 6125     # convert
 6126     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6127     # registers except esp clobbered at this point
 6128     # restore ed
 6129     89/<- %edx 4/r32/esp
 6130     (flush _test-output-buffered-file)
 6131     (flush _test-error-buffered-file)
 6132 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6138     # check output
 6139     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-few-inouts: output should be empty")
 6140     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: too few inouts (2 required)"  "F - test-get-with-too-few-inouts: error message")
 6141     # check that stop(1) was called
 6142     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-few-inouts: exit status")
 6143     # don't restore from ebp
 6144     81 0/subop/add %esp 8/imm32
 6145     # . epilogue
 6146     5d/pop-to-ebp
 6147     c3/return
 6148 
 6149 test-get-with-too-many-inouts:
 6150     # . prologue
 6151     55/push-ebp
 6152     89/<- %ebp 4/r32/esp
 6153     # setup
 6154     (clear-stream _test-input-stream)
 6155     (clear-stream $_test-input-buffered-file->buffer)
 6156     (clear-stream _test-output-stream)
 6157     (clear-stream $_test-output-buffered-file->buffer)
 6158     (clear-stream _test-error-stream)
 6159     (clear-stream $_test-error-buffered-file->buffer)
 6160     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6161     68/push 0/imm32
 6162     68/push 0/imm32
 6163     89/<- %edx 4/r32/esp
 6164     (tailor-exit-descriptor %edx 0x10)
 6165     #
 6166     (write _test-input-stream "fn foo {\n")
 6167     (write _test-input-stream "  var a: t\n")
 6168     (write _test-input-stream "  var c/ecx: (addr int) <- get a, x, 0\n")
 6169     (write _test-input-stream "}\n")
 6170     (write _test-input-stream "type t {\n")
 6171     (write _test-input-stream "  x: int\n")
 6172     (write _test-input-stream "}\n")
 6173     # convert
 6174     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6175     # registers except esp clobbered at this point
 6176     # restore ed
 6177     89/<- %edx 4/r32/esp
 6178     (flush _test-output-buffered-file)
 6179     (flush _test-error-buffered-file)
 6180 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6186     # check output
 6187     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-inouts: output should be empty")
 6188     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: too many inouts (2 required)"  "F - test-get-with-too-many-inouts: error message")
 6189     # check that stop(1) was called
 6190     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-inouts: exit status")
 6191     # don't restore from ebp
 6192     81 0/subop/add %esp 8/imm32
 6193     # . epilogue
 6194     5d/pop-to-ebp
 6195     c3/return
 6196 
 6197 test-get-with-no-output:
 6198     # . prologue
 6199     55/push-ebp
 6200     89/<- %ebp 4/r32/esp
 6201     # setup
 6202     (clear-stream _test-input-stream)
 6203     (clear-stream $_test-input-buffered-file->buffer)
 6204     (clear-stream _test-output-stream)
 6205     (clear-stream $_test-output-buffered-file->buffer)
 6206     (clear-stream _test-error-stream)
 6207     (clear-stream $_test-error-buffered-file->buffer)
 6208     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6209     68/push 0/imm32
 6210     68/push 0/imm32
 6211     89/<- %edx 4/r32/esp
 6212     (tailor-exit-descriptor %edx 0x10)
 6213     #
 6214     (write _test-input-stream "fn foo {\n")
 6215     (write _test-input-stream "  var a: t\n")
 6216     (write _test-input-stream "  get a, x\n")
 6217     (write _test-input-stream "}\n")
 6218     (write _test-input-stream "type t {\n")
 6219     (write _test-input-stream "  x: int\n")
 6220     (write _test-input-stream "}\n")
 6221     # convert
 6222     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6223     # registers except esp clobbered at this point
 6224     # restore ed
 6225     89/<- %edx 4/r32/esp
 6226     (flush _test-output-buffered-file)
 6227     (flush _test-error-buffered-file)
 6228 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6234     # check output
 6235     (check-stream-equal _test-output-stream  ""  "F - test-get-with-no-output: output should be empty")
 6236     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: must have an output"  "F - test-get-with-no-output: error message")
 6237     # check that stop(1) was called
 6238     (check-ints-equal *(edx+4) 2 "F - test-get-with-no-output: exit status")
 6239     # don't restore from ebp
 6240     81 0/subop/add %esp 8/imm32
 6241     # . epilogue
 6242     5d/pop-to-ebp
 6243     c3/return
 6244 
 6245 test-get-with-too-many-outputs:
 6246     # . prologue
 6247     55/push-ebp
 6248     89/<- %ebp 4/r32/esp
 6249     # setup
 6250     (clear-stream _test-input-stream)
 6251     (clear-stream $_test-input-buffered-file->buffer)
 6252     (clear-stream _test-output-stream)
 6253     (clear-stream $_test-output-buffered-file->buffer)
 6254     (clear-stream _test-error-stream)
 6255     (clear-stream $_test-error-buffered-file->buffer)
 6256     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6257     68/push 0/imm32
 6258     68/push 0/imm32
 6259     89/<- %edx 4/r32/esp
 6260     (tailor-exit-descriptor %edx 0x10)
 6261     #
 6262     (write _test-input-stream "fn foo {\n")
 6263     (write _test-input-stream "  var a: t\n")
 6264     (write _test-input-stream "  var b: int\n")
 6265     (write _test-input-stream "  var c/eax: (addr int) <- copy 0\n")
 6266     (write _test-input-stream "  c, b <- get a, x\n")
 6267     (write _test-input-stream "}\n")
 6268     (write _test-input-stream "type t {\n")
 6269     (write _test-input-stream "  x: int\n")
 6270     (write _test-input-stream "}\n")
 6271     # convert
 6272     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6273     # registers except esp clobbered at this point
 6274     # restore ed
 6275     89/<- %edx 4/r32/esp
 6276     (flush _test-output-buffered-file)
 6277     (flush _test-error-buffered-file)
 6278 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6284     # check output
 6285     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-outputs: output should be empty")
 6286     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: too many outputs (1 required)"  "F - test-get-with-too-many-outputs: error message")
 6287     # check that stop(1) was called
 6288     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-outputs: exit status")
 6289     # don't restore from ebp
 6290     81 0/subop/add %esp 8/imm32
 6291     # . epilogue
 6292     5d/pop-to-ebp
 6293     c3/return
 6294 
 6295 test-convert-array-of-user-defined-types:
 6296     # . prologue
 6297     55/push-ebp
 6298     89/<- %ebp 4/r32/esp
 6299     # setup
 6300     (clear-stream _test-input-stream)
 6301     (clear-stream $_test-input-buffered-file->buffer)
 6302     (clear-stream _test-output-stream)
 6303     (clear-stream $_test-output-buffered-file->buffer)
 6304     #
 6305     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 6306     (write _test-input-stream "  x: int\n")
 6307     (write _test-input-stream "  y: int\n")
 6308     (write _test-input-stream "}\n")
 6309     (write _test-input-stream "fn foo {\n")
 6310     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6311     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 6312     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 6313     (write _test-input-stream "}\n")
 6314     # convert
 6315     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6316     (flush _test-output-buffered-file)
 6317 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6323     # check output
 6324     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-array-of-user-defined-types/0")
 6325     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-array-of-user-defined-types/1")
 6326     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-array-of-user-defined-types/2")
 6327     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-array-of-user-defined-types/3")
 6328     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-array-of-user-defined-types/4")
 6329     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-array-of-user-defined-types/5")
 6330     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-array-of-user-defined-types/6")
 6331     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-array-of-user-defined-types/7")
 6332     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-array-of-user-defined-types/8")
 6333     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-array-of-user-defined-types/9")
 6334     (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")
 6335     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-array-of-user-defined-types/13")
 6336     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-array-of-user-defined-types/14")
 6337     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-array-of-user-defined-types/15")
 6338     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-array-of-user-defined-types/16")
 6339     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-array-of-user-defined-types/17")
 6340     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-array-of-user-defined-types/18")
 6341     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-array-of-user-defined-types/19")
 6342     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-array-of-user-defined-types/20")
 6343     # . epilogue
 6344     89/<- %esp 5/r32/ebp
 6345     5d/pop-to-ebp
 6346     c3/return
 6347 
 6348 test-convert-length-of-array-of-user-defined-types-to-eax:
 6349     # . prologue
 6350     55/push-ebp
 6351     89/<- %ebp 4/r32/esp
 6352     # setup
 6353     (clear-stream _test-input-stream)
 6354     (clear-stream $_test-input-buffered-file->buffer)
 6355     (clear-stream _test-output-stream)
 6356     (clear-stream $_test-output-buffered-file->buffer)
 6357     #
 6358     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6359     (write _test-input-stream "  x: int\n")
 6360     (write _test-input-stream "  y: int\n")
 6361     (write _test-input-stream "  z: int\n")
 6362     (write _test-input-stream "}\n")
 6363     (write _test-input-stream "fn foo {\n")
 6364     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6365     (write _test-input-stream "  var x/eax: (addr t) <- length arr\n")
 6366     (write _test-input-stream "}\n")
 6367     # convert
 6368     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6369     (flush _test-output-buffered-file)
 6370 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6376     # check output
 6377     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-eax/0")
 6378     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/1")
 6379     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-eax/2")
 6380     (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")
 6381     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/4")
 6382     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-eax/5")
 6383     # var arr
 6384     (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")
 6385     (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")
 6386     # length instruction
 6387     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/8")
 6388     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/9")
 6389     (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")
 6390     (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")
 6391     (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")
 6392     (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")
 6393     (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")
 6394     (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")
 6395     # reclaim arr
 6396     (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")
 6397     #
 6398     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/17")
 6399     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/18")
 6400     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/19")
 6401     (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")
 6402     (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")
 6403     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-eax/22")
 6404     # . epilogue
 6405     89/<- %esp 5/r32/ebp
 6406     5d/pop-to-ebp
 6407     c3/return
 6408 
 6409 test-convert-length-of-array-of-user-defined-types-to-ecx:
 6410     # . prologue
 6411     55/push-ebp
 6412     89/<- %ebp 4/r32/esp
 6413     # setup
 6414     (clear-stream _test-input-stream)
 6415     (clear-stream $_test-input-buffered-file->buffer)
 6416     (clear-stream _test-output-stream)
 6417     (clear-stream $_test-output-buffered-file->buffer)
 6418     #
 6419     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6420     (write _test-input-stream "  x: int\n")
 6421     (write _test-input-stream "  y: int\n")
 6422     (write _test-input-stream "  z: int\n")
 6423     (write _test-input-stream "}\n")
 6424     (write _test-input-stream "fn foo {\n")
 6425     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6426     (write _test-input-stream "  var x/ecx: (addr t) <- length arr\n")
 6427     (write _test-input-stream "}\n")
 6428     # convert
 6429     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6430     (flush _test-output-buffered-file)
 6431 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6437     # check output
 6438     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-ecx/0")
 6439     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/1")
 6440     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-ecx/2")
 6441     (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")
 6442     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/4")
 6443     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-ecx/5")
 6444     # var a
 6445     (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")
 6446     (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")
 6447     # var x
 6448     (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")
 6449     # length instruction
 6450     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/9")
 6451     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/10")
 6452     (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")
 6453     (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")
 6454     (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")
 6455     (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")
 6456     (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")
 6457     (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")
 6458     (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")
 6459     # reclaim x
 6460     (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")
 6461     # reclaim a
 6462     (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")
 6463     #
 6464     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/20")
 6465     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/21")
 6466     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/22")
 6467     (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")
 6468     (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")
 6469     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-ecx/25")
 6470     # . epilogue
 6471     89/<- %esp 5/r32/ebp
 6472     5d/pop-to-ebp
 6473     c3/return
 6474 
 6475 test-convert-length-of-array-of-user-defined-types-to-edx:
 6476     # . prologue
 6477     55/push-ebp
 6478     89/<- %ebp 4/r32/esp
 6479     # setup
 6480     (clear-stream _test-input-stream)
 6481     (clear-stream $_test-input-buffered-file->buffer)
 6482     (clear-stream _test-output-stream)
 6483     (clear-stream $_test-output-buffered-file->buffer)
 6484     #
 6485     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6486     (write _test-input-stream "  x: int\n")
 6487     (write _test-input-stream "  y: int\n")
 6488     (write _test-input-stream "  z: int\n")
 6489     (write _test-input-stream "}\n")
 6490     (write _test-input-stream "fn foo {\n")
 6491     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6492     (write _test-input-stream "  var x/edx: (addr t) <- length arr\n")
 6493     (write _test-input-stream "}\n")
 6494     # convert
 6495     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6496     (flush _test-output-buffered-file)
 6497 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6503     # check output
 6504     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-edx/0")
 6505     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/1")
 6506     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-edx/2")
 6507     (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")
 6508     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/4")
 6509     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-edx/5")
 6510     # var a
 6511     (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")
 6512     (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")
 6513     # var x
 6514     (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")
 6515     # length instruction
 6516     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/9")
 6517     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/10")
 6518     (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")
 6519     (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")
 6520     (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")
 6521     (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")
 6522     (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")
 6523     (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")
 6524     (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")
 6525     # reclaim x
 6526     (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")
 6527     # reclaim a
 6528     (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")
 6529     #
 6530     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/20")
 6531     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/21")
 6532     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/22")
 6533     (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")
 6534     (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")
 6535     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-edx/25")
 6536     # . epilogue
 6537     89/<- %esp 5/r32/ebp
 6538     5d/pop-to-ebp
 6539     c3/return
 6540 
 6541 test-convert-length-of-array-of-user-defined-types:
 6542     # . prologue
 6543     55/push-ebp
 6544     89/<- %ebp 4/r32/esp
 6545     # setup
 6546     (clear-stream _test-input-stream)
 6547     (clear-stream $_test-input-buffered-file->buffer)
 6548     (clear-stream _test-output-stream)
 6549     (clear-stream $_test-output-buffered-file->buffer)
 6550     #
 6551     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 6552     (write _test-input-stream "  x: int\n")
 6553     (write _test-input-stream "  y: int\n")
 6554     (write _test-input-stream "  z: int\n")
 6555     (write _test-input-stream "}\n")
 6556     (write _test-input-stream "fn foo {\n")
 6557     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6558     (write _test-input-stream "  var x/ebx: (addr t) <- length arr\n")
 6559     (write _test-input-stream "}\n")
 6560     # convert
 6561     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6562     (flush _test-output-buffered-file)
 6563 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6569     # check output
 6570     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types/0")
 6571     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types/1")
 6572     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types/2")
 6573     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types/3")
 6574     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types/4")
 6575     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types/5")
 6576     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types/6")
 6577     (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")
 6578     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ebx"  "F - test-convert-length-of-array-of-user-defined-types/8")
 6579     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types/9")
 6580     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types/10")
 6581     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types/11")
 6582     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types/12")
 6583     (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")
 6584     (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")
 6585     (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")
 6586     (check-next-stream-line-equal _test-output-stream "    89/<- %ebx 0/r32/eax"  "F - test-convert-length-of-array-of-user-defined-types/16")
 6587     (check-next-stream-line-equal _test-output-stream "    5a/pop-to-edx"       "F - test-convert-length-of-array-of-user-defined-types/17")
 6588     (check-next-stream-line-equal _test-output-stream "    59/pop-to-ecx"       "F - test-convert-length-of-array-of-user-defined-types/18")
 6589     (check-next-stream-line-equal _test-output-stream "    58/pop-to-eax"       "F - test-convert-length-of-array-of-user-defined-types/19")
 6590     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ebx"  "F - test-convert-length-of-array-of-user-defined-types/20")
 6591     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types/21")
 6592     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types/22")
 6593     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types/23")
 6594     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types/24")
 6595     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types/25")
 6596     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types/26")
 6597     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types/27")
 6598     # . epilogue
 6599     89/<- %esp 5/r32/ebp
 6600     5d/pop-to-ebp
 6601     c3/return
 6602 
 6603 #######################################################
 6604 # Parsing
 6605 #######################################################
 6606 
 6607 == data
 6608 
 6609 # Global state added to each var record when parsing a function
 6610 Next-block-index:  # (addr int)
 6611     1/imm32
 6612 
 6613 Curr-block-depth:  # (addr int)
 6614     1/imm32
 6615 
 6616 == code
 6617 
 6618 parse-mu:  # in: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
 6619     # pseudocode
 6620     #   var curr-function: (addr handle function) = Program->functions
 6621     #   var curr-signature: (addr handle function) = Program->signatures
 6622     #   var curr-type: (addr handle typeinfo) = Program->types
 6623     #   var line: (stream byte 512)
 6624     #   var word-slice: slice
 6625     #   while true                                  # line loop
 6626     #     clear-stream(line)
 6627     #     read-line-buffered(in, line)
 6628     #     if (line->write == 0) break               # end of file
 6629     #     word-slice = next-mu-token(line)
 6630     #     if slice-empty?(word-slice)               # end of line
 6631     #       continue
 6632     #     else if slice-starts-with?(word-slice, "#")  # comment
 6633     #       continue                                # end of line
 6634     #     else if slice-equal?(word-slice, "fn")
 6635     #       var new-function: (handle function) = allocate(function)
 6636     #       var vars: (stack live-var 256)
 6637     #       populate-mu-function-header(line, new-function, vars)
 6638     #       populate-mu-function-body(in, new-function, vars)
 6639     #       assert(vars->top == 0)
 6640     #       *curr-function = new-function
 6641     #       curr-function = &new-function->next
 6642     #     else if slice-equal?(word-slice, "sig")
 6643     #       var new-function: (handle function) = allocate(function)
 6644     #       populate-mu-function-signature(line, new-function)
 6645     #       *curr-signature = new-function
 6646     #       curr-signature = &new-function->next
 6647     #     else if slice-equal?(word-slice, "type")
 6648     #       word-slice = next-mu-token(line)
 6649     #       type-id = pos-or-insert-slice(Type-id, word-slice)
 6650     #       var new-type: (handle typeinfo) = find-or-create-typeinfo(type-id)
 6651     #       assert(next-word(line) == "{")
 6652     #       populate-mu-type(in, new-type)
 6653     #     else
 6654     #       abort()
 6655     #
 6656     # . prologue
 6657     55/push-ebp
 6658     89/<- %ebp 4/r32/esp
 6659     # var curr-signature: (addr handle function) at *(ebp-4)
 6660     68/push _Program-signatures/imm32
 6661     # . save registers
 6662     50/push-eax
 6663     51/push-ecx
 6664     52/push-edx
 6665     53/push-ebx
 6666     56/push-esi
 6667     57/push-edi
 6668     # var line/ecx: (stream byte 512)
 6669     81 5/subop/subtract %esp 0x200/imm32
 6670     68/push 0x200/imm32/size
 6671     68/push 0/imm32/read
 6672     68/push 0/imm32/write
 6673     89/<- %ecx 4/r32/esp
 6674     # var word-slice/edx: slice
 6675     68/push 0/imm32/end
 6676     68/push 0/imm32/start
 6677     89/<- %edx 4/r32/esp
 6678     # var curr-function/edi: (addr handle function)
 6679     bf/copy-to-edi _Program-functions/imm32
 6680     # var vars/ebx: (stack live-var 256)
 6681     81 5/subop/subtract %esp 0xc00/imm32
 6682     68/push 0xc00/imm32/size
 6683     68/push 0/imm32/top
 6684     89/<- %ebx 4/r32/esp
 6685     {
 6686 $parse-mu:line-loop:
 6687       (clear-stream %ecx)
 6688       (read-line-buffered *(ebp+8) %ecx)
 6689       # if (line->write == 0) break
 6690       81 7/subop/compare *ecx 0/imm32
 6691       0f 84/jump-if-= break/disp32
 6692 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
 6698       (next-mu-token %ecx %edx)
 6699       # if slice-empty?(word-slice) continue
 6700       (slice-empty? %edx)  # => eax
 6701       3d/compare-eax-and 0/imm32/false
 6702       0f 85/jump-if-!= loop/disp32
 6703       # if (*word-slice->start == "#") continue
 6704       # . eax = *word-slice->start
 6705       8b/-> *edx 0/r32/eax
 6706       8a/copy-byte *eax 0/r32/AL
 6707       81 4/subop/and %eax 0xff/imm32
 6708       # . if (eax == '#') continue
 6709       3d/compare-eax-and 0x23/imm32/hash
 6710       0f 84/jump-if-= loop/disp32
 6711       # if (slice-equal?(word-slice, "fn")) parse a function
 6712       {
 6713 $parse-mu:fn:
 6714         (slice-equal? %edx "fn")  # => eax
 6715         3d/compare-eax-and 0/imm32/false
 6716         0f 84/jump-if-= break/disp32
 6717         # var new-function/esi: (handle function)
 6718         68/push 0/imm32
 6719         68/push 0/imm32
 6720         89/<- %esi 4/r32/esp
 6721         # populate-mu-function(line, in, vars, new-function)
 6722         (allocate Heap *Function-size %esi)
 6723         # var new-function-addr/eax: (addr function)
 6724         (lookup *esi *(esi+4))  # => eax
 6725         # initialize vars
 6726         (clear-stack %ebx)
 6727         #
 6728         (populate-mu-function-header %ecx %eax %ebx *(ebp+0xc) *(ebp+0x10))
 6729         (populate-mu-function-body *(ebp+8) %eax %ebx *(ebp+0xc) *(ebp+0x10))
 6730         # *curr-function = new-function
 6731         8b/-> *esi 0/r32/eax
 6732         89/<- *edi 0/r32/eax
 6733         8b/-> *(esi+4) 0/r32/eax
 6734         89/<- *(edi+4) 0/r32/eax
 6735         # curr-function = &new-function->next
 6736         # . var tmp/eax: (addr function) = lookup(new-function)
 6737         (lookup *esi *(esi+4))  # => eax
 6738         # . curr-function = &tmp->next
 6739         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 6740         # reclaim new-function
 6741         81 0/subop/add %esp 8/imm32
 6742         #
 6743         e9/jump $parse-mu:line-loop/disp32
 6744       }
 6745       # if (slice-equal?(word-slice, "sig")) parse a function signature
 6746       # Function signatures are for providing types to SubX functions.
 6747       {
 6748 $parse-mu:sig:
 6749         (slice-equal? %edx "sig")  # => eax
 6750         3d/compare-eax-and 0/imm32/false
 6751         0f 84/jump-if-= break/disp32
 6752         # edi = curr-function
 6753         57/push-edi
 6754         8b/-> *(ebp-4) 7/r32/edi
 6755         # var new-function/esi: (handle function)
 6756         68/push 0/imm32
 6757         68/push 0/imm32
 6758         89/<- %esi 4/r32/esp
 6759         # populate-mu-function(line, in, vars, new-function)
 6760         (allocate Heap *Function-size %esi)
 6761         # var new-function-addr/eax: (addr function)
 6762         (lookup *esi *(esi+4))  # => eax
 6763         #
 6764         (populate-mu-function-signature %ecx %eax *(ebp+0xc) *(ebp+0x10))
 6765         # *curr-signature = new-function
 6766         8b/-> *esi 0/r32/eax
 6767         89/<- *edi 0/r32/eax
 6768         8b/-> *(esi+4) 0/r32/eax
 6769         89/<- *(edi+4) 0/r32/eax
 6770         # curr-signature = &new-function->next
 6771         # . var tmp/eax: (addr function) = lookup(new-function)
 6772         (lookup *esi *(esi+4))  # => eax
 6773         # . curr-function = &tmp->next
 6774         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 6775         # reclaim new-function
 6776         81 0/subop/add %esp 8/imm32
 6777         # save curr-function
 6778         89/<- *(ebp-4) 7/r32/edi
 6779         # restore edi
 6780         5f/pop-to-edi
 6781         #
 6782         e9/jump $parse-mu:line-loop/disp32
 6783       }
 6784       # if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition
 6785       {
 6786 $parse-mu:type:
 6787         (slice-equal? %edx "type")  # => eax
 6788         3d/compare-eax-and 0/imm32
 6789         0f 84/jump-if-= break/disp32
 6790         (next-mu-token %ecx %edx)
 6791         # var type-id/eax: int
 6792         (pos-or-insert-slice Type-id %edx)  # => eax
 6793         # spill
 6794         51/push-ecx
 6795         # var new-type/ecx: (handle typeinfo)
 6796         68/push 0/imm32
 6797         68/push 0/imm32
 6798         89/<- %ecx 4/r32/esp
 6799         (find-or-create-typeinfo %eax %ecx)
 6800         #
 6801         (lookup *ecx *(ecx+4))  # => eax
 6802         # TODO: ensure that 'line' has nothing else but '{'
 6803 #? (dump-typeinfos "=== aaa\n")
 6804         (populate-mu-type *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))  # => eax
 6805 #? (dump-typeinfos "=== zzz\n")
 6806         # reclaim new-type
 6807         81 0/subop/add %esp 8/imm32
 6808         # restore
 6809         59/pop-to-ecx
 6810         e9/jump $parse-mu:line-loop/disp32
 6811       }
 6812       # otherwise abort
 6813       e9/jump $parse-mu:error1/disp32
 6814     } # end line loop
 6815 $parse-mu:end:
 6816     # . reclaim locals
 6817     81 0/subop/add %esp 0x20c/imm32  # line
 6818     81 0/subop/add %esp 0xc08/imm32  # vars
 6819     81 0/subop/add %esp 8/imm32
 6820     # . restore registers
 6821     5f/pop-to-edi
 6822     5e/pop-to-esi
 6823     5b/pop-to-ebx
 6824     5a/pop-to-edx
 6825     59/pop-to-ecx
 6826     58/pop-to-eax
 6827     # . reclaim local
 6828     81 0/subop/add %esp 4/imm32
 6829     # . epilogue
 6830     89/<- %esp 5/r32/ebp
 6831     5d/pop-to-ebp
 6832     c3/return
 6833 
 6834 $parse-mu:error1:
 6835     # error("unexpected top-level command: " word-slice "\n")
 6836     (write-buffered *(ebp+0xc) "unexpected top-level command: ")
 6837     (write-slice-buffered *(ebp+0xc) %edx)
 6838     (write-buffered *(ebp+0xc) "\n")
 6839     (flush *(ebp+0xc))
 6840     (stop *(ebp+0x10) 1)
 6841     # never gets here
 6842 
 6843 $parse-mu:error2:
 6844     # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n")
 6845     (write-int32-hex-buffered *(ebp+0xc) *ebx)
 6846     (write-buffered *(ebp+0xc) " vars not reclaimed after fn '")
 6847     (write-slice-buffered *(ebp+0xc) *eax)  # Function-name
 6848     (write-buffered *(ebp+0xc) "'\n")
 6849     (flush *(ebp+0xc))
 6850     (stop *(ebp+0x10) 1)
 6851     # never gets here
 6852 
 6853 # scenarios considered:
 6854 # ✗ fn foo  # no block
 6855 # ✓ fn foo {
 6856 # ✗ fn foo { {
 6857 # ✗ fn foo { }
 6858 # ✗ fn foo { } {
 6859 # ✗ fn foo x {
 6860 # ✗ fn foo x: {
 6861 # ✓ fn foo x: int {
 6862 # ✓ fn foo x: int {
 6863 # ✓ fn foo x: int -> y/eax: int {
 6864 # TODO:
 6865 #   disallow outputs of type `(... addr ...)`
 6866 #   disallow inputs of type `(... addr ... addr ...)`
 6867 populate-mu-function-header:  # first-line: (addr stream byte), out: (addr function), vars: (addr stack live-var), err: (addr buffered-file), ed: (addr exit-descriptor)
 6868     # pseudocode:
 6869     #   var word-slice: slice
 6870     #   next-mu-token(first-line, word-slice)
 6871     #   assert(word-slice not in '{' '}' '->')
 6872     #   out->name = slice-to-string(word-slice)
 6873     #   ## inouts
 6874     #   while true
 6875     #     word-slice = next-mu-token(first-line)
 6876     #     if (word-slice == '{') goto done
 6877     #     if (word-slice == '->') break
 6878     #     assert(word-slice != '}')
 6879     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 6880     #     assert(v->register == null)
 6881     #     # v->block-depth is implicitly 0
 6882     #     out->inouts = append(v, out->inouts)
 6883     #     push(vars, {v, false})
 6884     #   ## outputs
 6885     #   while true
 6886     #     word-slice = next-mu-token(first-line)
 6887     #     if (word-slice == '{') break
 6888     #     assert(word-slice not in '}' '->')
 6889     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 6890     #     assert(v->register != null)
 6891     #     out->outputs = append(v, out->outputs)
 6892     #   done:
 6893     #
 6894     # . prologue
 6895     55/push-ebp
 6896     89/<- %ebp 4/r32/esp
 6897     # . save registers
 6898     50/push-eax
 6899     51/push-ecx
 6900     52/push-edx
 6901     53/push-ebx
 6902     57/push-edi
 6903     # edi = out
 6904     8b/-> *(ebp+0xc) 7/r32/edi
 6905     # var word-slice/ecx: slice
 6906     68/push 0/imm32/end
 6907     68/push 0/imm32/start
 6908     89/<- %ecx 4/r32/esp
 6909     # var v/ebx: (handle var)
 6910     68/push 0/imm32
 6911     68/push 0/imm32
 6912     89/<- %ebx 4/r32/esp
 6913     # read function name
 6914     (next-mu-token *(ebp+8) %ecx)
 6915     # error checking
 6916     # if (word-slice == '{') abort
 6917     (slice-equal? %ecx "{")   # => eax
 6918     3d/compare-eax-and 0/imm32/false
 6919     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6920     # if (word-slice == '->') abort
 6921     (slice-equal? %ecx "->")   # => eax
 6922     3d/compare-eax-and 0/imm32/false
 6923     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6924     # if (word-slice == '}') abort
 6925     (slice-equal? %ecx "}")   # => eax
 6926     3d/compare-eax-and 0/imm32/false
 6927     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6928     # save function name
 6929     (slice-to-string Heap %ecx %edi)  # Function-name
 6930     # save function inouts
 6931     {
 6932 $populate-mu-function-header:check-for-inout:
 6933       (next-mu-token *(ebp+8) %ecx)
 6934       # if (word-slice == '{') goto done
 6935       (slice-equal? %ecx "{")   # => eax
 6936       3d/compare-eax-and 0/imm32/false
 6937       0f 85/jump-if-!= $populate-mu-function-header:done/disp32
 6938       # if (word-slice == '->') break
 6939       (slice-equal? %ecx "->")   # => eax
 6940       3d/compare-eax-and 0/imm32/false
 6941       0f 85/jump-if-!= break/disp32
 6942       # if (word-slice == '}') abort
 6943       (slice-equal? %ecx "}")   # => eax
 6944       3d/compare-eax-and 0/imm32/false
 6945       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6946       # v = parse-var-with-type(word-slice, first-line)
 6947       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 6948       # assert(v->register == null)
 6949       # . eax: (addr var) = lookup(v)
 6950       (lookup *ebx *(ebx+4))  # => eax
 6951       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 6952       0f 85/jump-if-!= $populate-mu-function-header:error2/disp32
 6953       # v->block-depth is implicitly 0
 6954       #
 6955       # out->inouts = append(v, out->inouts)
 6956       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 6957       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 6958       # push(vars, {v, false})
 6959       (push *(ebp+0x10) *ebx)
 6960       (push *(ebp+0x10) *(ebx+4))
 6961       (push *(ebp+0x10) 0)  # false
 6962       #
 6963       e9/jump loop/disp32
 6964     }
 6965     # save function outputs
 6966     {
 6967 $populate-mu-function-header:check-for-out:
 6968       (next-mu-token *(ebp+8) %ecx)
 6969       # if (word-slice == '{') break
 6970       (slice-equal? %ecx "{")   # => eax
 6971       3d/compare-eax-and 0/imm32/false
 6972       0f 85/jump-if-!= break/disp32
 6973       # if (word-slice == '->') abort
 6974       (slice-equal? %ecx "->")   # => eax
 6975       3d/compare-eax-and 0/imm32/false
 6976       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6977       # if (word-slice == '}') abort
 6978       (slice-equal? %ecx "}")   # => eax
 6979       3d/compare-eax-and 0/imm32/false
 6980       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6981       # v = parse-var-with-type(word-slice, first-line)
 6982       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 6983       # assert(var->register != null)
 6984       # . eax: (addr var) = lookup(v)
 6985       (lookup *ebx *(ebx+4))  # => eax
 6986       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 6987       0f 84/jump-if-= $populate-mu-function-header:error3/disp32
 6988       # out->outputs = append(v, out->outputs)
 6989       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 6990       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 6991       #
 6992       e9/jump loop/disp32
 6993     }
 6994 $populate-mu-function-header:done:
 6995     (check-no-tokens-left *(ebp+8))
 6996 $populate-mu-function-header:end:
 6997     # . reclaim locals
 6998     81 0/subop/add %esp 0x10/imm32
 6999     # . restore registers
 7000     5f/pop-to-edi
 7001     5b/pop-to-ebx
 7002     5a/pop-to-edx
 7003     59/pop-to-ecx
 7004     58/pop-to-eax
 7005     # . epilogue
 7006     89/<- %esp 5/r32/ebp
 7007     5d/pop-to-ebp
 7008     c3/return
 7009 
 7010 $populate-mu-function-header:error1:
 7011     # error("function header not in form 'fn <name> {'")
 7012     (write-buffered *(ebp+0x14) "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 7013     (flush *(ebp+0x14))
 7014     (rewind-stream *(ebp+8))
 7015     (write-stream-data *(ebp+0x14) *(ebp+8))
 7016     (write-buffered *(ebp+0x14) "'\n")
 7017     (flush *(ebp+0x14))
 7018     (stop *(ebp+0x18) 1)
 7019     # never gets here
 7020 
 7021 $populate-mu-function-header:error2:
 7022     # error("fn " fn ": function inout '" var "' cannot be in a register")
 7023     (write-buffered *(ebp+0x14) "fn ")
 7024     50/push-eax
 7025     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 7026     (write-buffered *(ebp+0x14) %eax)
 7027     58/pop-to-eax
 7028     (write-buffered *(ebp+0x14) ": function inout '")
 7029     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 7030     (write-buffered *(ebp+0x10) %eax)
 7031     (write-buffered *(ebp+0x14) "' cannot be in a register")
 7032     (flush *(ebp+0x14))
 7033     (stop *(ebp+0x18) 1)
 7034     # never gets here
 7035 
 7036 $populate-mu-function-header:error3:
 7037     # error("fn " fn ": function output '" var "' must be in a register")
 7038     (write-buffered *(ebp+0x14) "fn ")
 7039     50/push-eax
 7040     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 7041     (write-buffered *(ebp+0x14) %eax)
 7042     58/pop-to-eax
 7043     (write-buffered *(ebp+0x14) ": function output '")
 7044     (lookup *ebx *(ebx+4))  # => eax
 7045     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 7046     (write-buffered *(ebp+0x14) %eax)
 7047     (write-buffered *(ebp+0x14) "' must be in a register, in instruction '")
 7048     (rewind-stream *(ebp+8))
 7049     (write-stream-data *(ebp+0x14) *(ebp+8))
 7050     (write-buffered *(ebp+0x14) "'\n")
 7051     (flush *(ebp+0x14))
 7052     (stop *(ebp+0x18) 1)
 7053     # never gets here
 7054 
 7055 # scenarios considered:
 7056 # ✓ fn foo
 7057 # ✗ fn foo {
 7058 # ✓ fn foo x
 7059 # ✓ fn foo x: int
 7060 # ✓ fn foo x: int -> y/eax: int
 7061 # TODO:
 7062 #   disallow outputs of type `(... addr ...)`
 7063 #   disallow inputs of type `(... addr ... addr ...)`
 7064 populate-mu-function-signature:  # first-line: (addr stream byte), out: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 7065     # pseudocode:
 7066     #   var word-slice: slice
 7067     #   next-mu-token(first-line, word-slice)
 7068     #   assert(word-slice not in '{' '}' '->')
 7069     #   out->name = slice-to-string(word-slice)
 7070     #   ## inouts
 7071     #   while true
 7072     #     word-slice = next-mu-token(first-line)
 7073     #     if slice-empty?(word-slice) break
 7074     #     if (word-slice == '->') break
 7075     #     assert(word-slice not in '{' '}')
 7076     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 7077     #     assert(v->register == null)
 7078     #     # v->block-depth is implicitly 0
 7079     #     out->inouts = append(v, out->inouts)
 7080     #   ## outputs
 7081     #   while true
 7082     #     word-slice = next-mu-token(first-line)
 7083     #     if slice-empty?(word-slice) break
 7084     #     assert(word-slice not in '{' '}' '->')
 7085     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 7086     #     assert(v->register != null)
 7087     #     out->outputs = append(v, out->outputs)
 7088     #
 7089     # . prologue
 7090     55/push-ebp
 7091     89/<- %ebp 4/r32/esp
 7092     # . save registers
 7093     50/push-eax
 7094     51/push-ecx
 7095     52/push-edx
 7096     53/push-ebx
 7097     57/push-edi
 7098     # edi = out
 7099     8b/-> *(ebp+0xc) 7/r32/edi
 7100     # var word-slice/ecx: slice
 7101     68/push 0/imm32/end
 7102     68/push 0/imm32/start
 7103     89/<- %ecx 4/r32/esp
 7104     # var v/ebx: (handle var)
 7105     68/push 0/imm32
 7106     68/push 0/imm32
 7107     89/<- %ebx 4/r32/esp
 7108     # read function name
 7109     (next-mu-token *(ebp+8) %ecx)
 7110     # error checking
 7111     # if (word-slice == '{') abort
 7112     (slice-equal? %ecx "{")   # => eax
 7113     3d/compare-eax-and 0/imm32/false
 7114     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7115     # if (word-slice == '->') abort
 7116     (slice-equal? %ecx "->")   # => eax
 7117     3d/compare-eax-and 0/imm32/false
 7118     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7119     # if (word-slice == '}') abort
 7120     (slice-equal? %ecx "}")   # => eax
 7121     3d/compare-eax-and 0/imm32/false
 7122     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7123     # save function name
 7124     (slice-to-string Heap %ecx %edi)  # Function-name
 7125     # save function inouts
 7126     {
 7127 $populate-mu-function-signature:check-for-inout:
 7128       (next-mu-token *(ebp+8) %ecx)
 7129       (slice-empty? %ecx)  # => eax
 7130       3d/compare-eax-and 0/imm32/false
 7131       0f 85/jump-if-!= break/disp32
 7132       # if (word-slice == '->') break
 7133       (slice-equal? %ecx "->")   # => eax
 7134       3d/compare-eax-and 0/imm32/false
 7135       0f 85/jump-if-!= break/disp32
 7136       # if (word-slice == '{') abort
 7137       (slice-equal? %ecx "{")   # => eax
 7138       3d/compare-eax-and 0/imm32/false
 7139       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7140       # if (word-slice == '}') abort
 7141       (slice-equal? %ecx "}")   # => eax
 7142       3d/compare-eax-and 0/imm32/false
 7143       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7144       # v = parse-var-with-type(word-slice, first-line)
 7145       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
 7146       # assert(v->register == null)
 7147       # . eax: (addr var) = lookup(v)
 7148       (lookup *ebx *(ebx+4))  # => eax
 7149       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 7150       0f 85/jump-if-!= $populate-mu-function-signature:error2/disp32
 7151       # v->block-depth is implicitly 0
 7152       #
 7153       # out->inouts = append(v, out->inouts)
 7154       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 7155       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 7156       #
 7157       e9/jump loop/disp32
 7158     }
 7159     # save function outputs
 7160     {
 7161 $populate-mu-function-signature:check-for-out:
 7162       (next-mu-token *(ebp+8) %ecx)
 7163       (slice-empty? %ecx)  # => eax
 7164       3d/compare-eax-and 0/imm32/false
 7165       0f 85/jump-if-!= break/disp32
 7166       # if (word-slice == '{') abort
 7167       (slice-equal? %ecx "{")   # => eax
 7168       3d/compare-eax-and 0/imm32/false
 7169       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7170       # if (word-slice == '->') abort
 7171       (slice-equal? %ecx "->")   # => eax
 7172       3d/compare-eax-and 0/imm32/false
 7173       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7174       # if (word-slice == '}') abort
 7175       (slice-equal? %ecx "}")   # => eax
 7176       3d/compare-eax-and 0/imm32/false
 7177       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7178       # v = parse-var-with-type(word-slice, first-line)
 7179       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
 7180       # assert(var->register != null)
 7181       # . eax: (addr var) = lookup(v)
 7182       (lookup *ebx *(ebx+4))  # => eax
 7183       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 7184       0f 84/jump-if-= $populate-mu-function-signature:error3/disp32
 7185       # out->outputs = append(v, out->outputs)
 7186       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 7187       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 7188       #
 7189       e9/jump loop/disp32
 7190     }
 7191 $populate-mu-function-signature:done:
 7192     (check-no-tokens-left *(ebp+8))
 7193 $populate-mu-function-signature:end:
 7194     # . reclaim locals
 7195     81 0/subop/add %esp 0x10/imm32
 7196     # . restore registers
 7197     5f/pop-to-edi
 7198     5b/pop-to-ebx
 7199     5a/pop-to-edx
 7200     59/pop-to-ecx
 7201     58/pop-to-eax
 7202     # . epilogue
 7203     89/<- %esp 5/r32/ebp
 7204     5d/pop-to-ebp
 7205     c3/return
 7206 
 7207 $populate-mu-function-signature:error1:
 7208     # error("function signature not in form 'fn <name> {'")
 7209     (write-buffered *(ebp+0x10) "function signature not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 7210     (flush *(ebp+0x10))
 7211     (rewind-stream *(ebp+8))
 7212     (write-stream-data *(ebp+0x10) *(ebp+8))
 7213     (write-buffered *(ebp+0x10) "'\n")
 7214     (flush *(ebp+0x10))
 7215     (stop *(ebp+0x14) 1)
 7216     # never gets here
 7217 
 7218 $populate-mu-function-signature:error2:
 7219     # error("fn " fn ": function inout '" var "' cannot be in a register")
 7220     (write-buffered *(ebp+0x10) "fn ")
 7221     50/push-eax
 7222     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 7223     (write-buffered *(ebp+0x10) %eax)
 7224     58/pop-to-eax
 7225     (write-buffered *(ebp+0x10) ": function inout '")
 7226     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 7227     (write-buffered *(ebp+0x10) %eax)
 7228     (write-buffered *(ebp+0x10) "' cannot be in a register")
 7229     (flush *(ebp+0x10))
 7230     (stop *(ebp+0x14) 1)
 7231     # never gets here
 7232 
 7233 $populate-mu-function-signature:error3:
 7234     # error("fn " fn ": function output '" var "' must be in a register")
 7235     (write-buffered *(ebp+0x10) "fn ")
 7236     50/push-eax
 7237     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 7238     (write-buffered *(ebp+0x10) %eax)
 7239     58/pop-to-eax
 7240     (write-buffered *(ebp+0x10) ": function output '")
 7241     (lookup *ebx *(ebx+4))  # => eax
 7242     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 7243     (write-buffered *(ebp+0x10) %eax)
 7244     (write-buffered *(ebp+0x10) "' must be in a register, in instruction '")
 7245     (rewind-stream *(ebp+8))
 7246     (write-stream-data *(ebp+0x10) *(ebp+8))
 7247     (write-buffered *(ebp+0x10) "'\n")
 7248     (flush *(ebp+0x10))
 7249     (stop *(ebp+0x14) 1)
 7250     # never gets here
 7251 
 7252 test-function-header-with-arg:
 7253     # . prologue
 7254     55/push-ebp
 7255     89/<- %ebp 4/r32/esp
 7256     # setup
 7257     (clear-stream _test-input-stream)
 7258     (write _test-input-stream "foo n: int {\n")
 7259     # var result/ecx: function
 7260     2b/subtract *Function-size 4/r32/esp
 7261     89/<- %ecx 4/r32/esp
 7262     (zero-out %ecx *Function-size)
 7263     # var vars/ebx: (stack live-var 16)
 7264     81 5/subop/subtract %esp 0xc0/imm32
 7265     68/push 0xc0/imm32/size
 7266     68/push 0/imm32/top
 7267     89/<- %ebx 4/r32/esp
 7268     # convert
 7269     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 7270     # check result->name
 7271     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 7272     (check-strings-equal %eax "foo" "F - test-function-header-with-arg/name")
 7273     # var v/edx: (addr var) = result->inouts->value
 7274     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 7275     (lookup *eax *(eax+4))  # List-value List-value => eax
 7276     89/<- %edx 0/r32/eax
 7277     # check v->name
 7278     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 7279     (check-strings-equal %eax "n" "F - test-function-header-with-arg/inout:0")
 7280     # check v->type
 7281     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 7282     (check-ints-equal *eax 1 "F - test-function-header-with-arg/inout:0/type:0")  # Type-tree-is-atom
 7283     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-arg/inout:0/type:1")  # Type-tree-value
 7284     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-arg/inout:0/type:2")  # Type-tree-right
 7285     # . epilogue
 7286     89/<- %esp 5/r32/ebp
 7287     5d/pop-to-ebp
 7288     c3/return
 7289 
 7290 test-function-header-with-multiple-args:
 7291     # . prologue
 7292     55/push-ebp
 7293     89/<- %ebp 4/r32/esp
 7294     # setup
 7295     (clear-stream _test-input-stream)
 7296     (write _test-input-stream "foo a: int, b: int c: int {\n")
 7297     # result/ecx: function
 7298     2b/subtract *Function-size 4/r32/esp
 7299     89/<- %ecx 4/r32/esp
 7300     (zero-out %ecx *Function-size)
 7301     # var vars/ebx: (stack live-var 16)
 7302     81 5/subop/subtract %esp 0xc0/imm32
 7303     68/push 0xc0/imm32/size
 7304     68/push 0/imm32/top
 7305     89/<- %ebx 4/r32/esp
 7306     # convert
 7307     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 7308     # check result->name
 7309     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 7310     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args/name")
 7311     # var inouts/edx: (addr list var) = lookup(result->inouts)
 7312     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 7313     89/<- %edx 0/r32/eax
 7314 $test-function-header-with-multiple-args:inout0:
 7315     # var v/ebx: (addr var) = lookup(inouts->value)
 7316     (lookup *edx *(edx+4))  # List-value List-value => eax
 7317     89/<- %ebx 0/r32/eax
 7318     # check v->name
 7319     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7320     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args/inout:0")  # Var-name
 7321     # check v->type
 7322     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7323     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:0/type:0")  # Type-tree-is-atom
 7324     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:0/type:1")  # Type-tree-value
 7325     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:0/type:2")  # Type-tree-right
 7326 $test-function-header-with-multiple-args:inout1:
 7327     # inouts = lookup(inouts->next)
 7328     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 7329     89/<- %edx 0/r32/eax
 7330     # v = lookup(inouts->value)
 7331     (lookup *edx *(edx+4))  # List-value List-value => eax
 7332     89/<- %ebx 0/r32/eax
 7333     # check v->name
 7334     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7335     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args/inout:1")  # Var-name
 7336     # check v->type
 7337     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7338     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:1/type:0")  # Type-tree-is-atom
 7339     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:1/type:1")  # Type-tree-value
 7340     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:1/type:2")  # Type-tree-right
 7341 $test-function-header-with-multiple-args:inout2:
 7342     # inouts = lookup(inouts->next)
 7343     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 7344     89/<- %edx 0/r32/eax
 7345     # v = lookup(inouts->value)
 7346     (lookup *edx *(edx+4))  # List-value List-value => eax
 7347     89/<- %ebx 0/r32/eax
 7348     # check v->name
 7349     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7350     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args/inout:2")  # Var-name
 7351     # check v->type
 7352     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7353     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:2/type:0")  # Type-tree-is-atom
 7354     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:2/type:1")  # Type-tree-value
 7355     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:2/type:2")  # Type-tree-right
 7356     # . epilogue
 7357     89/<- %esp 5/r32/ebp
 7358     5d/pop-to-ebp
 7359     c3/return
 7360 
 7361 test-function-header-with-multiple-args-and-outputs:
 7362     # . prologue
 7363     55/push-ebp
 7364     89/<- %ebp 4/r32/esp
 7365     # setup
 7366     (clear-stream _test-input-stream)
 7367     (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n")
 7368     # result/ecx: function
 7369     2b/subtract *Function-size 4/r32/esp
 7370     89/<- %ecx 4/r32/esp
 7371     (zero-out %ecx *Function-size)
 7372     # var vars/ebx: (stack live-var 16)
 7373     81 5/subop/subtract %esp 0xc0/imm32
 7374     68/push 0xc0/imm32/size
 7375     68/push 0/imm32/top
 7376     89/<- %ebx 4/r32/esp
 7377     # convert
 7378     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 7379     # check result->name
 7380     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 7381     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args-and-outputs/name")
 7382     # var inouts/edx: (addr list var) = lookup(result->inouts)
 7383     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 7384     89/<- %edx 0/r32/eax
 7385 $test-function-header-with-multiple-args-and-outputs:inout0:
 7386     # var v/ebx: (addr var) = lookup(inouts->value)
 7387     (lookup *edx *(edx+4))  # List-value List-value => eax
 7388     89/<- %ebx 0/r32/eax
 7389     # check v->name
 7390     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7391     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0")
 7392     # check v->type
 7393     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7394     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0")  # Type-tree-is-atom
 7395     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1")  # Type-tree-value
 7396     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:2")  # Type-tree-right
 7397 $test-function-header-with-multiple-args-and-outputs:inout1:
 7398     # inouts = lookup(inouts->next)
 7399     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 7400     89/<- %edx 0/r32/eax
 7401     # v = lookup(inouts->value)
 7402     (lookup *edx *(edx+4))  # List-value List-value => eax
 7403     89/<- %ebx 0/r32/eax
 7404     # check v->name
 7405     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7406     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1")
 7407     # check v->type
 7408     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7409     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0")  # Type-tree-is-atom
 7410     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1")  # Type-tree-value
 7411     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:2")  # Type-tree-right
 7412 $test-function-header-with-multiple-args-and-outputs:inout2:
 7413     # inouts = lookup(inouts->next)
 7414     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 7415     89/<- %edx 0/r32/eax
 7416     # v = lookup(inouts->value)
 7417     (lookup *edx *(edx+4))  # List-value List-value => eax
 7418     89/<- %ebx 0/r32/eax
 7419     # check v->name
 7420     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7421     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2")
 7422     # check v->type
 7423     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7424     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0")  # Type-tree-is-atom
 7425     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1")  # Type-tree-value
 7426     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:2")  # Type-tree-right
 7427 $test-function-header-with-multiple-args-and-outputs:out0:
 7428     # var outputs/edx: (addr list var) = lookup(result->outputs)
 7429     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 7430     89/<- %edx 0/r32/eax
 7431     # v = lookup(outputs->value)
 7432     (lookup *edx *(edx+4))  # List-value List-value => eax
 7433     89/<- %ebx 0/r32/eax
 7434     # check v->name
 7435     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7436     (check-strings-equal %eax "x" "F - test-function-header-with-multiple-args-and-outputs/output:0")
 7437     # check v->register
 7438     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 7439     (check-strings-equal %eax "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register")
 7440     # check v->type
 7441     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7442     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:0")  # Type-tree-is-atom
 7443     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1")  # Type-tree-value
 7444     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:2")  # Type-tree-right
 7445 $test-function-header-with-multiple-args-and-outputs:out1:
 7446     # outputs = lookup(outputs->next)
 7447     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 7448     89/<- %edx 0/r32/eax
 7449     # v = lookup(inouts->value)
 7450     (lookup *edx *(edx+4))  # List-value List-value => eax
 7451     89/<- %ebx 0/r32/eax
 7452     # check v->name
 7453     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7454     (check-strings-equal %eax "y" "F - test-function-header-with-multiple-args-and-outputs/output:1")
 7455     # check v->register
 7456     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 7457     (check-strings-equal %eax "edx" "F - test-function-header-with-multiple-args-and-outputs/output:1/register")
 7458     # check v->type
 7459     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7460     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:0")  # Type-tree-is-atom
 7461     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1")  # Type-tree-value
 7462     (check-ints-equal *(eax+0c) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:2")  # Type-tree-right
 7463     # . epilogue
 7464     89/<- %esp 5/r32/ebp
 7465     5d/pop-to-ebp
 7466     c3/return
 7467 
 7468 # format for variables with types
 7469 #   x: int
 7470 #   x: int,
 7471 #   x/eax: int
 7472 #   x/eax: int,
 7473 # ignores at most one trailing comma
 7474 # WARNING: modifies name
 7475 parse-var-with-type:  # name: (addr slice), first-line: (addr stream byte), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 7476     # pseudocode:
 7477     #   var s: slice
 7478     #   if (!slice-ends-with(name, ":"))
 7479     #     abort
 7480     #   --name->end to skip ':'
 7481     #   next-token-from-slice(name->start, name->end, '/', s)
 7482     #   new-var-from-slice(s, out)
 7483     #   ## register
 7484     #   next-token-from-slice(s->end, name->end, '/', s)
 7485     #   if (!slice-empty?(s))
 7486     #     out->register = slice-to-string(s)
 7487     #   ## type
 7488     #   var type: (handle type-tree) = parse-type(first-line)
 7489     #   out->type = type
 7490     #
 7491     # . prologue
 7492     55/push-ebp
 7493     89/<- %ebp 4/r32/esp
 7494     # . save registers
 7495     50/push-eax
 7496     51/push-ecx
 7497     52/push-edx
 7498     53/push-ebx
 7499     56/push-esi
 7500     57/push-edi
 7501     # esi = name
 7502     8b/-> *(ebp+8) 6/r32/esi
 7503     # if (!slice-ends-with?(name, ":")) abort
 7504     8b/-> *(esi+4) 1/r32/ecx  # Slice-end
 7505     49/decrement-ecx
 7506     8a/copy-byte *ecx 1/r32/CL
 7507     81 4/subop/and %ecx 0xff/imm32
 7508     81 7/subop/compare %ecx 0x3a/imm32/colon
 7509     0f 85/jump-if-!= $parse-var-with-type:abort/disp32
 7510     # --name->end to skip ':'
 7511     ff 1/subop/decrement *(esi+4)
 7512     # var s/ecx: slice
 7513     68/push 0/imm32/end
 7514     68/push 0/imm32/start
 7515     89/<- %ecx 4/r32/esp
 7516 $parse-var-with-type:parse-name:
 7517     (next-token-from-slice *esi *(esi+4) 0x2f %ecx)  # Slice-start, Slice-end, '/'
 7518 $parse-var-with-type:create-var:
 7519     # new-var-from-slice(s, out)
 7520     (new-var-from-slice Heap %ecx *(ebp+0x10))
 7521     # save out->register
 7522 $parse-var-with-type:save-register:
 7523     # . var out-addr/edi: (addr var) = lookup(*out)
 7524     8b/-> *(ebp+0x10) 7/r32/edi
 7525     (lookup *edi *(edi+4))  # => eax
 7526     89/<- %edi 0/r32/eax
 7527     # . s = next-token(...)
 7528     (next-token-from-slice *(ecx+4) *(esi+4) 0x2f %ecx)  # s->end, name->end, '/'
 7529     # . if (!slice-empty?(s)) out->register = slice-to-string(s)
 7530     {
 7531 $parse-var-with-type:write-register:
 7532       (slice-empty? %ecx)  # => eax
 7533       3d/compare-eax-and 0/imm32/false
 7534       75/jump-if-!= break/disp8
 7535       # out->register = slice-to-string(s)
 7536       8d/copy-address *(edi+0x18) 0/r32/eax  # Var-register
 7537       (slice-to-string Heap %ecx %eax)
 7538     }
 7539 $parse-var-with-type:save-type:
 7540     8d/copy-address *(edi+8) 0/r32/eax  # Var-type
 7541     (parse-type Heap *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 7542 $parse-var-with-type:end:
 7543     # . reclaim locals
 7544     81 0/subop/add %esp 8/imm32
 7545     # . restore registers
 7546     5f/pop-to-edi
 7547     5e/pop-to-esi
 7548     5b/pop-to-ebx
 7549     5a/pop-to-edx
 7550     59/pop-to-ecx
 7551     58/pop-to-eax
 7552     # . epilogue
 7553     89/<- %esp 5/r32/ebp
 7554     5d/pop-to-ebp
 7555     c3/return
 7556 
 7557 $parse-var-with-type:abort:
 7558     # error("var should have form 'name: type' in '" line "'\n")
 7559     (write-buffered *(ebp+0x14) "var should have form 'name: type' in '")
 7560     (flush *(ebp+0x14))
 7561     (rewind-stream *(ebp+0xc))
 7562     (write-stream-data *(ebp+0x14) *(ebp+0xc))
 7563     (write-buffered *(ebp+0x14) "'\n")
 7564     (flush *(ebp+0x14))
 7565     (stop *(ebp+0x18) 1)
 7566     # never gets here
 7567 
 7568 parse-type:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
 7569     # pseudocode:
 7570     #   var s: slice = next-mu-token(in)
 7571     #   assert s != ""
 7572     #   assert s != "->"
 7573     #   assert s != "{"
 7574     #   assert s != "}"
 7575     #   if s == ")"
 7576     #     return
 7577     #   out = allocate(Type-tree)
 7578     #   if s != "("
 7579     #     HACK: if s is an int, parse and return it
 7580     #     out->is-atom? = true
 7581     #     if (s[0] == "_")
 7582     #       out->value = type-parameter
 7583     #       out->parameter-name = slice-to-string(ad, s)
 7584     #     else
 7585     #       out->value = pos-or-insert-slice(Type-id, s)
 7586     #     return
 7587     #   out->left = parse-type(ad, in)
 7588     #   out->right = parse-type-tree(ad, in)
 7589     #
 7590     # . prologue
 7591     55/push-ebp
 7592     89/<- %ebp 4/r32/esp
 7593     # . save registers
 7594     50/push-eax
 7595     51/push-ecx
 7596     52/push-edx
 7597     # clear out
 7598     (zero-out *(ebp+0x10) *Handle-size)
 7599     # var s/ecx: slice
 7600     68/push 0/imm32
 7601     68/push 0/imm32
 7602     89/<- %ecx 4/r32/esp
 7603     # s = next-mu-token(in)
 7604     (next-mu-token *(ebp+0xc) %ecx)
 7605 #?     (write-buffered Stderr "tok: ")
 7606 #?     (write-slice-buffered Stderr %ecx)
 7607 #?     (write-buffered Stderr "$\n")
 7608 #?     (flush Stderr)
 7609     # assert s != ""
 7610     (slice-equal? %ecx "")  # => eax
 7611     3d/compare-eax-and 0/imm32/false
 7612     0f 85/jump-if-!= $parse-type:abort/disp32
 7613     # assert s != "{"
 7614     (slice-equal? %ecx "{")  # => eax
 7615     3d/compare-eax-and 0/imm32/false
 7616     0f 85/jump-if-!= $parse-type:abort/disp32
 7617     # assert s != "}"
 7618     (slice-equal? %ecx "}")  # => eax
 7619     3d/compare-eax-and 0/imm32/false
 7620     0f 85/jump-if-!= $parse-type:abort/disp32
 7621     # assert s != "->"
 7622     (slice-equal? %ecx "->")  # => eax
 7623     3d/compare-eax-and 0/imm32/false
 7624     0f 85/jump-if-!= $parse-type:abort/disp32
 7625     # if (s == ")") return
 7626     (slice-equal? %ecx ")")  # => eax
 7627     3d/compare-eax-and 0/imm32/false
 7628     0f 85/jump-if-!= $parse-type:end/disp32
 7629     # out = new tree
 7630     (allocate *(ebp+8) *Type-tree-size *(ebp+0x10))
 7631     # var out-addr/edx: (addr type-tree) = lookup(*out)
 7632     8b/-> *(ebp+0x10) 2/r32/edx
 7633     (lookup *edx *(edx+4))  # => eax
 7634     89/<- %edx 0/r32/eax
 7635     {
 7636       # if (s != "(") break
 7637       (slice-equal? %ecx "(")  # => eax
 7638       3d/compare-eax-and 0/imm32/false
 7639       0f 85/jump-if-!= break/disp32
 7640       # if s is a number, store it in the type's size field
 7641       {
 7642 $parse-type:check-for-int:
 7643         # var tmp/eax: byte = *s->slice
 7644         8b/-> *ecx 0/r32/eax
 7645         8a/copy-byte *eax 0/r32/AL
 7646         81 4/subop/and %eax 0xff/imm32
 7647         # TODO: raise an error on `var x: (array int a)`
 7648         (is-decimal-digit? %eax)  # => eax
 7649         3d/compare-eax-and 0/imm32/false
 7650         74/jump-if-= break/disp8
 7651         #
 7652         (is-hex-int? %ecx)  # => eax
 7653         3d/compare-eax-and 0/imm32/false
 7654         74/jump-if-= break/disp8
 7655 $parse-type:int:
 7656         (check-mu-hex-int %ecx *(ebp+0x14) *(ebp+0x18))
 7657         (parse-hex-int-from-slice %ecx)  # => eax
 7658         c7 0/subop/copy *(edx+4) 9/imm32/type-id-array-capacity  # Type-tree-value
 7659         89/<- *(edx+8) 0/r32/eax  # Type-tree-value-size
 7660         e9/jump $parse-type:end/disp32
 7661       }
 7662 $parse-type:atom:
 7663       # out->is-atom? = true
 7664       c7 0/subop/copy *edx 1/imm32/true  # Type-tree-is-atom
 7665       {
 7666 $parse-type:check-for-type-parameter:
 7667         # var tmp/eax: byte = *s->slice
 7668         8b/-> *ecx 0/r32/eax
 7669         8a/copy-byte *eax 0/r32/AL
 7670         81 4/subop/and %eax 0xff/imm32
 7671         # if (tmp != '_') break
 7672         3d/compare-eax-and 0x5f/imm32/_
 7673         75/jump-if-!= break/disp8
 7674 $parse-type:type-parameter:
 7675         # out->value = type-parameter
 7676         c7 0/subop/copy *(edx+4) 0xa/imm32/type-parameter  # Type-tree-value
 7677         # out->parameter-name = slice-to-string(ad, s)
 7678         8d/copy-address *(edx+8) 0/r32/eax  # Type-tree-parameter-name
 7679         (slice-to-string *(ebp+8) %ecx %eax)
 7680         e9/jump $parse-type:end/disp32
 7681       }
 7682 $parse-type:non-type-parameter:
 7683       # out->value = pos-or-insert-slice(Type-id, s)
 7684       (pos-or-insert-slice Type-id %ecx)  # => eax
 7685       89/<- *(edx+4) 0/r32/eax  # Type-tree-value
 7686       e9/jump $parse-type:end/disp32
 7687     }
 7688 $parse-type:non-atom:
 7689     # otherwise s == "("
 7690     # out->left = parse-type(ad, in)
 7691     8d/copy-address *(edx+4) 0/r32/eax  # Type-tree-left
 7692     (parse-type *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 7693     # out->right = parse-type-tree(ad, in)
 7694     8d/copy-address *(edx+0xc) 0/r32/eax  # Type-tree-right
 7695     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 7696 $parse-type:end:
 7697     # . reclaim locals
 7698     81 0/subop/add %esp 8/imm32
 7699     # . restore registers
 7700     5a/pop-to-edx
 7701     59/pop-to-ecx
 7702     58/pop-to-eax
 7703     # . epilogue
 7704     89/<- %esp 5/r32/ebp
 7705     5d/pop-to-ebp
 7706     c3/return
 7707 
 7708 $parse-type:abort:
 7709     # error("unexpected token when parsing type: '" s "'\n")
 7710     (write-buffered *(ebp+0x14) "unexpected token when parsing type: '")
 7711     (write-slice-buffered *(ebp+0x14) %ecx)
 7712     (write-buffered *(ebp+0x14) "'\n")
 7713     (flush *(ebp+0x14))
 7714     (stop *(ebp+0x18) 1)
 7715     # never gets here
 7716 
 7717 parse-type-tree:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
 7718     # pseudocode:
 7719     #   var tmp: (handle type-tree) = parse-type(ad, in)
 7720     #   if tmp == 0
 7721     #     return 0
 7722     #   out = allocate(Type-tree)
 7723     #   out->left = tmp
 7724     #   out->right = parse-type-tree(ad, in)
 7725     #
 7726     # . prologue
 7727     55/push-ebp
 7728     89/<- %ebp 4/r32/esp
 7729     # . save registers
 7730     50/push-eax
 7731     51/push-ecx
 7732     52/push-edx
 7733     #
 7734     (zero-out *(ebp+0x10) *Handle-size)
 7735     # var tmp/ecx: (handle type-tree)
 7736     68/push 0/imm32
 7737     68/push 0/imm32
 7738     89/<- %ecx 4/r32/esp
 7739     # tmp = parse-type(ad, in)
 7740     (parse-type *(ebp+8) *(ebp+0xc) %ecx *(ebp+0x14) *(ebp+0x18))
 7741     # if (tmp == 0) return
 7742     81 7/subop/compare *ecx 0/imm32
 7743     74/jump-if-= $parse-type-tree:end/disp8
 7744     # out = new tree
 7745     (allocate *(ebp+8) *Type-tree-size *(ebp+0x10))
 7746     # var out-addr/edx: (addr tree) = lookup(*out)
 7747     8b/-> *(ebp+0x10) 2/r32/edx
 7748     (lookup *edx *(edx+4))  # => eax
 7749     89/<- %edx 0/r32/eax
 7750     # out->left = tmp
 7751     8b/-> *ecx 0/r32/eax
 7752     89/<- *(edx+4) 0/r32/eax  # Type-tree-left
 7753     8b/-> *(ecx+4) 0/r32/eax
 7754     89/<- *(edx+8) 0/r32/eax  # Type-tree-left
 7755     # out->right = parse-type-tree(ad, in)
 7756     8d/copy-address *(edx+0xc) 0/r32/eax  # Type-tree-right
 7757     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 7758 $parse-type-tree:end:
 7759     # . reclaim locals
 7760     81 0/subop/add %esp 8/imm32
 7761     # . restore registers
 7762     5a/pop-to-edx
 7763     59/pop-to-ecx
 7764     58/pop-to-eax
 7765     # . epilogue
 7766     89/<- %esp 5/r32/ebp
 7767     5d/pop-to-ebp
 7768     c3/return
 7769 
 7770 next-mu-token:  # in: (addr stream byte), out: (addr slice)
 7771     # pseudocode:
 7772     # start:
 7773     #   skip-chars-matching-whitespace(in)
 7774     #   if in->read >= in->write              # end of in
 7775     #     out = {0, 0}
 7776     #     return
 7777     #   out->start = &in->data[in->read]
 7778     #   var curr-byte/eax: byte = in->data[in->read]
 7779     #   if curr->byte == ','                  # comment token
 7780     #     ++in->read
 7781     #     goto start
 7782     #   if curr-byte == '#'                   # comment
 7783     #     goto done                             # treat as eof
 7784     #   if curr-byte == '"'                   # string literal
 7785     #     skip-string(in)
 7786     #     goto done                           # no metadata
 7787     #   if curr-byte == '('
 7788     #     ++in->read
 7789     #     goto done
 7790     #   if curr-byte == ')'
 7791     #     ++in->read
 7792     #     goto done
 7793     #   # read a word
 7794     #   while true
 7795     #     if in->read >= in->write
 7796     #       break
 7797     #     curr-byte = in->data[in->read]
 7798     #     if curr-byte == ' '
 7799     #       break
 7800     #     if curr-byte == '\r'
 7801     #       break
 7802     #     if curr-byte == '\n'
 7803     #       break
 7804     #     if curr-byte == '('
 7805     #       break
 7806     #     if curr-byte == ')'
 7807     #       break
 7808     #     if curr-byte == ','
 7809     #       break
 7810     #     ++in->read
 7811     # done:
 7812     #   out->end = &in->data[in->read]
 7813     #
 7814     # . prologue
 7815     55/push-ebp
 7816     89/<- %ebp 4/r32/esp
 7817     # . save registers
 7818     50/push-eax
 7819     51/push-ecx
 7820     56/push-esi
 7821     57/push-edi
 7822     # esi = in
 7823     8b/-> *(ebp+8) 6/r32/esi
 7824     # edi = out
 7825     8b/-> *(ebp+0xc) 7/r32/edi
 7826 $next-mu-token:start:
 7827     (skip-chars-matching-whitespace %esi)
 7828 $next-mu-token:check0:
 7829     # if (in->read >= in->write) return out = {0, 0}
 7830     # . ecx = in->read
 7831     8b/-> *(esi+4) 1/r32/ecx
 7832     # . if (ecx >= in->write) return out = {0, 0}
 7833     3b/compare<- *esi 1/r32/ecx
 7834     c7 0/subop/copy *edi 0/imm32
 7835     c7 0/subop/copy *(edi+4) 0/imm32
 7836     0f 8d/jump-if->= $next-mu-token:end/disp32
 7837     # out->start = &in->data[in->read]
 7838     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 7839     89/<- *edi 0/r32/eax
 7840     # var curr-byte/eax: byte = in->data[in->read]
 7841     31/xor-with %eax 0/r32/eax
 7842     8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 7843     {
 7844 $next-mu-token:check-for-comma:
 7845       # if (curr-byte != ',') break
 7846       3d/compare-eax-and 0x2c/imm32/comma
 7847       75/jump-if-!= break/disp8
 7848       # ++in->read
 7849       ff 0/subop/increment *(esi+4)
 7850       # restart
 7851       e9/jump $next-mu-token:start/disp32
 7852     }
 7853     {
 7854 $next-mu-token:check-for-comment:
 7855       # if (curr-byte != '#') break
 7856       3d/compare-eax-and 0x23/imm32/pound
 7857       75/jump-if-!= break/disp8
 7858       # return eof
 7859       e9/jump $next-mu-token:done/disp32
 7860     }
 7861     {
 7862 $next-mu-token:check-for-string-literal:
 7863       # if (curr-byte != '"') break
 7864       3d/compare-eax-and 0x22/imm32/dquote
 7865       75/jump-if-!= break/disp8
 7866       (skip-string %esi)
 7867       # return
 7868       e9/jump $next-mu-token:done/disp32
 7869     }
 7870     {
 7871 $next-mu-token:check-for-open-paren:
 7872       # if (curr-byte != '(') break
 7873       3d/compare-eax-and 0x28/imm32/open-paren
 7874       75/jump-if-!= break/disp8
 7875       # ++in->read
 7876       ff 0/subop/increment *(esi+4)
 7877       # return
 7878       e9/jump $next-mu-token:done/disp32
 7879     }
 7880     {
 7881 $next-mu-token:check-for-close-paren:
 7882       # if (curr-byte != ')') break
 7883       3d/compare-eax-and 0x29/imm32/close-paren
 7884       75/jump-if-!= break/disp8
 7885       # ++in->read
 7886       ff 0/subop/increment *(esi+4)
 7887       # return
 7888       e9/jump $next-mu-token:done/disp32
 7889     }
 7890     {
 7891 $next-mu-token:regular-word-without-metadata:
 7892       # if (in->read >= in->write) break
 7893       # . ecx = in->read
 7894       8b/-> *(esi+4) 1/r32/ecx
 7895       # . if (ecx >= in->write) break
 7896       3b/compare<- *esi 1/r32/ecx
 7897       7d/jump-if->= break/disp8
 7898       # var c/eax: byte = in->data[in->read]
 7899       31/xor-with %eax 0/r32/eax
 7900       8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 7901       # if (c == ' ') break
 7902       3d/compare-eax-and 0x20/imm32/space
 7903       74/jump-if-= break/disp8
 7904       # if (c == '\r') break
 7905       3d/compare-eax-and 0xd/imm32/carriage-return
 7906       74/jump-if-= break/disp8
 7907       # if (c == '\n') break
 7908       3d/compare-eax-and 0xa/imm32/newline
 7909       74/jump-if-= break/disp8
 7910       # if (c == '(') break
 7911       3d/compare-eax-and 0x28/imm32/open-paren
 7912       0f 84/jump-if-= break/disp32
 7913       # if (c == ')') break
 7914       3d/compare-eax-and 0x29/imm32/close-paren
 7915       0f 84/jump-if-= break/disp32
 7916       # if (c == ',') break
 7917       3d/compare-eax-and 0x2c/imm32/comma
 7918       0f 84/jump-if-= break/disp32
 7919       # ++in->read
 7920       ff 0/subop/increment *(esi+4)
 7921       #
 7922       e9/jump loop/disp32
 7923     }
 7924 $next-mu-token:done:
 7925     # out->end = &in->data[in->read]
 7926     8b/-> *(esi+4) 1/r32/ecx
 7927     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 7928     89/<- *(edi+4) 0/r32/eax
 7929 $next-mu-token:end:
 7930     # . restore registers
 7931     5f/pop-to-edi
 7932     5e/pop-to-esi
 7933     59/pop-to-ecx
 7934     58/pop-to-eax
 7935     # . epilogue
 7936     89/<- %esp 5/r32/ebp
 7937     5d/pop-to-ebp
 7938     c3/return
 7939 
 7940 pos-or-insert-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 7941     # . prologue
 7942     55/push-ebp
 7943     89/<- %ebp 4/r32/esp
 7944     # if (pos-slice(arr, s) != -1) return it
 7945     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 7946     3d/compare-eax-and -1/imm32
 7947     75/jump-if-!= $pos-or-insert-slice:end/disp8
 7948 $pos-or-insert-slice:insert:
 7949     # var s2/eax: (handle array byte)
 7950     68/push 0/imm32
 7951     68/push 0/imm32
 7952     89/<- %eax 4/r32/esp
 7953     (slice-to-string Heap *(ebp+0xc) %eax)
 7954     # throw away alloc-id
 7955     (lookup *eax *(eax+4))  # => eax
 7956     (write-int *(ebp+8) %eax)
 7957     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 7958 $pos-or-insert-slice:end:
 7959     # . reclaim locals
 7960     81 0/subop/add %esp 8/imm32
 7961     # . epilogue
 7962     89/<- %esp 5/r32/ebp
 7963     5d/pop-to-ebp
 7964     c3/return
 7965 
 7966 # return the index in an array of strings matching 's', -1 if not found
 7967 # index is denominated in elements, not bytes
 7968 pos-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 7969     # . prologue
 7970     55/push-ebp
 7971     89/<- %ebp 4/r32/esp
 7972     # . save registers
 7973     51/push-ecx
 7974     52/push-edx
 7975     53/push-ebx
 7976     56/push-esi
 7977 #?     (write-buffered Stderr "pos-slice: ")
 7978 #?     (write-slice-buffered Stderr *(ebp+0xc))
 7979 #?     (write-buffered Stderr "\n")
 7980 #?     (flush Stderr)
 7981     # esi = arr
 7982     8b/-> *(ebp+8) 6/r32/esi
 7983     # var index/ecx: int = 0
 7984     b9/copy-to-ecx 0/imm32
 7985     # var curr/edx: (addr (addr array byte)) = arr->data
 7986     8d/copy-address *(esi+0xc) 2/r32/edx
 7987     # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write]
 7988     8b/-> *esi 3/r32/ebx
 7989     8d/copy-address *(esi+ebx+0xc) 3/r32/ebx
 7990     {
 7991 #?       (write-buffered Stderr "  ")
 7992 #?       (write-int32-hex-buffered Stderr %ecx)
 7993 #?       (write-buffered Stderr "\n")
 7994 #?       (flush Stderr)
 7995       # if (curr >= max) return -1
 7996       39/compare %edx 3/r32/ebx
 7997       b8/copy-to-eax -1/imm32
 7998       73/jump-if-addr>= $pos-slice:end/disp8
 7999       # if (slice-equal?(s, *curr)) break
 8000       (slice-equal? *(ebp+0xc) *edx)  # => eax
 8001       3d/compare-eax-and 0/imm32/false
 8002       75/jump-if-!= break/disp8
 8003       # ++index
 8004       41/increment-ecx
 8005       # curr += 4
 8006       81 0/subop/add %edx 4/imm32
 8007       #
 8008       eb/jump loop/disp8
 8009     }
 8010     # return index
 8011     89/<- %eax 1/r32/ecx
 8012 $pos-slice:end:
 8013 #?     (write-buffered Stderr "=> ")
 8014 #?     (write-int32-hex-buffered Stderr %eax)
 8015 #?     (write-buffered Stderr "\n")
 8016     # . restore registers
 8017     5e/pop-to-esi
 8018     5b/pop-to-ebx
 8019     5a/pop-to-edx
 8020     59/pop-to-ecx
 8021     # . epilogue
 8022     89/<- %esp 5/r32/ebp
 8023     5d/pop-to-ebp
 8024     c3/return
 8025 
 8026 test-parse-var-with-type:
 8027     # . prologue
 8028     55/push-ebp
 8029     89/<- %ebp 4/r32/esp
 8030     # (eax..ecx) = "x:"
 8031     b8/copy-to-eax "x:"/imm32
 8032     8b/-> *eax 1/r32/ecx
 8033     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8034     05/add-to-eax 4/imm32
 8035     # var slice/ecx: slice = {eax, ecx}
 8036     51/push-ecx
 8037     50/push-eax
 8038     89/<- %ecx 4/r32/esp
 8039     # _test-input-stream contains "int"
 8040     (clear-stream _test-input-stream)
 8041     (write _test-input-stream "int")
 8042     # var v/edx: (handle var)
 8043     68/push 0/imm32
 8044     68/push 0/imm32
 8045     89/<- %edx 4/r32/esp
 8046     #
 8047     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 8048     # var v-addr/edx: (addr var) = lookup(v)
 8049     (lookup *edx *(edx+4))  # => eax
 8050     89/<- %edx 0/r32/eax
 8051     # check v-addr->name
 8052     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8053     (check-strings-equal %eax "x" "F - test-parse-var-with-type/name")
 8054     # check v-addr->type
 8055     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8056     (check-ints-equal *eax 1 "F - test-parse-var-with-type/type:0")  # Type-tree-is-atom
 8057     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type/type:1")  # Type-tree-value
 8058     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type/type:2")  # Type-tree-right
 8059     # . epilogue
 8060     89/<- %esp 5/r32/ebp
 8061     5d/pop-to-ebp
 8062     c3/return
 8063 
 8064 test-parse-var-with-type-and-register:
 8065     # . prologue
 8066     55/push-ebp
 8067     89/<- %ebp 4/r32/esp
 8068     # (eax..ecx) = "x/eax:"
 8069     b8/copy-to-eax "x/eax:"/imm32
 8070     8b/-> *eax 1/r32/ecx
 8071     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8072     05/add-to-eax 4/imm32
 8073     # var slice/ecx: slice = {eax, ecx}
 8074     51/push-ecx
 8075     50/push-eax
 8076     89/<- %ecx 4/r32/esp
 8077     # _test-input-stream contains "int"
 8078     (clear-stream _test-input-stream)
 8079     (write _test-input-stream "int")
 8080     # var v/edx: (handle var)
 8081     68/push 0/imm32
 8082     68/push 0/imm32
 8083     89/<- %edx 4/r32/esp
 8084     #
 8085     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 8086     # var v-addr/edx: (addr var) = lookup(v)
 8087     (lookup *edx *(edx+4))  # => eax
 8088     89/<- %edx 0/r32/eax
 8089     # check v-addr->name
 8090     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8091     (check-strings-equal %eax "x" "F - test-parse-var-with-type-and-register/name")
 8092     # check v-addr->register
 8093     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 8094     (check-strings-equal %eax "eax" "F - test-parse-var-with-type-and-register/register")
 8095     # check v-addr->type
 8096     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8097     (check-ints-equal *eax 1 "F - test-parse-var-with-type-and-register/type:0")  # Type-tree-is-atom
 8098     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type-and-register/type:1")  # Type-tree-left
 8099     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type-and-register/type:2")  # Type-tree-right
 8100     # . epilogue
 8101     89/<- %esp 5/r32/ebp
 8102     5d/pop-to-ebp
 8103     c3/return
 8104 
 8105 test-parse-var-with-trailing-characters:
 8106     # . prologue
 8107     55/push-ebp
 8108     89/<- %ebp 4/r32/esp
 8109     # (eax..ecx) = "x:"
 8110     b8/copy-to-eax "x:"/imm32
 8111     8b/-> *eax 1/r32/ecx
 8112     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8113     05/add-to-eax 4/imm32
 8114     # var slice/ecx: slice = {eax, ecx}
 8115     51/push-ecx
 8116     50/push-eax
 8117     89/<- %ecx 4/r32/esp
 8118     # _test-input-stream contains "int,"
 8119     (clear-stream _test-input-stream)
 8120     (write _test-input-stream "int,")
 8121     # var v/edx: (handle var)
 8122     68/push 0/imm32
 8123     68/push 0/imm32
 8124     89/<- %edx 4/r32/esp
 8125     #
 8126     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 8127     # var v-addr/edx: (addr var) = lookup(v)
 8128     (lookup *edx *(edx+4))  # => eax
 8129     89/<- %edx 0/r32/eax
 8130     # check v-addr->name
 8131     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8132     (check-strings-equal %eax "x" "F - test-parse-var-with-trailing-characters/name")
 8133     # check v-addr->register
 8134     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-trailing-characters/register")  # Var-register
 8135     # check v-addr->type
 8136     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8137     (check-ints-equal *eax 1 "F - test-parse-var-with-trailing-characters/type:0")  # Type-tree-is-atom
 8138     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-trailing-characters/type:1")  # Type-tree-left
 8139     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-trailing-characters/type:1")  # Type-tree-right
 8140     # . epilogue
 8141     89/<- %esp 5/r32/ebp
 8142     5d/pop-to-ebp
 8143     c3/return
 8144 
 8145 test-parse-var-with-register-and-trailing-characters:
 8146     # . prologue
 8147     55/push-ebp
 8148     89/<- %ebp 4/r32/esp
 8149     # (eax..ecx) = "x/eax:"
 8150     b8/copy-to-eax "x/eax:"/imm32
 8151     8b/-> *eax 1/r32/ecx
 8152     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8153     05/add-to-eax 4/imm32
 8154     # var slice/ecx: slice = {eax, ecx}
 8155     51/push-ecx
 8156     50/push-eax
 8157     89/<- %ecx 4/r32/esp
 8158     # _test-input-stream contains "int,"
 8159     (clear-stream _test-input-stream)
 8160     (write _test-input-stream "int,")
 8161     # var v/edx: (handle var)
 8162     68/push 0/imm32
 8163     68/push 0/imm32
 8164     89/<- %edx 4/r32/esp
 8165     #
 8166     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 8167     # var v-addr/edx: (addr var) = lookup(v)
 8168     (lookup *edx *(edx+4))  # => eax
 8169     89/<- %edx 0/r32/eax
 8170     # check v-addr->name
 8171     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8172     (check-strings-equal %eax "x" "F - test-parse-var-with-register-and-trailing-characters/name")
 8173     # check v-addr->register
 8174     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 8175     (check-strings-equal %eax "eax" "F - test-parse-var-with-register-and-trailing-characters/register")
 8176     # check v-addr->type
 8177     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8178     (check-ints-equal *eax 1 "F - test-parse-var-with-register-and-trailing-characters/type:0")  # Type-tree-is-atom
 8179     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-register-and-trailing-characters/type:1")  # Type-tree-left
 8180     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-register-and-trailing-characters/type:2")  # Type-tree-right
 8181     # . epilogue
 8182     89/<- %esp 5/r32/ebp
 8183     5d/pop-to-ebp
 8184     c3/return
 8185 
 8186 test-parse-var-with-compound-type:
 8187     # . prologue
 8188     55/push-ebp
 8189     89/<- %ebp 4/r32/esp
 8190     # (eax..ecx) = "x:"
 8191     b8/copy-to-eax "x:"/imm32
 8192     8b/-> *eax 1/r32/ecx
 8193     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8194     05/add-to-eax 4/imm32
 8195     # var slice/ecx: slice = {eax, ecx}
 8196     51/push-ecx
 8197     50/push-eax
 8198     89/<- %ecx 4/r32/esp
 8199     # _test-input-stream contains "(addr int)"
 8200     (clear-stream _test-input-stream)
 8201     (write _test-input-stream "(addr int)")
 8202     # var v/edx: (handle var)
 8203     68/push 0/imm32
 8204     68/push 0/imm32
 8205     89/<- %edx 4/r32/esp
 8206     #
 8207     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 8208     # var v-addr/edx: (addr var) = lookup(v)
 8209     (lookup *edx *(edx+4))  # => eax
 8210     89/<- %edx 0/r32/eax
 8211     # check v-addr->name
 8212     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8213     (check-strings-equal %eax "x" "F - test-parse-var-with-compound-type/name")
 8214     # check v-addr->register
 8215     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-compound-type/register")  # Var-register
 8216     # - check v-addr->type
 8217     # var type/edx: (addr type-tree) = var->type
 8218     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8219     89/<- %edx 0/r32/eax
 8220     # type is a non-atom
 8221     (check-ints-equal *edx 0 "F - test-parse-var-with-compound-type/type:0")  # Type-tree-is-atom
 8222     # type->left == atom(addr)
 8223     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
 8224     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:1")  # Type-tree-is-atom
 8225     (check-ints-equal *(eax+4) 2 "F - test-parse-var-with-compound-type/type:2")  # Type-tree-value
 8226     # type->right->left == atom(int)
 8227     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
 8228     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
 8229     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:3")  # Type-tree-is-atom
 8230     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-compound-type/type:4")  # Type-tree-value
 8231     # type->right->right == null
 8232     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-compound-type/type:5")  # Type-tree-right
 8233     # . epilogue
 8234     89/<- %esp 5/r32/ebp
 8235     5d/pop-to-ebp
 8236     c3/return
 8237 
 8238 # identifier starts with a letter or '$' or '_'
 8239 # no constraints at the moment on later letters
 8240 # all we really want to do so far is exclude '{', '}' and '->'
 8241 is-identifier?:  # in: (addr slice) -> result/eax: boolean
 8242     # . prologue
 8243     55/push-ebp
 8244     89/<- %ebp 4/r32/esp
 8245     # if (slice-empty?(in)) return false
 8246     (slice-empty? *(ebp+8))  # => eax
 8247     3d/compare-eax-and 0/imm32/false
 8248     75/jump-if-!= $is-identifier?:false/disp8
 8249     # var c/eax: byte = *in->start
 8250     8b/-> *(ebp+8) 0/r32/eax
 8251     8b/-> *eax 0/r32/eax
 8252     8a/copy-byte *eax 0/r32/AL
 8253     81 4/subop/and %eax 0xff/imm32
 8254     # if (c == '$') return true
 8255     3d/compare-eax-and 0x24/imm32/$
 8256     74/jump-if-= $is-identifier?:true/disp8
 8257     # if (c == '_') return true
 8258     3d/compare-eax-and 0x5f/imm32/_
 8259     74/jump-if-= $is-identifier?:true/disp8
 8260     # drop case
 8261     25/and-eax-with 0x5f/imm32
 8262     # if (c < 'A') return false
 8263     3d/compare-eax-and 0x41/imm32/A
 8264     7c/jump-if-< $is-identifier?:false/disp8
 8265     # if (c > 'Z') return false
 8266     3d/compare-eax-and 0x5a/imm32/Z
 8267     7f/jump-if-> $is-identifier?:false/disp8
 8268     # otherwise return true
 8269 $is-identifier?:true:
 8270     b8/copy-to-eax 1/imm32/true
 8271     eb/jump $is-identifier?:end/disp8
 8272 $is-identifier?:false:
 8273     b8/copy-to-eax 0/imm32/false
 8274 $is-identifier?:end:
 8275     # . epilogue
 8276     89/<- %esp 5/r32/ebp
 8277     5d/pop-to-ebp
 8278     c3/return
 8279 
 8280 test-is-identifier-dollar:
 8281     # . prologue
 8282     55/push-ebp
 8283     89/<- %ebp 4/r32/esp
 8284     # (eax..ecx) = "$a"
 8285     b8/copy-to-eax "$a"/imm32
 8286     8b/-> *eax 1/r32/ecx
 8287     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8288     05/add-to-eax 4/imm32
 8289     # var slice/ecx: slice = {eax, ecx}
 8290     51/push-ecx
 8291     50/push-eax
 8292     89/<- %ecx 4/r32/esp
 8293     #
 8294     (is-identifier? %ecx)
 8295     (check-ints-equal %eax 1 "F - test-is-identifier-dollar")
 8296     # . epilogue
 8297     89/<- %esp 5/r32/ebp
 8298     5d/pop-to-ebp
 8299     c3/return
 8300 
 8301 test-is-identifier-underscore:
 8302     # . prologue
 8303     55/push-ebp
 8304     89/<- %ebp 4/r32/esp
 8305     # (eax..ecx) = "_a"
 8306     b8/copy-to-eax "_a"/imm32
 8307     8b/-> *eax 1/r32/ecx
 8308     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8309     05/add-to-eax 4/imm32
 8310     # var slice/ecx: slice = {eax, ecx}
 8311     51/push-ecx
 8312     50/push-eax
 8313     89/<- %ecx 4/r32/esp
 8314     #
 8315     (is-identifier? %ecx)
 8316     (check-ints-equal %eax 1 "F - test-is-identifier-underscore")
 8317     # . epilogue
 8318     89/<- %esp 5/r32/ebp
 8319     5d/pop-to-ebp
 8320     c3/return
 8321 
 8322 test-is-identifier-a:
 8323     # . prologue
 8324     55/push-ebp
 8325     89/<- %ebp 4/r32/esp
 8326     # (eax..ecx) = "a$"
 8327     b8/copy-to-eax "a$"/imm32
 8328     8b/-> *eax 1/r32/ecx
 8329     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8330     05/add-to-eax 4/imm32
 8331     # var slice/ecx: slice = {eax, ecx}
 8332     51/push-ecx
 8333     50/push-eax
 8334     89/<- %ecx 4/r32/esp
 8335     #
 8336     (is-identifier? %ecx)
 8337     (check-ints-equal %eax 1 "F - test-is-identifier-a")
 8338     # . epilogue
 8339     89/<- %esp 5/r32/ebp
 8340     5d/pop-to-ebp
 8341     c3/return
 8342 
 8343 test-is-identifier-z:
 8344     # . prologue
 8345     55/push-ebp
 8346     89/<- %ebp 4/r32/esp
 8347     # (eax..ecx) = "z$"
 8348     b8/copy-to-eax "z$"/imm32
 8349     8b/-> *eax 1/r32/ecx
 8350     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8351     05/add-to-eax 4/imm32
 8352     # var slice/ecx: slice = {eax, ecx}
 8353     51/push-ecx
 8354     50/push-eax
 8355     89/<- %ecx 4/r32/esp
 8356     #
 8357     (is-identifier? %ecx)
 8358     (check-ints-equal %eax 1 "F - test-is-identifier-z")
 8359     # . epilogue
 8360     89/<- %esp 5/r32/ebp
 8361     5d/pop-to-ebp
 8362     c3/return
 8363 
 8364 test-is-identifier-A:
 8365     # . prologue
 8366     55/push-ebp
 8367     89/<- %ebp 4/r32/esp
 8368     # (eax..ecx) = "A$"
 8369     b8/copy-to-eax "A$"/imm32
 8370     8b/-> *eax 1/r32/ecx
 8371     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8372     05/add-to-eax 4/imm32
 8373     # var slice/ecx: slice = {eax, ecx}
 8374     51/push-ecx
 8375     50/push-eax
 8376     89/<- %ecx 4/r32/esp
 8377     #
 8378     (is-identifier? %ecx)
 8379     (check-ints-equal %eax 1 "F - test-is-identifier-A")
 8380     # . epilogue
 8381     89/<- %esp 5/r32/ebp
 8382     5d/pop-to-ebp
 8383     c3/return
 8384 
 8385 test-is-identifier-Z:
 8386     # . prologue
 8387     55/push-ebp
 8388     89/<- %ebp 4/r32/esp
 8389     # (eax..ecx) = "Z$"
 8390     b8/copy-to-eax "Z$"/imm32
 8391     8b/-> *eax 1/r32/ecx
 8392     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8393     05/add-to-eax 4/imm32
 8394     # var slice/ecx: slice = {eax, ecx}
 8395     51/push-ecx
 8396     50/push-eax
 8397     89/<- %ecx 4/r32/esp
 8398     #
 8399     (is-identifier? %ecx)
 8400     (check-ints-equal %eax 1 "F - test-is-identifier-Z")
 8401     # . epilogue
 8402     89/<- %esp 5/r32/ebp
 8403     5d/pop-to-ebp
 8404     c3/return
 8405 
 8406 test-is-identifier-at:
 8407     # character before 'A' is invalid
 8408     # . prologue
 8409     55/push-ebp
 8410     89/<- %ebp 4/r32/esp
 8411     # (eax..ecx) = "@a"
 8412     b8/copy-to-eax "@a"/imm32
 8413     8b/-> *eax 1/r32/ecx
 8414     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8415     05/add-to-eax 4/imm32
 8416     # var slice/ecx: slice = {eax, ecx}
 8417     51/push-ecx
 8418     50/push-eax
 8419     89/<- %ecx 4/r32/esp
 8420     #
 8421     (is-identifier? %ecx)
 8422     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 8423     # . epilogue
 8424     89/<- %esp 5/r32/ebp
 8425     5d/pop-to-ebp
 8426     c3/return
 8427 
 8428 test-is-identifier-square-bracket:
 8429     # character after 'Z' is invalid
 8430     # . prologue
 8431     55/push-ebp
 8432     89/<- %ebp 4/r32/esp
 8433     # (eax..ecx) = "[a"
 8434     b8/copy-to-eax "[a"/imm32
 8435     8b/-> *eax 1/r32/ecx
 8436     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8437     05/add-to-eax 4/imm32
 8438     # var slice/ecx: slice = {eax, ecx}
 8439     51/push-ecx
 8440     50/push-eax
 8441     89/<- %ecx 4/r32/esp
 8442     #
 8443     (is-identifier? %ecx)
 8444     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 8445     # . epilogue
 8446     89/<- %esp 5/r32/ebp
 8447     5d/pop-to-ebp
 8448     c3/return
 8449 
 8450 test-is-identifier-backtick:
 8451     # character before 'a' is invalid
 8452     # . prologue
 8453     55/push-ebp
 8454     89/<- %ebp 4/r32/esp
 8455     # (eax..ecx) = "`a"
 8456     b8/copy-to-eax "`a"/imm32
 8457     8b/-> *eax 1/r32/ecx
 8458     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8459     05/add-to-eax 4/imm32
 8460     # var slice/ecx: slice = {eax, ecx}
 8461     51/push-ecx
 8462     50/push-eax
 8463     89/<- %ecx 4/r32/esp
 8464     #
 8465     (is-identifier? %ecx)
 8466     (check-ints-equal %eax 0 "F - test-is-identifier-backtick")
 8467     # . epilogue
 8468     89/<- %esp 5/r32/ebp
 8469     5d/pop-to-ebp
 8470     c3/return
 8471 
 8472 test-is-identifier-curly-brace-open:
 8473     # character after 'z' is invalid; also used for blocks
 8474     # . prologue
 8475     55/push-ebp
 8476     89/<- %ebp 4/r32/esp
 8477     # (eax..ecx) = "{a"
 8478     b8/copy-to-eax "{a"/imm32
 8479     8b/-> *eax 1/r32/ecx
 8480     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8481     05/add-to-eax 4/imm32
 8482     # var slice/ecx: slice = {eax, ecx}
 8483     51/push-ecx
 8484     50/push-eax
 8485     89/<- %ecx 4/r32/esp
 8486     #
 8487     (is-identifier? %ecx)
 8488     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open")
 8489     # . epilogue
 8490     89/<- %esp 5/r32/ebp
 8491     5d/pop-to-ebp
 8492     c3/return
 8493 
 8494 test-is-identifier-curly-brace-close:
 8495     # . prologue
 8496     55/push-ebp
 8497     89/<- %ebp 4/r32/esp
 8498     # (eax..ecx) = "}a"
 8499     b8/copy-to-eax "}a"/imm32
 8500     8b/-> *eax 1/r32/ecx
 8501     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8502     05/add-to-eax 4/imm32
 8503     # var slice/ecx: slice = {eax, ecx}
 8504     51/push-ecx
 8505     50/push-eax
 8506     89/<- %ecx 4/r32/esp
 8507     #
 8508     (is-identifier? %ecx)
 8509     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close")
 8510     # . epilogue
 8511     89/<- %esp 5/r32/ebp
 8512     5d/pop-to-ebp
 8513     c3/return
 8514 
 8515 test-is-identifier-hyphen:
 8516     # disallow leading '-' since '->' has special meaning
 8517     # . prologue
 8518     55/push-ebp
 8519     89/<- %ebp 4/r32/esp
 8520     # (eax..ecx) = "-a"
 8521     b8/copy-to-eax "-a"/imm32
 8522     8b/-> *eax 1/r32/ecx
 8523     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8524     05/add-to-eax 4/imm32
 8525     # var slice/ecx: slice = {eax, ecx}
 8526     51/push-ecx
 8527     50/push-eax
 8528     89/<- %ecx 4/r32/esp
 8529     #
 8530     (is-identifier? %ecx)
 8531     (check-ints-equal %eax 0 "F - test-is-identifier-hyphen")
 8532     # . epilogue
 8533     89/<- %esp 5/r32/ebp
 8534     5d/pop-to-ebp
 8535     c3/return
 8536 
 8537 populate-mu-function-body:  # in: (addr buffered-file), out: (addr function), vars: (addr stack live-var), err: (addr buffered-file), ed: (addr exit-descriptor)
 8538     # . prologue
 8539     55/push-ebp
 8540     89/<- %ebp 4/r32/esp
 8541     # . save registers
 8542     50/push-eax
 8543     56/push-esi
 8544     57/push-edi
 8545     # esi = in
 8546     8b/-> *(ebp+8) 6/r32/esi
 8547     # edi = out
 8548     8b/-> *(ebp+0xc) 7/r32/edi
 8549     # initialize some global state
 8550     c7 0/subop/copy *Curr-block-depth 1/imm32
 8551     # parse-mu-block(in, vars, out, out->body)
 8552     8d/copy-address *(edi+0x18) 0/r32/eax  # Function-body
 8553     (parse-mu-block %esi *(ebp+0x10) %edi %eax *(ebp+0x14) *(ebp+0x18))
 8554 $populate-mu-function-body:end:
 8555     # . restore registers
 8556     5f/pop-to-edi
 8557     5e/pop-to-esi
 8558     58/pop-to-eax
 8559     # . epilogue
 8560     89/<- %esp 5/r32/ebp
 8561     5d/pop-to-ebp
 8562     c3/return
 8563 
 8564 # parses a block, assuming that the leading '{' has already been read by the caller
 8565 parse-mu-block:  # in: (addr buffered-file), vars: (addr stack live-var), fn: (addr function), out: (addr handle block), err: (addr buffered-file), ed: (addr exit-descriptor)
 8566     # pseudocode:
 8567     #   var line: (stream byte 512)
 8568     #   var word-slice: slice
 8569     #   allocate(Heap, Stmt-size, out)
 8570     #   var out-addr: (addr block) = lookup(*out)
 8571     #   out-addr->tag = 0/block
 8572     #   out-addr->var = some unique name
 8573     #   push(vars, {out-addr->var, false})
 8574     #   while true                                  # line loop
 8575     #     clear-stream(line)
 8576     #     read-line-buffered(in, line)
 8577     #     if (line->write == 0) break               # end of file
 8578     #     word-slice = next-mu-token(line)
 8579     #     if slice-empty?(word-slice)               # end of line
 8580     #       continue
 8581     #     else if slice-starts-with?(word-slice, "#")
 8582     #       continue
 8583     #     else if slice-equal?(word-slice, "{")
 8584     #       assert(no-tokens-in(line))
 8585     #       block = parse-mu-block(in, vars, fn)
 8586     #       append-to-block(out-addr, block)
 8587     #     else if slice-equal?(word-slice, "}")
 8588     #       break
 8589     #     else if slice-ends-with?(word-slice, ":")
 8590     #       # TODO: error-check the rest of 'line'
 8591     #       --word-slice->end to skip ':'
 8592     #       named-block = parse-mu-named-block(word-slice, in, vars, fn)
 8593     #       append-to-block(out-addr, named-block)
 8594     #     else if slice-equal?(word-slice, "var")
 8595     #       var-def = parse-mu-var-def(line, vars, fn)
 8596     #       append-to-block(out-addr, var-def)
 8597     #     else
 8598     #       stmt = parse-mu-stmt(line, vars, fn)
 8599     #       append-to-block(out-addr, stmt)
 8600     #   pop(vars)
 8601     #
 8602     # . prologue
 8603     55/push-ebp
 8604     89/<- %ebp 4/r32/esp
 8605     # . save registers
 8606     50/push-eax
 8607     51/push-ecx
 8608     52/push-edx
 8609     53/push-ebx
 8610     57/push-edi
 8611     # var line/ecx: (stream byte 512)
 8612     81 5/subop/subtract %esp 0x200/imm32
 8613     68/push 0x200/imm32/size
 8614     68/push 0/imm32/read
 8615     68/push 0/imm32/write
 8616     89/<- %ecx 4/r32/esp
 8617     # var word-slice/edx: slice
 8618     68/push 0/imm32/end
 8619     68/push 0/imm32/start
 8620     89/<- %edx 4/r32/esp
 8621     # allocate into out
 8622     (allocate Heap *Stmt-size *(ebp+0x14))
 8623     # var out-addr/edi: (addr block) = lookup(*out)
 8624     8b/-> *(ebp+0x14) 7/r32/edi
 8625     (lookup *edi *(edi+4))  # => eax
 8626     89/<- %edi 0/r32/eax
 8627     # out-addr->tag is 0 (block) by default
 8628     # set out-addr->var
 8629     8d/copy-address *(edi+0xc) 0/r32/eax  # Block-var
 8630     (new-block-name *(ebp+0x10) %eax)
 8631     # push(vars, out-addr->var)
 8632     (push *(ebp+0xc) *(edi+0xc))  # Block-var
 8633     (push *(ebp+0xc) *(edi+0x10))  # Block-var
 8634     (push *(ebp+0xc) 0)  # false
 8635     # increment *Curr-block-depth
 8636     ff 0/subop/increment *Curr-block-depth
 8637     {
 8638 $parse-mu-block:line-loop:
 8639       # line = read-line-buffered(in)
 8640       (clear-stream %ecx)
 8641       (read-line-buffered *(ebp+8) %ecx)
 8642 #?       (write-buffered Stderr "line: ")
 8643 #?       (write-stream-data Stderr %ecx)
 8644 #? #?       (write-buffered Stderr Newline)  # line has its own newline
 8645 #?       (flush Stderr)
 8646 #?       (rewind-stream %ecx)
 8647       # if (line->write == 0) break
 8648       81 7/subop/compare *ecx 0/imm32
 8649       0f 84/jump-if-= break/disp32
 8650 #?       (write-buffered Stderr "vars:\n")
 8651 #?       (dump-vars *(ebp+0xc))
 8652       # word-slice = next-mu-token(line)
 8653       (next-mu-token %ecx %edx)
 8654 #?       (write-buffered Stderr "word: ")
 8655 #?       (write-slice-buffered Stderr %edx)
 8656 #?       (write-buffered Stderr Newline)
 8657 #?       (flush Stderr)
 8658       # if slice-empty?(word-slice) continue
 8659       (slice-empty? %edx)
 8660       3d/compare-eax-and 0/imm32/false
 8661       0f 85/jump-if-!= loop/disp32
 8662       # if (slice-starts-with?(word-slice, '#') continue
 8663       # . eax = *word-slice->start
 8664       8b/-> *edx 0/r32/eax
 8665       8a/copy-byte *eax 0/r32/AL
 8666       81 4/subop/and %eax 0xff/imm32
 8667       # . if (eax == '#') continue
 8668       3d/compare-eax-and 0x23/imm32/hash
 8669       0f 84/jump-if-= loop/disp32
 8670       # if slice-equal?(word-slice, "{")
 8671       {
 8672 $parse-mu-block:check-for-block:
 8673         (slice-equal? %edx "{")
 8674         3d/compare-eax-and 0/imm32/false
 8675         74/jump-if-= break/disp8
 8676         (check-no-tokens-left %ecx)
 8677         # parse new block and append
 8678         # . var tmp/eax: (handle block)
 8679         68/push 0/imm32
 8680         68/push 0/imm32
 8681         89/<- %eax 4/r32/esp
 8682         # .
 8683         (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 8684         (append-to-block Heap %edi  *eax *(eax+4))
 8685         # . reclaim tmp
 8686         81 0/subop/add %esp 8/imm32
 8687         # .
 8688         e9/jump $parse-mu-block:line-loop/disp32
 8689       }
 8690       # if slice-equal?(word-slice, "}") break
 8691 $parse-mu-block:check-for-end:
 8692       (slice-equal? %edx "}")
 8693       3d/compare-eax-and 0/imm32/false
 8694       0f 85/jump-if-!= break/disp32
 8695       # if slice-ends-with?(word-slice, ":") parse named block and append
 8696       {
 8697 $parse-mu-block:check-for-named-block:
 8698         # . eax = *(word-slice->end-1)
 8699         8b/-> *(edx+4) 0/r32/eax
 8700         48/decrement-eax
 8701         8a/copy-byte *eax 0/r32/AL
 8702         81 4/subop/and %eax 0xff/imm32
 8703         # . if (eax != ':') break
 8704         3d/compare-eax-and 0x3a/imm32/colon
 8705         0f 85/jump-if-!= break/disp32
 8706         # TODO: error-check the rest of 'line'
 8707         #
 8708         # skip ':'
 8709         ff 1/subop/decrement *(edx+4)  # Slice-end
 8710         # var tmp/eax: (handle block)
 8711         68/push 0/imm32
 8712         68/push 0/imm32
 8713         89/<- %eax 4/r32/esp
 8714         #
 8715         (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 8716         (append-to-block Heap %edi  *eax *(eax+4))
 8717         # reclaim tmp
 8718         81 0/subop/add %esp 8/imm32
 8719         #
 8720         e9/jump $parse-mu-block:line-loop/disp32
 8721       }
 8722       # if slice-equal?(word-slice, "var")
 8723       {
 8724 $parse-mu-block:check-for-var:
 8725         (slice-equal? %edx "var")
 8726         3d/compare-eax-and 0/imm32/false
 8727         74/jump-if-= break/disp8
 8728         # var tmp/eax: (handle block)
 8729         68/push 0/imm32
 8730         68/push 0/imm32
 8731         89/<- %eax 4/r32/esp
 8732         #
 8733         (parse-mu-var-def %ecx *(ebp+0xc) %eax *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 8734         (append-to-block Heap %edi  *eax *(eax+4))
 8735         # reclaim tmp
 8736         81 0/subop/add %esp 8/imm32
 8737         #
 8738         e9/jump $parse-mu-block:line-loop/disp32
 8739       }
 8740 $parse-mu-block:regular-stmt:
 8741       # otherwise
 8742       # var tmp/eax: (handle block)
 8743       68/push 0/imm32
 8744       68/push 0/imm32
 8745       89/<- %eax 4/r32/esp
 8746       #
 8747       (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 8748       (append-to-block Heap %edi  *eax *(eax+4))
 8749       # reclaim tmp
 8750       81 0/subop/add %esp 8/imm32
 8751       #
 8752       e9/jump loop/disp32
 8753     } # end line loop
 8754     (clean-up-blocks *(ebp+0xc) *Curr-block-depth *(ebp+0x10))
 8755     # decrement *Curr-block-depth
 8756     ff 1/subop/decrement *Curr-block-depth
 8757     # pop(vars)
 8758     (pop *(ebp+0xc))  # => eax
 8759     (pop *(ebp+0xc))  # => eax
 8760     (pop *(ebp+0xc))  # => eax
 8761 $parse-mu-block:end:
 8762     # . reclaim locals
 8763     81 0/subop/add %esp 0x214/imm32
 8764     # . restore registers
 8765     5f/pop-to-edi
 8766     5b/pop-to-ebx
 8767     5a/pop-to-edx
 8768     59/pop-to-ecx
 8769     58/pop-to-eax
 8770     # . epilogue
 8771     89/<- %esp 5/r32/ebp
 8772     5d/pop-to-ebp
 8773     c3/return
 8774 
 8775 $parse-mu-block:abort:
 8776     # error("'{' or '}' should be on its own line, but got '")
 8777     (write-buffered *(ebp+0x18) "'{' or '}' should be on its own line, but got '")
 8778     (rewind-stream %ecx)
 8779     (write-stream-data *(ebp+0x18) %ecx)
 8780     (write-buffered *(ebp+0x18) "'\n")
 8781     (flush *(ebp+0x18))
 8782     (stop *(ebp+0x1c) 1)
 8783     # never gets here
 8784 
 8785 new-block-name:  # fn: (addr function), out: (addr handle var)
 8786     # . prologue
 8787     55/push-ebp
 8788     89/<- %ebp 4/r32/esp
 8789     # . save registers
 8790     50/push-eax
 8791     51/push-ecx
 8792     52/push-edx
 8793     # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:'
 8794     8b/-> *(ebp+8) 0/r32/eax
 8795     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8796     8b/-> *eax 0/r32/eax  # String-size
 8797     05/add-to-eax 0xd/imm32  # 10 + 2 for '$:'
 8798     89/<- %ecx 0/r32/eax
 8799     # var name/edx: (stream byte n)
 8800     29/subtract-from %esp 1/r32/ecx
 8801     ff 6/subop/push %ecx
 8802     68/push 0/imm32/read
 8803     68/push 0/imm32/write
 8804     89/<- %edx 4/r32/esp
 8805     (clear-stream %edx)
 8806     # eax = fn->name
 8807     8b/-> *(ebp+8) 0/r32/eax
 8808     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8809     # construct result using Next-block-index (and increment it)
 8810     (write %edx "$")
 8811     (write %edx %eax)
 8812     (write %edx ":")
 8813     (write-int32-hex %edx *Next-block-index)
 8814     ff 0/subop/increment *Next-block-index
 8815     # var s/eax: slice = {name->data, name->data + name->write}  (clobbering edx)
 8816     # . eax = name->write
 8817     8b/-> *edx 0/r32/eax
 8818     # . edx = name->data
 8819     8d/copy-address *(edx+0xc) 2/r32/edx
 8820     # . eax = name->write + name->data
 8821     01/add-to %eax 2/r32/edx
 8822     # . push {edx, eax}
 8823     ff 6/subop/push %eax
 8824     ff 6/subop/push %edx
 8825     89/<- %eax 4/r32/esp
 8826     # out = new literal(s)
 8827     (new-literal Heap %eax *(ebp+0xc))
 8828 #?     8b/-> *(ebp+0xc) 0/r32/eax
 8829 #?     (write-buffered Stderr "type allocid in caller after new-literal: ")
 8830 #?     (write-int32-hex-buffered Stderr *(eax+8))
 8831 #?     (write-buffered Stderr " for var ")
 8832 #?     (write-int32-hex-buffered Stderr %eax)
 8833 #?     (write-buffered Stderr Newline)
 8834 #?     (flush Stderr)
 8835 $new-block-name:end:
 8836     # . reclaim locals
 8837     81 0/subop/add %ecx 0xc/imm32  # name.{read/write/len}
 8838     81 0/subop/add %ecx 8/imm32  # slice
 8839     01/add-to %esp 1/r32/ecx
 8840     # . restore registers
 8841     5a/pop-to-edx
 8842     59/pop-to-ecx
 8843     58/pop-to-eax
 8844     # . epilogue
 8845     89/<- %esp 5/r32/ebp
 8846     5d/pop-to-ebp
 8847     c3/return
 8848 
 8849 check-no-tokens-left:  # line: (addr stream byte)
 8850     # . prologue
 8851     55/push-ebp
 8852     89/<- %ebp 4/r32/esp
 8853     # . save registers
 8854     50/push-eax
 8855     51/push-ecx
 8856     # var s/ecx: slice
 8857     68/push 0/imm32/end
 8858     68/push 0/imm32/start
 8859     89/<- %ecx 4/r32/esp
 8860     #
 8861     (next-mu-token *(ebp+8) %ecx)
 8862     # if slice-empty?(s) return
 8863     (slice-empty? %ecx)
 8864     3d/compare-eax-and 0/imm32/false
 8865     75/jump-if-!= $check-no-tokens-left:end/disp8
 8866     # if (slice-starts-with?(s, '#') return
 8867     # . eax = *s->start
 8868     8b/-> *edx 0/r32/eax
 8869     8a/copy-byte *eax 0/r32/AL
 8870     81 4/subop/and %eax 0xff/imm32
 8871     # . if (eax == '#') continue
 8872     3d/compare-eax-and 0x23/imm32/hash
 8873     74/jump-if-= $check-no-tokens-left:end/disp8
 8874     # abort
 8875     (write-buffered Stderr "'{' or '}' should be on its own line, but got '")
 8876     (rewind-stream %ecx)
 8877     (write-stream 2 %ecx)
 8878     (write-buffered Stderr "'\n")
 8879     (flush Stderr)
 8880     # . syscall(exit, 1)
 8881     bb/copy-to-ebx  1/imm32
 8882     e8/call syscall_exit/disp32
 8883     # never gets here
 8884 $check-no-tokens-left:end:
 8885     # . reclaim locals
 8886     81 0/subop/add %esp 8/imm32
 8887     # . restore registers
 8888     59/pop-to-ecx
 8889     58/pop-to-eax
 8890     # . epilogue
 8891     89/<- %esp 5/r32/ebp
 8892     5d/pop-to-ebp
 8893     c3/return
 8894 
 8895 parse-mu-named-block:  # name: (addr slice), in: (addr buffered-file), vars: (addr stack live-var), fn: (addr function), out: (addr handle stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
 8896     # pseudocode:
 8897     #   var v: (handle var)
 8898     #   new-literal(name, v)
 8899     #   push(vars, {v, false})
 8900     #   parse-mu-block(in, vars, fn, out)
 8901     #   pop(vars)
 8902     #   out->tag = block
 8903     #   out->var = v
 8904     #
 8905     # . prologue
 8906     55/push-ebp
 8907     89/<- %ebp 4/r32/esp
 8908     # . save registers
 8909     50/push-eax
 8910     51/push-ecx
 8911     57/push-edi
 8912     # var v/ecx: (handle var)
 8913     68/push 0/imm32
 8914     68/push 0/imm32
 8915     89/<- %ecx 4/r32/esp
 8916     #
 8917     (new-literal Heap *(ebp+8) %ecx)
 8918     # push(vars, v)
 8919     (push *(ebp+0x10) *ecx)
 8920     (push *(ebp+0x10) *(ecx+4))
 8921     (push *(ebp+0x10) 0)  # false
 8922     #
 8923     (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20))
 8924     # pop v off vars
 8925     (pop *(ebp+0x10))  # => eax
 8926     (pop *(ebp+0x10))  # => eax
 8927     (pop *(ebp+0x10))  # => eax
 8928     # var out-addr/edi: (addr stmt) = lookup(*out)
 8929     8b/-> *(ebp+0x18) 7/r32/edi
 8930     (lookup *edi *(edi+4))  # => eax
 8931     89/<- %edi 0/r32/eax
 8932     # out-addr->tag = named-block
 8933     c7 0/subop/copy *edi 0/imm32/block  # Stmt-tag
 8934     # out-addr->var = v
 8935     8b/-> *ecx 0/r32/eax
 8936     89/<- *(edi+0xc) 0/r32/eax  # Block-var
 8937     8b/-> *(ecx+4) 0/r32/eax
 8938     89/<- *(edi+0x10) 0/r32/eax  # Block-var
 8939 $parse-mu-named-block:end:
 8940     # . reclaim locals
 8941     81 0/subop/add %esp 8/imm32
 8942     # . restore registers
 8943     5f/pop-to-edi
 8944     59/pop-to-ecx
 8945     58/pop-to-eax
 8946     # . epilogue
 8947     89/<- %esp 5/r32/ebp
 8948     5d/pop-to-ebp
 8949     c3/return
 8950 
 8951 parse-mu-var-def:  # line: (addr stream byte), vars: (addr stack live-var), out: (addr handle stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 8952     # . prologue
 8953     55/push-ebp
 8954     89/<- %ebp 4/r32/esp
 8955     # . save registers
 8956     50/push-eax
 8957     51/push-ecx
 8958     52/push-edx
 8959     53/push-ebx
 8960     57/push-edi
 8961     # edi = out
 8962     8b/-> *(ebp+0x10) 7/r32/edi
 8963     # var word-slice/ecx: slice
 8964     68/push 0/imm32/end
 8965     68/push 0/imm32/start
 8966     89/<- %ecx 4/r32/esp
 8967     # var v/edx: (handle var)
 8968     68/push 0/imm32
 8969     68/push 0/imm32
 8970     89/<- %edx 4/r32/esp
 8971     # v = parse-var-with-type(next-mu-token(line))
 8972     (next-mu-token *(ebp+8) %ecx)
 8973     (parse-var-with-type %ecx *(ebp+8) %edx *(ebp+0x18) *(ebp+0x1c))
 8974     # var v-addr/eax: (addr var)
 8975     (lookup *edx *(edx+4))  # => eax
 8976     # v->block-depth = *Curr-block-depth
 8977     8b/-> *Curr-block-depth 3/r32/ebx
 8978     89/<- *(eax+0x10) 3/r32/ebx  # Var-block-depth
 8979     # either v has no register and there's no more to this line
 8980     8b/-> *(eax+0x18) 0/r32/eax  # Var-register
 8981     3d/compare-eax-and 0/imm32
 8982     {
 8983       75/jump-if-!= break/disp8
 8984       # TODO: disallow vars of type 'byte' on the stack
 8985       # ensure that there's nothing else on this line
 8986       (next-mu-token *(ebp+8) %ecx)
 8987       (slice-empty? %ecx)  # => eax
 8988       3d/compare-eax-and 0/imm32/false
 8989       0f 84/jump-if-= $parse-mu-var-def:error2/disp32
 8990       #
 8991       (new-var-def Heap  *edx *(edx+4)  %edi)
 8992       e9/jump $parse-mu-var-def:update-vars/disp32
 8993     }
 8994     # or v has a register and there's more to this line
 8995     {
 8996       0f 84/jump-if-= break/disp32
 8997       # TODO: disallow vars of type 'byte' in registers 'esi' or 'edi'
 8998       # TODO: vars of type 'byte' should only be initialized by clearing to 0
 8999       # ensure that the next word is '<-'
 9000       (next-mu-token *(ebp+8) %ecx)
 9001       (slice-equal? %ecx "<-")  # => eax
 9002       3d/compare-eax-and 0/imm32/false
 9003       0f 84/jump-if-= $parse-mu-var-def:error1/disp32
 9004       #
 9005       (new-reg-var-def Heap  *edx *(edx+4)  %edi)
 9006       (lookup *edi *(edi+4))  # => eax
 9007       (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9008     }
 9009 $parse-mu-var-def:update-vars:
 9010     # push 'v' at end of function
 9011     (push *(ebp+0xc) *edx)
 9012     (push *(ebp+0xc) *(edx+4))
 9013     (push *(ebp+0xc) 0)  # Live-var-register-spilled is unused during parsing
 9014 $parse-mu-var-def:end:
 9015     # . reclaim locals
 9016     81 0/subop/add %esp 0x10/imm32
 9017     # . restore registers
 9018     5f/pop-to-edi
 9019     5b/pop-to-ebx
 9020     5a/pop-to-edx
 9021     59/pop-to-ecx
 9022     58/pop-to-eax
 9023     # . epilogue
 9024     89/<- %esp 5/r32/ebp
 9025     5d/pop-to-ebp
 9026     c3/return
 9027 
 9028 $parse-mu-var-def:error1:
 9029     (rewind-stream *(ebp+8))
 9030     # error("register variable requires a valid instruction to initialize but got '" line "'\n")
 9031     (write-buffered *(ebp+0x18) "register variable requires a valid instruction to initialize but got '")
 9032     (flush *(ebp+0x18))
 9033     (write-stream-data *(ebp+0x18) *(ebp+8))
 9034     (write-buffered *(ebp+0x18) "'\n")
 9035     (flush *(ebp+0x18))
 9036     (stop *(ebp+0x1c) 1)
 9037     # never gets here
 9038 
 9039 $parse-mu-var-def:error2:
 9040     (rewind-stream *(ebp+8))
 9041     # error("fn " fn ": var " var ": variables on the stack can't take an initializer\n")
 9042     (write-buffered *(ebp+0x18) "fn ")
 9043     8b/-> *(ebp+0x14) 0/r32/eax
 9044     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9045     (write-buffered *(ebp+0x18) %eax)
 9046     (write-buffered *(ebp+0x18) ": var ")
 9047     # var v-addr/eax: (addr var) = lookup(v)
 9048     (lookup *edx *(edx+4))  # => eax
 9049     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9050     (write-buffered *(ebp+0x18) %eax)
 9051     (write-buffered *(ebp+0x18) ": variables on the stack can't take an initializer\n")
 9052     (flush *(ebp+0x18))
 9053     (stop *(ebp+0x1c) 1)
 9054     # never gets here
 9055 
 9056 test-parse-mu-var-def:
 9057     # 'var n: int'
 9058     # . prologue
 9059     55/push-ebp
 9060     89/<- %ebp 4/r32/esp
 9061     # setup
 9062     (clear-stream _test-input-stream)
 9063     (write _test-input-stream "n: int\n")  # caller has consumed the 'var'
 9064     c7 0/subop/copy *Curr-block-depth 1/imm32
 9065     # var out/esi: (handle stmt)
 9066     68/push 0/imm32
 9067     68/push 0/imm32
 9068     89/<- %esi 4/r32/esp
 9069     # var vars/ecx: (stack (addr var) 16)
 9070     81 5/subop/subtract %esp 0xc0/imm32
 9071     68/push 0xc0/imm32/size
 9072     68/push 0/imm32/top
 9073     89/<- %ecx 4/r32/esp
 9074     (clear-stack %ecx)
 9075     # convert
 9076     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
 9077     # var out-addr/esi: (addr stmt)
 9078     (lookup *esi *(esi+4))  # => eax
 9079     89/<- %esi 0/r32/eax
 9080     #
 9081     (check-ints-equal *esi 2 "F - test-parse-mu-var-def/tag")  # Stmt-tag is var-def
 9082     # var v/ecx: (addr var) = lookup(out->var)
 9083     (lookup *(esi+4) *(esi+8))  # Vardef-var Vardef-var => eax
 9084     89/<- %ecx 0/r32/eax
 9085     # v->name
 9086     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 9087     (check-strings-equal %eax "n" "F - test-parse-mu-var-def/var-name")
 9088     # v->register
 9089     (check-ints-equal *(ecx+0x18) 0 "F - test-parse-mu-var-def/var-register")  # Var-register
 9090     # v->block-depth
 9091     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-var-def/output-block-depth")  # Var-block-depth
 9092     # v->type == int
 9093     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 9094     (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0")  # Type-tree-is-atom
 9095     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-var-def/var-type:1")  # Type-tree-value
 9096     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-var-def/var-type:2")  # Type-tree-right
 9097     # . epilogue
 9098     89/<- %esp 5/r32/ebp
 9099     5d/pop-to-ebp
 9100     c3/return
 9101 
 9102 test-parse-mu-reg-var-def:
 9103     # 'var n/eax: int <- copy 0'
 9104     # . prologue
 9105     55/push-ebp
 9106     89/<- %ebp 4/r32/esp
 9107     # setup
 9108     (clear-stream _test-input-stream)
 9109     (write _test-input-stream "n/eax: int <- copy 0\n")  # caller has consumed the 'var'
 9110     c7 0/subop/copy *Curr-block-depth 1/imm32
 9111     # var out/esi: (handle stmt)
 9112     68/push 0/imm32
 9113     68/push 0/imm32
 9114     89/<- %esi 4/r32/esp
 9115     # var vars/ecx: (stack (addr var) 16)
 9116     81 5/subop/subtract %esp 0xc0/imm32
 9117     68/push 0xc0/imm32/size
 9118     68/push 0/imm32/top
 9119     89/<- %ecx 4/r32/esp
 9120     (clear-stack %ecx)
 9121     # convert
 9122     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
 9123     # var out-addr/esi: (addr stmt)
 9124     (lookup *esi *(esi+4))  # => eax
 9125     89/<- %esi 0/r32/eax
 9126     #
 9127     (check-ints-equal *esi 3 "F - test-parse-mu-reg-var-def/tag")  # Stmt-tag is reg-var-def
 9128     # var v/ecx: (addr var) = lookup(out->outputs->value)
 9129     # . eax: (addr stmt-var) = lookup(out->outputs)
 9130     (lookup *(esi+0x14) *(esi+0x18))  # Regvardef-outputs Regvardef-outputs => eax
 9131     # .
 9132     (check-ints-equal *(eax+8) 0 "F - test-parse-mu-reg-var-def/single-output")  # Stmt-var-next
 9133     # . eax: (addr var) = lookup(eax->value)
 9134     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9135     # . ecx = eax
 9136     89/<- %ecx 0/r32/eax
 9137     # v->name
 9138     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 9139     (check-strings-equal %eax "n" "F - test-parse-mu-reg-var-def/output-name")  # Var-name
 9140     # v->register
 9141     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 9142     (check-strings-equal %eax "eax" "F - test-parse-mu-reg-var-def/output-register")
 9143     # v->block-depth
 9144     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-reg-var-def/output-block-depth")  # Var-block-depth
 9145     # v->type == int
 9146     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 9147     (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0")  # Type-tree-is-atom
 9148     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-reg-var-def/output-type:1")  # Type-tree-value
 9149     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-type:2")  # Type-tree-right
 9150     # . epilogue
 9151     89/<- %esp 5/r32/ebp
 9152     5d/pop-to-ebp
 9153     c3/return
 9154 
 9155 parse-mu-stmt:  # line: (addr stream byte), vars: (addr stack live-var), fn: (addr function), out: (addr handle stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
 9156     # Carefully push any outputs on the vars stack _after_ reading the inputs
 9157     # that may conflict with them.
 9158     #
 9159     # The only situation in which outputs are pushed here (when it's not a
 9160     # 'var' vardef stmt), and so can possibly conflict with inputs, is if the
 9161     # output is a function output.
 9162     #
 9163     # pseudocode:
 9164     #   var name: slice
 9165     #   allocate(Heap, Stmt-size, out)
 9166     #   var out-addr: (addr stmt) = lookup(*out)
 9167     #   out-addr->tag = stmt
 9168     #   if stmt-has-outputs?(line)
 9169     #     while true
 9170     #       name = next-mu-token(line)
 9171     #       if (name == '<-') break
 9172     #       assert(is-identifier?(name))
 9173     #       var v: (handle var) = lookup-var-or-find-in-fn-outputs(name, vars, fn)
 9174     #       out-addr->outputs = append(v, out-addr->outputs)
 9175     #   add-operation-and-inputs-to-stmt(out-addr, line, vars)
 9176     #   for output in stmt->outputs:
 9177     #     maybe-define-var(output, vars)
 9178     #
 9179     # . prologue
 9180     55/push-ebp
 9181     89/<- %ebp 4/r32/esp
 9182     # . save registers
 9183     50/push-eax
 9184     51/push-ecx
 9185     52/push-edx
 9186     53/push-ebx
 9187     57/push-edi
 9188     # var name/ecx: slice
 9189     68/push 0/imm32/end
 9190     68/push 0/imm32/start
 9191     89/<- %ecx 4/r32/esp
 9192     # var is-deref?/edx: boolean = false
 9193     ba/copy-to-edx 0/imm32/false
 9194     # var v: (handle var)
 9195     68/push 0/imm32
 9196     68/push 0/imm32
 9197     89/<- %ebx 4/r32/esp
 9198     #
 9199     (allocate Heap *Stmt-size *(ebp+0x14))
 9200     # var out-addr/edi: (addr stmt) = lookup(*out)
 9201     8b/-> *(ebp+0x14) 7/r32/edi
 9202     (lookup *edi *(edi+4))  # => eax
 9203     89/<- %edi 0/r32/eax
 9204     # out-addr->tag = 1/stmt
 9205     c7 0/subop/copy *edi 1/imm32/stmt1  # Stmt-tag
 9206     {
 9207       (stmt-has-outputs? *(ebp+8))
 9208       3d/compare-eax-and 0/imm32/false
 9209       0f 84/jump-if-= break/disp32
 9210       {
 9211 $parse-mu-stmt:read-outputs:
 9212         # name = next-mu-token(line)
 9213         (next-mu-token *(ebp+8) %ecx)
 9214         # if slice-empty?(word-slice) break
 9215         (slice-empty? %ecx)  # => eax
 9216         3d/compare-eax-and 0/imm32/false
 9217         0f 85/jump-if-!= break/disp32
 9218         # if (name == "<-") break
 9219         (slice-equal? %ecx "<-")  # => eax
 9220         3d/compare-eax-and 0/imm32/false
 9221         0f 85/jump-if-!= break/disp32
 9222         # is-deref? = false
 9223         ba/copy-to-edx 0/imm32/false
 9224         # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 9225         8b/-> *ecx 0/r32/eax  # Slice-start
 9226         8a/copy-byte *eax 0/r32/AL
 9227         81 4/subop/and %eax 0xff/imm32
 9228         3d/compare-eax-and 0x2a/imm32/asterisk
 9229         {
 9230           75/jump-if-!= break/disp8
 9231           ff 0/subop/increment *ecx
 9232           ba/copy-to-edx 1/imm32/true
 9233         }
 9234         # assert(is-identifier?(name))
 9235         (is-identifier? %ecx)  # => eax
 9236         3d/compare-eax-and 0/imm32/false
 9237         0f 84/jump-if-= $parse-mu-stmt:abort/disp32
 9238         #
 9239         (lookup-var-or-find-in-fn-outputs %ecx *(ebp+0xc) *(ebp+0x10) %ebx *(ebp+0x18) *(ebp+0x1c))
 9240         8d/copy-address *(edi+0x14) 0/r32/eax  # Stmt1-outputs
 9241         (append-stmt-var Heap  *ebx *(ebx+4)  *(edi+0x14) *(edi+0x18)  %edx  %eax)  # Stmt1-outputs
 9242         #
 9243         e9/jump loop/disp32
 9244       }
 9245     }
 9246     (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 9247 $parse-mu-stmt:define-outputs:
 9248     # var output/edi: (addr stmt-var) = lookup(out-addr->outputs)
 9249     (lookup *(edi+0x14) *(edi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
 9250     89/<- %edi 0/r32/eax
 9251     {
 9252 $parse-mu-stmt:define-outputs-loop:
 9253       # if (output == null) break
 9254       81 7/subop/compare %edi 0/imm32
 9255       74/jump-if-= break/disp8
 9256       #
 9257       (maybe-define-var *edi *(edi+4)  *(ebp+0xc))  # if output is a deref, then it's already been defined,
 9258                                                     # and must be in vars. This call will be a no-op, but safe.
 9259       # output = output->next
 9260       (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
 9261       89/<- %edi 0/r32/eax
 9262       #
 9263       eb/jump loop/disp8
 9264     }
 9265 $parse-mu-stmt:end:
 9266     # . reclaim locals
 9267     81 0/subop/add %esp 0x10/imm32
 9268     # . restore registers
 9269     5f/pop-to-edi
 9270     5b/pop-to-ebx
 9271     5a/pop-to-edx
 9272     59/pop-to-ecx
 9273     58/pop-to-eax
 9274     # . epilogue
 9275     89/<- %esp 5/r32/ebp
 9276     5d/pop-to-ebp
 9277     c3/return
 9278 
 9279 $parse-mu-stmt:abort:
 9280     # error("invalid identifier '" name "'\n")
 9281     (write-buffered *(ebp+0x18) "invalid identifier '")
 9282     (write-slice-buffered *(ebp+0x18) %ecx)
 9283     (write-buffered *(ebp+0x18) "'\n")
 9284     (flush *(ebp+0x18))
 9285     (stop *(ebp+0x1c) 1)
 9286     # never gets here
 9287 
 9288 add-operation-and-inputs-to-stmt:  # stmt: (addr stmt), line: (addr stream byte), vars: (addr stack live-var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 9289     # pseudocode:
 9290     #   stmt->name = slice-to-string(next-mu-token(line))
 9291     #   while true
 9292     #     name = next-mu-token(line)
 9293     #     v = lookup-var-or-literal(name)
 9294     #     stmt->inouts = append(v, stmt->inouts)
 9295     #
 9296     # . prologue
 9297     55/push-ebp
 9298     89/<- %ebp 4/r32/esp
 9299     # . save registers
 9300     50/push-eax
 9301     51/push-ecx
 9302     52/push-edx
 9303     53/push-ebx
 9304     56/push-esi
 9305     57/push-edi
 9306     # edi = stmt
 9307     8b/-> *(ebp+8) 7/r32/edi
 9308     # var name/ecx: slice
 9309     68/push 0/imm32/end
 9310     68/push 0/imm32/start
 9311     89/<- %ecx 4/r32/esp
 9312     # var is-deref?/edx: boolean = false
 9313     ba/copy-to-edx 0/imm32/false
 9314     # var v/esi: (handle var)
 9315     68/push 0/imm32
 9316     68/push 0/imm32
 9317     89/<- %esi 4/r32/esp
 9318 $add-operation-and-inputs-to-stmt:read-operation:
 9319     (next-mu-token *(ebp+0xc) %ecx)
 9320     8d/copy-address *(edi+4) 0/r32/eax  # Stmt1-operation or Regvardef-operationStmt1-operation or Regvardef-operation
 9321     (slice-to-string Heap %ecx %eax)
 9322     # var is-get?/ebx: boolean = (name == "get")
 9323     (slice-equal? %ecx "get")  # => eax
 9324     89/<- %ebx 0/r32/eax
 9325     {
 9326 $add-operation-and-inputs-to-stmt:read-inouts:
 9327       # name = next-mu-token(line)
 9328       (next-mu-token *(ebp+0xc) %ecx)
 9329       # if slice-empty?(word-slice) break
 9330       (slice-empty? %ecx)  # => eax
 9331       3d/compare-eax-and 0/imm32/false
 9332       0f 85/jump-if-!= break/disp32
 9333       # if (name == "<-") abort
 9334       (slice-equal? %ecx "<-")
 9335       3d/compare-eax-and 0/imm32/false
 9336       0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32
 9337       # if (is-get? && second operand) lookup or create offset
 9338       {
 9339         81 7/subop/compare %ebx 0/imm32/false
 9340         74/jump-if-= break/disp8
 9341         (lookup *(edi+0xc) *(edi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9342         3d/compare-eax-and 0/imm32
 9343         74/jump-if-= break/disp8
 9344         (lookup-or-create-constant %eax %ecx %esi)
 9345 #?         (lookup *esi *(esi+4))
 9346 #?         (write-buffered Stderr "creating new output var ")
 9347 #?         (write-int32-hex-buffered Stderr %eax)
 9348 #?         (write-buffered Stderr " for field called ")
 9349 #?         (write-slice-buffered Stderr %ecx)
 9350 #?         (write-buffered Stderr "; var name ")
 9351 #?         (lookup *eax *(eax+4))  # Var-name
 9352 #?         (write-buffered Stderr %eax)
 9353 #?         (write-buffered Stderr Newline)
 9354 #?         (flush Stderr)
 9355         e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32
 9356       }
 9357       # is-deref? = false
 9358       ba/copy-to-edx 0/imm32/false
 9359       # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 9360       8b/-> *ecx 0/r32/eax  # Slice-start
 9361       8a/copy-byte *eax 0/r32/AL
 9362       81 4/subop/and %eax 0xff/imm32
 9363       3d/compare-eax-and 0x2a/imm32/asterisk
 9364       {
 9365         75/jump-if-!= break/disp8
 9366 $add-operation-and-inputs-to-stmt:inout-is-deref:
 9367         ff 0/subop/increment *ecx
 9368         ba/copy-to-edx 1/imm32/true
 9369       }
 9370       (lookup-var-or-literal %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9371 $add-operation-and-inputs-to-stmt:save-var:
 9372       8d/copy-address *(edi+0xc) 0/r32/eax
 9373       (append-stmt-var Heap  *esi *(esi+4)  *(edi+0xc) *(edi+0x10)  %edx  %eax)  # Stmt1-inouts or Regvardef-inouts
 9374       #
 9375       e9/jump loop/disp32
 9376     }
 9377 $add-operation-and-inputs-to-stmt:end:
 9378     # . reclaim locals
 9379     81 0/subop/add %esp 0x10/imm32
 9380     # . restore registers
 9381     5f/pop-to-edi
 9382     5e/pop-to-esi
 9383     5b/pop-to-ebx
 9384     5a/pop-to-edx
 9385     59/pop-to-ecx
 9386     58/pop-to-eax
 9387     # . epilogue
 9388     89/<- %esp 5/r32/ebp
 9389     5d/pop-to-ebp
 9390     c3/return
 9391 
 9392 $add-operation-and-inputs-to-stmt:abort:
 9393     # error("fn ___: invalid identifier in '" line "'\n")
 9394     (write-buffered *(ebp+0x18) "fn ")
 9395     8b/-> *(ebp+0x14) 0/r32/eax
 9396     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9397     (write-buffered *(ebp+0x18) %eax)
 9398     (rewind-stream *(ebp+0xc))
 9399     (write-buffered *(ebp+0x18) ": invalid identifier in '")
 9400     (write-stream-data *(ebp+0x18) *(ebp+0xc))
 9401     (write-buffered *(ebp+0x18) "'\n")
 9402     (flush *(ebp+0x18))
 9403     (stop *(ebp+0x1c) 1)
 9404     # never gets here
 9405 
 9406 stmt-has-outputs?:  # line: (addr stream byte) -> result/eax: boolean
 9407     # . prologue
 9408     55/push-ebp
 9409     89/<- %ebp 4/r32/esp
 9410     # . save registers
 9411     51/push-ecx
 9412     # var word-slice/ecx: slice
 9413     68/push 0/imm32/end
 9414     68/push 0/imm32/start
 9415     89/<- %ecx 4/r32/esp
 9416     # result = false
 9417     b8/copy-to-eax 0/imm32/false
 9418     (rewind-stream *(ebp+8))
 9419     {
 9420       (next-mu-token *(ebp+8) %ecx)
 9421       # if slice-empty?(word-slice) break
 9422       (slice-empty? %ecx)
 9423       3d/compare-eax-and 0/imm32/false
 9424       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 9425       0f 85/jump-if-!= break/disp32
 9426       # if slice-starts-with?(word-slice, '#') break
 9427       # . eax = *word-slice->start
 9428       8b/-> *ecx 0/r32/eax
 9429       8a/copy-byte *eax 0/r32/AL
 9430       81 4/subop/and %eax 0xff/imm32
 9431       # . if (eax == '#') break
 9432       3d/compare-eax-and 0x23/imm32/hash
 9433       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 9434       0f 84/jump-if-= break/disp32
 9435       # if slice-equal?(word-slice, '<-') return true
 9436       (slice-equal? %ecx "<-")
 9437       3d/compare-eax-and 0/imm32/false
 9438       74/jump-if-= loop/disp8
 9439       b8/copy-to-eax 1/imm32/true
 9440     }
 9441 $stmt-has-outputs:end:
 9442     (rewind-stream *(ebp+8))
 9443     # . reclaim locals
 9444     81 0/subop/add %esp 8/imm32
 9445     # . restore registers
 9446     59/pop-to-ecx
 9447     # . epilogue
 9448     89/<- %esp 5/r32/ebp
 9449     5d/pop-to-ebp
 9450     c3/return
 9451 
 9452 # if 'name' starts with a digit, create a new literal var for it
 9453 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found
 9454 lookup-var-or-literal:  # name: (addr slice), vars: (addr stack live-var), out: (addr handle var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 9455     # . prologue
 9456     55/push-ebp
 9457     89/<- %ebp 4/r32/esp
 9458     # . save registers
 9459     50/push-eax
 9460     51/push-ecx
 9461     56/push-esi
 9462     # esi = name
 9463     8b/-> *(ebp+8) 6/r32/esi
 9464     # if slice-empty?(name) abort
 9465     (slice-empty? %esi)  # => eax
 9466     3d/compare-eax-and 0/imm32/false
 9467     0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32
 9468     # var c/ecx: byte = *name->start
 9469     8b/-> *esi 1/r32/ecx
 9470     8a/copy-byte *ecx 1/r32/CL
 9471     81 4/subop/and %ecx 0xff/imm32
 9472     # if is-decimal-digit?(c) return new var(name)
 9473     {
 9474       (is-decimal-digit? %ecx)  # => eax
 9475       3d/compare-eax-and 0/imm32/false
 9476       74/jump-if-= break/disp8
 9477 $lookup-var-or-literal:literal:
 9478       (new-literal-integer Heap %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9479       eb/jump $lookup-var-or-literal:end/disp8
 9480     }
 9481     # else if (c == '"') return new var(name)
 9482     {
 9483       81 7/subop/compare %ecx 0x22/imm32/dquote
 9484       75/jump-if-!= break/disp8
 9485 $lookup-var-or-literal:literal-string:
 9486       (new-literal Heap %esi *(ebp+0x10))
 9487       eb/jump $lookup-var-or-literal:end/disp8
 9488     }
 9489     # otherwise return lookup-var(name, vars)
 9490     {
 9491 $lookup-var-or-literal:var:
 9492       (lookup-var %esi *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9493     }
 9494 $lookup-var-or-literal:end:
 9495     # . restore registers
 9496     5e/pop-to-esi
 9497     59/pop-to-ecx
 9498     58/pop-to-eax
 9499     # . epilogue
 9500     89/<- %esp 5/r32/ebp
 9501     5d/pop-to-ebp
 9502     c3/return
 9503 
 9504 $lookup-var-or-literal:abort:
 9505     (write-buffered *(ebp+0x18) "fn ")
 9506     8b/-> *(ebp+0x14) 0/r32/eax
 9507     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9508     (write-buffered *(ebp+0x18) %eax)
 9509     (write-buffered *(ebp+0x18) ": empty variable!")
 9510     (flush *(ebp+0x18))
 9511     (stop *(ebp+0x1c) 1)
 9512     # never gets here
 9513 
 9514 # return first 'name' from the top (back) of 'vars' and abort if not found
 9515 lookup-var:  # name: (addr slice), vars: (addr stack live-var), out: (addr handle var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 9516     # . prologue
 9517     55/push-ebp
 9518     89/<- %ebp 4/r32/esp
 9519     # . save registers
 9520     50/push-eax
 9521     #
 9522     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9523     # if (*out == 0) abort
 9524     8b/-> *(ebp+0x10) 0/r32/eax
 9525     81 7/subop/compare *eax 0/imm32
 9526     74/jump-if-= $lookup-var:abort/disp8
 9527 $lookup-var:end:
 9528     # . restore registers
 9529     58/pop-to-eax
 9530     # . epilogue
 9531     89/<- %esp 5/r32/ebp
 9532     5d/pop-to-ebp
 9533     c3/return
 9534 
 9535 $lookup-var:abort:
 9536     (write-buffered *(ebp+0x18) "fn ")
 9537     8b/-> *(ebp+0x14) 0/r32/eax
 9538     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9539     (write-buffered *(ebp+0x18) %eax)
 9540     (write-buffered *(ebp+0x18) ": unknown variable '")
 9541     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 9542     (write-buffered *(ebp+0x18) "'\n")
 9543     (flush *(ebp+0x18))
 9544     (stop *(ebp+0x1c) 1)
 9545     # never gets here
 9546 
 9547 # return first 'name' from the top (back) of 'vars', and 0/null if not found
 9548 # ensure that 'name' if in a register is the topmost variable in that register
 9549 lookup-var-helper:  # name: (addr slice), vars: (addr stack live-var), out: (addr handle var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 9550     # pseudocode:
 9551     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 9552     #   var min = vars->data
 9553     #   while curr >= min
 9554     #     var v: (handle var) = *curr
 9555     #     if v->name == name
 9556     #       return
 9557     #     curr -= 12
 9558     #
 9559     # . prologue
 9560     55/push-ebp
 9561     89/<- %ebp 4/r32/esp
 9562     # . save registers
 9563     50/push-eax
 9564     51/push-ecx
 9565     52/push-edx
 9566     53/push-ebx
 9567     56/push-esi
 9568     57/push-edi
 9569     # clear out
 9570     (zero-out *(ebp+0x10) *Handle-size)
 9571     # esi = vars
 9572     8b/-> *(ebp+0xc) 6/r32/esi
 9573     # ebx = vars->top
 9574     8b/-> *esi 3/r32/ebx
 9575     # if (vars->top > vars->size) abort
 9576     3b/compare<- *(esi+4) 0/r32/eax
 9577     0f 8f/jump-if-> $lookup-var-helper:error1/disp32
 9578     # var min/edx: (addr handle var) = vars->data
 9579     8d/copy-address *(esi+8) 2/r32/edx
 9580     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
 9581     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
 9582     # var var-in-reg/edi: 8 addrs
 9583     68/push 0/imm32
 9584     68/push 0/imm32
 9585     68/push 0/imm32
 9586     68/push 0/imm32
 9587     68/push 0/imm32
 9588     68/push 0/imm32
 9589     68/push 0/imm32
 9590     68/push 0/imm32
 9591     89/<- %edi 4/r32/esp
 9592     {
 9593 $lookup-var-helper:loop:
 9594       # if (curr < min) return
 9595       39/compare %ebx 2/r32/edx
 9596       0f 82/jump-if-addr< break/disp32
 9597       # var v/ecx: (addr var) = lookup(*curr)
 9598       (lookup *ebx *(ebx+4))  # => eax
 9599       89/<- %ecx 0/r32/eax
 9600       # var vn/eax: (addr array byte) = lookup(v->name)
 9601       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 9602       # if (vn == name) return curr
 9603       (slice-equal? *(ebp+8) %eax)  # => eax
 9604       3d/compare-eax-and 0/imm32/false
 9605       {
 9606         74/jump-if-= break/disp8
 9607 $lookup-var-helper:found:
 9608         # var vr/eax: (addr array byte) = lookup(v->register)
 9609         (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 9610         3d/compare-eax-and 0/imm32
 9611         {
 9612           74/jump-if-= break/disp8
 9613 $lookup-var-helper:found-register:
 9614           # var reg/eax: int = get(Registers, vr)
 9615           (get Mu-registers %eax 0xc "Mu-registers")  # => eax
 9616           8b/-> *eax 0/r32/eax
 9617           # if (var-in-reg[reg]) error
 9618           8b/-> *(edi+eax<<2) 0/r32/eax
 9619           3d/compare-eax-and 0/imm32
 9620           0f 85/jump-if-!= $lookup-var-helper:error2/disp32
 9621         }
 9622 $lookup-var-helper:return:
 9623         # esi = out
 9624         8b/-> *(ebp+0x10) 6/r32/esi
 9625         # *out = *curr
 9626         8b/-> *ebx 0/r32/eax
 9627         89/<- *esi 0/r32/eax
 9628         8b/-> *(ebx+4) 0/r32/eax
 9629         89/<- *(esi+4) 0/r32/eax
 9630         # return
 9631         eb/jump $lookup-var-helper:end/disp8
 9632       }
 9633       # 'name' not yet found; update var-in-reg if v in register
 9634       # . var vr/eax: (addr array byte) = lookup(v->register)
 9635       (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 9636       # . if (var == 0) continue
 9637       3d/compare-eax-and 0/imm32
 9638       74/jump-if-= $lookup-var-helper:continue/disp8
 9639       # . var reg/eax: int = get(Registers, vr)
 9640       (get Mu-registers %eax 0xc "Mu-registers")  # => eax
 9641       8b/-> *eax 0/r32/eax
 9642       # . if (var-in-reg[reg] == 0) var-in-reg[reg] = v
 9643       81 7/subop/compare *(edi+eax<<2) 0/imm32
 9644       75/jump-if-!= $lookup-var-helper:continue/disp8
 9645       89/<- *(edi+eax<<2) 1/r32/ecx
 9646 $lookup-var-helper:continue:
 9647       # curr -= 12
 9648       81 5/subop/subtract %ebx 0xc/imm32
 9649       e9/jump loop/disp32
 9650     }
 9651 $lookup-var-helper:end:
 9652     # . reclaim locals
 9653     81 0/subop/add %esp 0x20/imm32
 9654     # . restore registers
 9655     5f/pop-to-edi
 9656     5e/pop-to-esi
 9657     5b/pop-to-ebx
 9658     5a/pop-to-edx
 9659     59/pop-to-ecx
 9660     58/pop-to-eax
 9661     # . epilogue
 9662     89/<- %esp 5/r32/ebp
 9663     5d/pop-to-ebp
 9664     c3/return
 9665 
 9666 $lookup-var-helper:error1:
 9667     (write-buffered *(ebp+0x18) "fn ")
 9668     8b/-> *(ebp+0x14) 0/r32/eax
 9669     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9670     (write-buffered *(ebp+0x18) %eax)
 9671     (write-buffered *(ebp+0x18) ": malformed stack when looking up '")
 9672     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 9673     (write-buffered *(ebp+0x18) "'\n")
 9674     (flush *(ebp+0x18))
 9675     (stop *(ebp+0x1c) 1)
 9676     # never gets here
 9677 
 9678 $lookup-var-helper:error2:
 9679     # eax contains the conflicting var at this point
 9680     (write-buffered *(ebp+0x18) "fn ")
 9681     50/push-eax
 9682     8b/-> *(ebp+0x14) 0/r32/eax
 9683     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9684     (write-buffered *(ebp+0x18) %eax)
 9685     58/pop-eax
 9686     (write-buffered *(ebp+0x18) ": register ")
 9687     50/push-eax
 9688     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 9689     (write-buffered *(ebp+0x18) %eax)
 9690     58/pop-to-eax
 9691     (write-buffered *(ebp+0x18) " reads var '")
 9692     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 9693     (write-buffered *(ebp+0x18) "' after writing var '")
 9694     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9695     (write-buffered *(ebp+0x18) %eax)
 9696     (write-buffered *(ebp+0x18) "'\n")
 9697     (flush *(ebp+0x18))
 9698     (stop *(ebp+0x1c) 1)
 9699     # never gets here
 9700 
 9701 dump-vars:  # vars: (addr stack live-var)
 9702     # pseudocode:
 9703     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 9704     #   var min = vars->data
 9705     #   while curr >= min
 9706     #     var v: (handle var) = *curr
 9707     #     print v
 9708     #     curr -= 12
 9709     #
 9710     # . prologue
 9711     55/push-ebp
 9712     89/<- %ebp 4/r32/esp
 9713     # . save registers
 9714     52/push-edx
 9715     53/push-ebx
 9716     56/push-esi
 9717     # esi = vars
 9718     8b/-> *(ebp+8) 6/r32/esi
 9719     # ebx = vars->top
 9720     8b/-> *esi 3/r32/ebx
 9721     # var min/edx: (addr handle var) = vars->data
 9722     8d/copy-address *(esi+8) 2/r32/edx
 9723     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
 9724     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
 9725     {
 9726 $dump-vars:loop:
 9727       # if (curr < min) return
 9728       39/compare %ebx 2/r32/edx
 9729       0f 82/jump-if-addr< break/disp32
 9730       #
 9731       (write-buffered Stderr "  var@")
 9732       (dump-var 2 %ebx)
 9733       # curr -= 12
 9734       81 5/subop/subtract %ebx 0xc/imm32
 9735       e9/jump loop/disp32
 9736     }
 9737 $dump-vars:end:
 9738     # . restore registers
 9739     5e/pop-to-esi
 9740     5b/pop-to-ebx
 9741     5a/pop-to-edx
 9742     # . epilogue
 9743     89/<- %esp 5/r32/ebp
 9744     5d/pop-to-ebp
 9745     c3/return
 9746 
 9747 == data
 9748 # Like Registers, but no esp or ebp
 9749 Mu-registers:  # (addr stream {(handle array byte), int})
 9750   # a table is a stream
 9751   0x48/imm32/write
 9752   0/imm32/read
 9753   0x48/imm32/length
 9754   # data
 9755   # it is perfectly ok to use fake alloc-ids -- as long as you never try to reclaim them
 9756   0x11/imm32/alloc-id $Mu-register-eax/imm32 0/imm32
 9757   0x11/imm32/alloc-id $Mu-register-ecx/imm32 1/imm32
 9758   0x11/imm32/alloc-id $Mu-register-edx/imm32 2/imm32
 9759   0x11/imm32/alloc-id $Mu-register-ebx/imm32 3/imm32
 9760   0x11/imm32/alloc-id $Mu-register-esi/imm32 6/imm32
 9761   0x11/imm32/alloc-id $Mu-register-edi/imm32 7/imm32
 9762 
 9763 $Mu-register-eax:
 9764   0x11/imm32/alloc-id
 9765   3/imm32/size
 9766   0x65/e 0x61/a 0x78/x
 9767 
 9768 $Mu-register-ecx:
 9769   0x11/imm32/alloc-id
 9770   3/imm32/size
 9771   0x65/e 0x63/c 0x78/x
 9772 
 9773 $Mu-register-edx:
 9774   0x11/imm32/alloc-id
 9775   3/imm32/size
 9776   0x65/e 0x64/d 0x78/x
 9777 
 9778 $Mu-register-ebx:
 9779   0x11/imm32/alloc-id
 9780   3/imm32/size
 9781   0x65/e 0x62/b 0x78/x
 9782 
 9783 $Mu-register-esi:
 9784   0x11/imm32/alloc-id
 9785   3/imm32/size
 9786   0x65/e 0x73/s 0x69/i
 9787 
 9788 $Mu-register-edi:
 9789   0x11/imm32/alloc-id
 9790   3/imm32/size
 9791   0x65/e 0x64/d 0x69/i
 9792 
 9793 == code
 9794 
 9795 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found
 9796 lookup-var-or-find-in-fn-outputs:  # name: (addr slice), vars: (addr stack live-var), fn: (addr function), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 9797     # . prologue
 9798     55/push-ebp
 9799     89/<- %ebp 4/r32/esp
 9800     # . save registers
 9801     50/push-eax
 9802     #
 9803     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))  # arg order slightly different; 'fn' is deemphasized
 9804     {
 9805       # if (out != 0) return
 9806       8b/-> *(ebp+0x14) 0/r32/eax
 9807       81 7/subop/compare *eax 0/imm32
 9808       75/jump-if-!= break/disp8
 9809       # if name is one of fn's outputs, return it
 9810       (find-in-function-outputs *(ebp+0x10) *(ebp+8) *(ebp+0x14))
 9811       8b/-> *(ebp+0x14) 0/r32/eax
 9812       81 7/subop/compare *eax 0/imm32
 9813       # otherwise abort
 9814       0f 84/jump-if-= $lookup-or-define-var:abort/disp32
 9815     }
 9816 $lookup-or-define-var:end:
 9817     # . restore registers
 9818     58/pop-to-eax
 9819     # . epilogue
 9820     89/<- %esp 5/r32/ebp
 9821     5d/pop-to-ebp
 9822     c3/return
 9823 
 9824 $lookup-or-define-var:abort:
 9825     (write-buffered *(ebp+0x18) "unknown variable '")
 9826     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 9827     (write-buffered *(ebp+0x18) "'\n")
 9828     (flush *(ebp+0x18))
 9829     (stop *(ebp+0x1c) 1)
 9830     # never gets here
 9831 
 9832 find-in-function-outputs:  # fn: (addr function), name: (addr slice), out: (addr handle var)
 9833     # . prologue
 9834     55/push-ebp
 9835     89/<- %ebp 4/r32/esp
 9836     # . save registers
 9837     50/push-eax
 9838     51/push-ecx
 9839     # var curr/ecx: (addr list var) = lookup(fn->outputs)
 9840     8b/-> *(ebp+8) 1/r32/ecx
 9841     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 9842     89/<- %ecx 0/r32/eax
 9843     # while curr != null
 9844     {
 9845       81 7/subop/compare %ecx 0/imm32
 9846       74/jump-if-= break/disp8
 9847       # var v/eax: (addr var) = lookup(curr->value)
 9848       (lookup *ecx *(ecx+4))  # List-value List-value => eax
 9849       # var s/eax: (addr array byte) = lookup(v->name)
 9850       (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9851       # if (s == name) return curr->value
 9852       (slice-equal? *(ebp+0xc) %eax)  # => eax
 9853       3d/compare-eax-and 0/imm32/false
 9854       {
 9855         74/jump-if-= break/disp8
 9856         # var edi = out
 9857         57/push-edi
 9858         8b/-> *(ebp+0x10) 7/r32/edi
 9859         # *out = curr->value
 9860         8b/-> *ecx 0/r32/eax
 9861         89/<- *edi 0/r32/eax
 9862         8b/-> *(ecx+4) 0/r32/eax
 9863         89/<- *(edi+4) 0/r32/eax
 9864         #
 9865         5f/pop-to-edi
 9866         eb/jump $find-in-function-outputs:end/disp8
 9867       }
 9868       # curr = curr->next
 9869       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
 9870       89/<- %ecx 0/r32/eax
 9871       #
 9872       eb/jump loop/disp8
 9873     }
 9874     b8/copy-to-eax 0/imm32
 9875 $find-in-function-outputs:end:
 9876     # . restore registers
 9877     59/pop-to-ecx
 9878     58/pop-to-eax
 9879     # . epilogue
 9880     89/<- %esp 5/r32/ebp
 9881     5d/pop-to-ebp
 9882     c3/return
 9883 
 9884 # push 'out' to 'vars' if not already there; it's assumed to be a fn output
 9885 maybe-define-var:  # out: (handle var), vars: (addr stack live-var)
 9886     # . prologue
 9887     55/push-ebp
 9888     89/<- %ebp 4/r32/esp
 9889     # . save registers
 9890     50/push-eax
 9891     # var out-addr/eax: (addr var)
 9892     (lookup *(ebp+8) *(ebp+0xc))  # => eax
 9893     #
 9894     (binding-exists? %eax *(ebp+0x10))  # => eax
 9895     3d/compare-eax-and 0/imm32/false
 9896     75/jump-if-!= $maybe-define-var:end/disp8
 9897     # otherwise update vars
 9898     (push *(ebp+0x10) *(ebp+8))
 9899     (push *(ebp+0x10) *(ebp+0xc))
 9900     (push *(ebp+0x10) 0)  # 'out' is always a fn output; never spill it
 9901 $maybe-define-var:end:
 9902     # . restore registers
 9903     58/pop-to-eax
 9904     # . epilogue
 9905     89/<- %esp 5/r32/ebp
 9906     5d/pop-to-ebp
 9907     c3/return
 9908 
 9909 # simpler version of lookup-var-helper
 9910 binding-exists?:  # target: (addr var), vars: (addr stack live-var) -> result/eax: boolean
 9911     # pseudocode:
 9912     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 9913     #   var min = vars->data
 9914     #   while curr >= min
 9915     #     var v: (handle var) = *curr
 9916     #     if v->name == target->name
 9917     #       return true
 9918     #     curr -= 12
 9919     #   return false
 9920     #
 9921     # . prologue
 9922     55/push-ebp
 9923     89/<- %ebp 4/r32/esp
 9924     # . save registers
 9925     51/push-ecx
 9926     52/push-edx
 9927     56/push-esi
 9928     # var target-name/ecx: (addr array byte) = lookup(target->name)
 9929     8b/-> *(ebp+8) 0/r32/eax
 9930     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9931     89/<- %ecx 0/r32/eax
 9932     # esi = vars
 9933     8b/-> *(ebp+0xc) 6/r32/esi
 9934     # eax = vars->top
 9935     8b/-> *esi 0/r32/eax
 9936     # var min/edx: (addr handle var) = vars->data
 9937     8d/copy-address *(esi+8) 2/r32/edx
 9938     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
 9939     8d/copy-address *(esi+eax-4) 6/r32/esi  # vars + 8 + vars->type - 12
 9940     {
 9941 $binding-exists?:loop:
 9942       # if (curr < min) return
 9943       39/compare %esi 2/r32/edx
 9944       0f 82/jump-if-addr< break/disp32
 9945       # var v/eax: (addr var) = lookup(*curr)
 9946       (lookup *esi *(esi+4))  # => eax
 9947       # var vn/eax: (addr array byte) = lookup(v->name)
 9948       (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9949       # if (vn == target-name) return true
 9950       (string-equal? %ecx %eax)  # => eax
 9951       3d/compare-eax-and 0/imm32/false
 9952       75/jump-if-!= $binding-exists?:end/disp8  # eax already contains true
 9953       # curr -= 12
 9954       81 5/subop/subtract %esi 0xc/imm32
 9955       e9/jump loop/disp32
 9956     }
 9957     b8/copy-to-eax 0/imm32/false
 9958 $binding-exists?:end:
 9959     # . restore registers
 9960     5e/pop-to-esi
 9961     5a/pop-to-edx
 9962     59/pop-to-ecx
 9963     # . epilogue
 9964     89/<- %esp 5/r32/ebp
 9965     5d/pop-to-ebp
 9966     c3/return
 9967 
 9968 test-parse-mu-stmt:
 9969     # . prologue
 9970     55/push-ebp
 9971     89/<- %ebp 4/r32/esp
 9972     # setup
 9973     (clear-stream _test-input-stream)
 9974     (write _test-input-stream "increment n\n")
 9975     # var vars/ecx: (stack (addr var) 16)
 9976     81 5/subop/subtract %esp 0xc0/imm32
 9977     68/push 0xc0/imm32/size
 9978     68/push 0/imm32/top
 9979     89/<- %ecx 4/r32/esp
 9980     (clear-stack %ecx)
 9981     # var v/edx: (handle var)
 9982     68/push 0/imm32
 9983     68/push 0/imm32
 9984     89/<- %edx 4/r32/esp
 9985     # var s/eax: (handle array byte)
 9986     68/push 0/imm32
 9987     68/push 0/imm32
 9988     89/<- %eax 4/r32/esp
 9989     # v = new var("n")
 9990     (copy-array Heap "n" %eax)
 9991     (new-var Heap *eax *(eax+4) %edx)
 9992     #
 9993     (push %ecx *edx)
 9994     (push %ecx *(edx+4))
 9995     (push %ecx 0)
 9996     # var out/eax: (handle stmt)
 9997     68/push 0/imm32
 9998     68/push 0/imm32
 9999     89/<- %eax 4/r32/esp
10000     # convert
10001     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
10002     # var out-addr/edx: (addr stmt) = lookup(*out)
10003     (lookup *eax *(eax+4))  # => eax
10004     89/<- %edx 0/r32/eax
10005     # out->tag
10006     (check-ints-equal *edx 1 "F - test-parse-mu-stmt/tag")  # Stmt-tag is Stmt1
10007     # out->operation
10008     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
10009     (check-strings-equal %eax "increment" "F - test-parse-mu-stmt/name")  # Stmt1-operation
10010     # out->inouts->value->name
10011     # . eax = out->inouts
10012     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10013     # . eax = out->inouts->value
10014     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10015     # . eax = out->inouts->value->name
10016     (lookup *eax *(eax+4))  # Var-name Var-name => eax
10017     # .
10018     (check-strings-equal %eax "n" "F - test-parse-mu-stmt/inout:0")
10019     # . epilogue
10020     89/<- %esp 5/r32/ebp
10021     5d/pop-to-ebp
10022     c3/return
10023 
10024 test-parse-mu-stmt-with-comma:
10025     # . prologue
10026     55/push-ebp
10027     89/<- %ebp 4/r32/esp
10028     # setup
10029     (clear-stream _test-input-stream)
10030     (write _test-input-stream "copy-to n, 3\n")
10031     # var vars/ecx: (stack (addr var) 16)
10032     81 5/subop/subtract %esp 0xc0/imm32
10033     68/push 0xc0/imm32/size
10034     68/push 0/imm32/top
10035     89/<- %ecx 4/r32/esp
10036     (clear-stack %ecx)
10037     # var v/edx: (handle var)
10038     68/push 0/imm32
10039     68/push 0/imm32
10040     89/<- %edx 4/r32/esp
10041     # var s/eax: (handle array byte)
10042     68/push 0/imm32
10043     68/push 0/imm32
10044     89/<- %eax 4/r32/esp
10045     # v = new var("n")
10046     (copy-array Heap "n" %eax)
10047     (new-var Heap *eax *(eax+4) %edx)
10048     #
10049     (push %ecx *edx)
10050     (push %ecx *(edx+4))
10051     (push %ecx 0)
10052     # var out/eax: (handle stmt)
10053     68/push 0/imm32
10054     68/push 0/imm32
10055     89/<- %eax 4/r32/esp
10056     # convert
10057     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
10058     # var out-addr/edx: (addr stmt) = lookup(*out)
10059     (lookup *eax *(eax+4))  # => eax
10060     89/<- %edx 0/r32/eax
10061     # out->tag
10062     (check-ints-equal *edx 1 "F - test-parse-mu-stmt-with-comma/tag")  # Stmt-tag is Stmt1
10063     # out->operation
10064     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
10065     (check-strings-equal %eax "copy-to" "F - test-parse-mu-stmt-with-comma/name")  # Stmt1-operation
10066     # out->inouts->value->name
10067     # . eax = out->inouts
10068     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10069     # . eax = out->inouts->value
10070     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10071     # . eax = out->inouts->value->name
10072     (lookup *eax *(eax+4))  # Var-name Var-name => eax
10073     # .
10074     (check-strings-equal %eax "n" "F - test-parse-mu-stmt-with-comma/inout:0")
10075     # . epilogue
10076     89/<- %esp 5/r32/ebp
10077     5d/pop-to-ebp
10078     c3/return
10079 
10080 new-var:  # ad: (addr allocation-descriptor), name: (handle array byte), out: (addr handle var)
10081     # . prologue
10082     55/push-ebp
10083     89/<- %ebp 4/r32/esp
10084     # . save registers
10085     50/push-eax
10086     51/push-ecx
10087     # ecx = out
10088     8b/-> *(ebp+0x14) 1/r32/ecx
10089     #
10090     (allocate *(ebp+8) *Var-size %ecx)
10091     # var out-addr/eax: (addr var)
10092     (lookup *ecx *(ecx+4))  # => eax
10093     # out-addr->name = name
10094     8b/-> *(ebp+0xc) 1/r32/ecx
10095     89/<- *eax 1/r32/ecx  # Var-name
10096     8b/-> *(ebp+0x10) 1/r32/ecx
10097     89/<- *(eax+4) 1/r32/ecx  # Var-name
10098 #?     (write-buffered Stderr "var ")
10099 #?     (lookup *(ebp+0xc) *(ebp+0x10))
10100 #?     (write-buffered Stderr %eax)
10101 #?     (write-buffered Stderr " at ")
10102 #?     8b/-> *(ebp+0x14) 1/r32/ecx
10103 #?     (lookup *ecx *(ecx+4))  # => eax
10104 #?     (write-int32-hex-buffered Stderr %eax)
10105 #?     (write-buffered Stderr Newline)
10106 #?     (flush Stderr)
10107 $new-var:end:
10108     # . restore registers
10109     59/pop-to-ecx
10110     58/pop-to-eax
10111     # . epilogue
10112     89/<- %esp 5/r32/ebp
10113     5d/pop-to-ebp
10114     c3/return
10115 
10116 new-literal-integer:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
10117     # . prologue
10118     55/push-ebp
10119     89/<- %ebp 4/r32/esp
10120     # . save registers
10121     50/push-eax
10122     51/push-ecx
10123     # if (!is-hex-int?(name)) abort
10124     (is-hex-int? *(ebp+0xc))  # => eax
10125     3d/compare-eax-and 0/imm32/false
10126     0f 84/jump-if-= $new-literal-integer:abort/disp32
10127     # a little more error-checking
10128     (check-mu-hex-int *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
10129     # out = new var(s)
10130     (new-var-from-slice *(ebp+8) *(ebp+0xc) *(ebp+0x10))
10131     # var out-addr/ecx: (addr var) = lookup(*out)
10132     8b/-> *(ebp+0x10) 0/r32/eax
10133     (lookup *eax *(eax+4))  # => eax
10134     89/<- %ecx 0/r32/eax
10135     # out-addr->block-depth = *Curr-block-depth
10136     8b/-> *Curr-block-depth 0/r32/eax
10137     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
10138     # out-addr->type = new tree()
10139     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
10140     (allocate *(ebp+8) *Type-tree-size %eax)
10141     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
10142     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
10143     # nothing else to do; default type is 'literal'
10144 $new-literal-integer:end:
10145     # . reclaim locals
10146     81 0/subop/add %esp 8/imm32
10147     # . restore registers
10148     59/pop-to-ecx
10149     58/pop-to-eax
10150     # . epilogue
10151     89/<- %esp 5/r32/ebp
10152     5d/pop-to-ebp
10153     c3/return
10154 
10155 $new-literal-integer:abort:
10156     (write-buffered *(ebp+0x18) "fn ")
10157     8b/-> *(ebp+0x14) 0/r32/eax
10158     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10159     (write-buffered *(ebp+0x18) %eax)
10160     (write-buffered *(ebp+0x18) ": variable '")
10161     (write-slice-buffered *(ebp+0x18) *(ebp+0xc))
10162     (write-buffered *(ebp+0x18) "' cannot begin with a digit (or do you have a typo in a number?)\n")
10163     (flush *(ebp+0x18))
10164     (stop *(ebp+0x1c) 1)
10165     # never gets here
10166 
10167 # precondition: name is a valid hex integer; require a '0x' prefix
10168 check-mu-hex-int:  # name: (addr slice), err: (addr buffered-file), ed: (addr exit-descriptor)
10169     # . prologue
10170     55/push-ebp
10171     89/<- %ebp 4/r32/esp
10172     # . save registers
10173     50/push-eax
10174     51/push-ecx
10175     52/push-edx
10176     #
10177     8b/-> *(ebp+8) 1/r32/ecx
10178     # var start/ecx: (addr byte) = name->start
10179     8b/-> *(ecx+4) 2/r32/edx
10180     # var end/ecx: (addr byte) = name->end
10181     8b/-> *ecx 1/r32/ecx
10182     # var len/eax: int = name->end - name->start
10183     89/<- %eax 2/r32/edx
10184     29/subtract-from %eax 1/r32/ecx
10185     # if (len <= 1) return
10186     3d/compare-eax-with 1/imm32
10187     0f 8e/jump-if-<= $check-mu-hex-int:end/disp32
10188 $check-mu-hex-int:length->-1:
10189     # if slice-starts-with?("0x") return
10190     (slice-starts-with? *(ebp+8) "0x")  # => eax
10191     3d/compare-eax-with 0/imm32/false
10192     75/jump-if-!= $check-mu-hex-int:end/disp8
10193 $check-mu-hex-int:abort:
10194     # otherwise abort
10195     (write-buffered *(ebp+0xc) "literal integers are always hex in Mu; either start '")
10196     (write-slice-buffered *(ebp+0xc) *(ebp+8))
10197     (write-buffered *(ebp+0xc) "' with a '0x' to be unambiguous, or convert it to decimal.\n")
10198     (flush *(ebp+0xc))
10199     (stop *(ebp+0x10) 1)
10200 $check-mu-hex-int:end:
10201     # . restore registers
10202     5a/pop-to-edx
10203     59/pop-to-ecx
10204     58/pop-to-eax
10205     # . epilogue
10206     89/<- %esp 5/r32/ebp
10207     5d/pop-to-ebp
10208     c3/return
10209 
10210 new-literal:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
10211     # . prologue
10212     55/push-ebp
10213     89/<- %ebp 4/r32/esp
10214     # . save registers
10215     50/push-eax
10216     51/push-ecx
10217     # var s/ecx: (handle array byte)
10218     68/push 0/imm32
10219     68/push 0/imm32
10220     89/<- %ecx 4/r32/esp
10221     # s = slice-to-string(name)
10222     (slice-to-string Heap *(ebp+0xc) %ecx)
10223     # allocate to out
10224     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
10225     # var out-addr/ecx: (addr var) = lookup(*out)
10226     8b/-> *(ebp+0x10) 1/r32/ecx
10227     (lookup *ecx *(ecx+4))  # => eax
10228     89/<- %ecx 0/r32/eax
10229     # out-addr->block-depth = *Curr-block-depth
10230     8b/-> *Curr-block-depth 0/r32/eax
10231     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
10232     # out-addr->type/eax = new type
10233     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
10234     (allocate *(ebp+8) *Type-tree-size %eax)
10235     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
10236     # nothing else to do; default type is 'literal'
10237     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
10238 $new-literal:end:
10239     # . reclaim locals
10240     81 0/subop/add %esp 8/imm32
10241     # . restore registers
10242     59/pop-to-ecx
10243     58/pop-to-eax
10244     # . epilogue
10245     89/<- %esp 5/r32/ebp
10246     5d/pop-to-ebp
10247     c3/return
10248 
10249 new-var-from-slice:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
10250     # . prologue
10251     55/push-ebp
10252     89/<- %ebp 4/r32/esp
10253     # . save registers
10254     51/push-ecx
10255     # var tmp/ecx: (handle array byte)
10256     68/push 0/imm32
10257     68/push 0/imm32
10258     89/<- %ecx 4/r32/esp
10259     # tmp = slice-to-string(name)
10260     (slice-to-string Heap *(ebp+0xc) %ecx)
10261     # out = new-var(tmp)
10262     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
10263 $new-var-from-slice:end:
10264     # . reclaim locals
10265     81 0/subop/add %esp 8/imm32
10266     # . restore registers
10267     59/pop-to-ecx
10268     # . epilogue
10269     89/<- %esp 5/r32/ebp
10270     5d/pop-to-ebp
10271     c3/return
10272 
10273 new-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
10274     # . prologue
10275     55/push-ebp
10276     89/<- %ebp 4/r32/esp
10277     # . save registers
10278     50/push-eax
10279     51/push-ecx
10280     #
10281     (allocate *(ebp+8) *Stmt-size *(ebp+0x14))
10282     # var out-addr/eax: (addr stmt) = lookup(*out)
10283     8b/-> *(ebp+0x14) 0/r32/eax
10284     (lookup *eax *(eax+4))  # => eax
10285     # out-addr->tag = stmt
10286     c7 0/subop/copy *eax 2/imm32/tag/var-on-stack  # Stmt-tag
10287     # result->var = var
10288     8b/-> *(ebp+0xc) 1/r32/ecx
10289     89/<- *(eax+4) 1/r32/ecx  # Vardef-var
10290     8b/-> *(ebp+0x10) 1/r32/ecx
10291     89/<- *(eax+8) 1/r32/ecx  # Vardef-var
10292 $new-var-def:end:
10293     # . restore registers
10294     59/pop-to-ecx
10295     58/pop-to-eax
10296     # . epilogue
10297     89/<- %esp 5/r32/ebp
10298     5d/pop-to-ebp
10299     c3/return
10300 
10301 new-reg-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
10302     # . prologue
10303     55/push-ebp
10304     89/<- %ebp 4/r32/esp
10305     # . save registers
10306     50/push-eax
10307     # eax = out
10308     8b/-> *(ebp+0x14) 0/r32/eax
10309     #
10310     (allocate *(ebp+8) *Stmt-size %eax)
10311     # var out-addr/eax: (addr stmt) = lookup(*out)
10312     (lookup *eax *(eax+4))  # => eax
10313     # set tag
10314     c7 0/subop/copy *eax 3/imm32/tag/var-in-register  # Stmt-tag
10315     # set output
10316     8d/copy-address *(eax+0x14) 0/r32/eax  # Regvardef-outputs
10317     (append-stmt-var Heap  *(ebp+0xc) *(ebp+0x10)  0 0  0  %eax)
10318 $new-reg-var-def:end:
10319     # . restore registers
10320     58/pop-to-eax
10321     # . epilogue
10322     89/<- %esp 5/r32/ebp
10323     5d/pop-to-ebp
10324     c3/return
10325 
10326 append-list:  # ad: (addr allocation-descriptor), value: (handle _type), list: (handle list _type), out: (addr handle list _type)
10327     # . prologue
10328     55/push-ebp
10329     89/<- %ebp 4/r32/esp
10330     # . save registers
10331     50/push-eax
10332     51/push-ecx
10333     57/push-edi
10334     # edi = out
10335     8b/-> *(ebp+0x1c) 7/r32/edi
10336     # *out = new list
10337     (allocate *(ebp+8) *List-size %edi)
10338     # var out-addr/edi: (addr list _type) = lookup(*out)
10339     (lookup *edi *(edi+4))  # => eax
10340     89/<- %edi 0/r32/eax
10341     # out-addr->value = value
10342     8b/-> *(ebp+0xc) 0/r32/eax
10343     89/<- *edi 0/r32/eax  # List-value
10344     8b/-> *(ebp+0x10) 0/r32/eax
10345     89/<- *(edi+4) 0/r32/eax  # List-value
10346     # if (list == null) return
10347     81 7/subop/compare *(ebp+0x14) 0/imm32
10348     74/jump-if-= $append-list:end/disp8
10349     # otherwise append
10350 $append-list:non-empty-list:
10351     # var curr/eax: (addr list _type) = lookup(list)
10352     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
10353     # while (curr->next != null) curr = curr->next
10354     {
10355       81 7/subop/compare *(eax+8) 0/imm32  # List-next
10356       74/jump-if-= break/disp8
10357       # curr = lookup(curr->next)
10358       (lookup *(eax+8) *(eax+0xc))  # List-next, List-next => eax
10359       #
10360       eb/jump loop/disp8
10361     }
10362     # edi = out
10363     8b/-> *(ebp+0x1c) 7/r32/edi
10364     # curr->next = out
10365     8b/-> *edi 1/r32/ecx
10366     89/<- *(eax+8) 1/r32/ecx  # List-next
10367     8b/-> *(edi+4) 1/r32/ecx
10368     89/<- *(eax+0xc) 1/r32/ecx  # List-next
10369     # out = list
10370     8b/-> *(ebp+0x14) 1/r32/ecx
10371     89/<- *edi 1/r32/ecx
10372     8b/-> *(ebp+0x18) 1/r32/ecx
10373     89/<- *(edi+4) 1/r32/ecx
10374 $append-list:end:
10375     # . restore registers
10376     5f/pop-to-edi
10377     59/pop-to-ecx
10378     58/pop-to-eax
10379     # . epilogue
10380     89/<- %esp 5/r32/ebp
10381     5d/pop-to-ebp
10382     c3/return
10383 
10384 append-stmt-var:  # ad: (addr allocation-descriptor), v: (handle var), vars: (handle stmt-var), is-deref?: boolean, out: (addr handle stmt-var)
10385     # . prologue
10386     55/push-ebp
10387     89/<- %ebp 4/r32/esp
10388     # . save registers
10389     50/push-eax
10390     51/push-ecx
10391     57/push-edi
10392     # edi = out
10393     8b/-> *(ebp+0x20) 7/r32/edi
10394     # out = new stmt-var
10395     (allocate *(ebp+8) *Stmt-var-size %edi)
10396     # var out-addr/ecx: (addr stmt-var) = lookup(*out)
10397     (lookup *edi *(edi+4))  # => eax
10398     89/<- %ecx 0/r32/eax
10399     # out-addr->value = v
10400     8b/-> *(ebp+0xc) 0/r32/eax
10401     89/<- *ecx 0/r32/eax  # Stmt-var-value
10402     8b/-> *(ebp+0x10) 0/r32/eax
10403     89/<- *(ecx+4) 0/r32/eax  # Stmt-var-value
10404     # out-addr->is-deref? = is-deref?
10405     8b/-> *(ebp+0x1c) 0/r32/eax
10406     89/<- *(ecx+0x10) 0/r32/eax  # Stmt-var-is-deref
10407     # if (vars == null) return result
10408     81 7/subop/compare *(ebp+0x14) 0/imm32/null
10409     74/jump-if-= $append-stmt-var:end/disp8
10410     # otherwise append
10411     # var curr/eax: (addr stmt-var) = lookup(vars)
10412     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
10413     # while (curr->next != null) curr = curr->next
10414     {
10415       81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
10416       74/jump-if-= break/disp8
10417       # curr = lookup(curr->next)
10418       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next, Stmt-var-next => eax
10419       #
10420       eb/jump loop/disp8
10421     }
10422     # curr->next = out
10423     8b/-> *edi 1/r32/ecx
10424     89/<- *(eax+8) 1/r32/ecx  # Stmt-var-next
10425     8b/-> *(edi+4) 1/r32/ecx
10426     89/<- *(eax+0xc) 1/r32/ecx  # Stmt-var-next
10427     # out = vars
10428     8b/-> *(ebp+0x14) 1/r32/ecx
10429     89/<- *edi 1/r32/ecx
10430     8b/-> *(ebp+0x18) 1/r32/ecx
10431     89/<- *(edi+4) 1/r32/ecx
10432 $append-stmt-var:end:
10433     # . restore registers
10434     5f/pop-to-edi
10435     59/pop-to-ecx
10436     58/pop-to-eax
10437     # . epilogue
10438     89/<- %esp 5/r32/ebp
10439     5d/pop-to-ebp
10440     c3/return
10441 
10442 append-to-block:  # ad: (addr allocation-descriptor), block: (addr block), x: (handle stmt)
10443     # . prologue
10444     55/push-ebp
10445     89/<- %ebp 4/r32/esp
10446     # . save registers
10447     50/push-eax
10448     56/push-esi
10449     # esi = block
10450     8b/-> *(ebp+0xc) 6/r32/esi
10451     # block->stmts = append(x, block->stmts)
10452     8d/copy-address *(esi+4) 0/r32/eax  # Block-stmts
10453     (append-list *(ebp+8)  *(ebp+0x10) *(ebp+0x14)  *(esi+4) *(esi+8)  %eax)  # ad, x, x, Block-stmts, Block-stmts
10454 $append-to-block:end:
10455     # . restore registers
10456     5e/pop-to-esi
10457     58/pop-to-eax
10458     # . epilogue
10459     89/<- %esp 5/r32/ebp
10460     5d/pop-to-ebp
10461     c3/return
10462 
10463 ## Parsing types
10464 # We need to create metadata on user-defined types, and we need to use this
10465 # metadata as we parse instructions.
10466 # However, we also want to allow types to be used before their definitions.
10467 # This means we can't ever assume any type data structures exist.
10468 
10469 lookup-or-create-constant:  # container: (addr stmt-var), field-name: (addr slice), out: (addr handle var)
10470     # . prologue
10471     55/push-ebp
10472     89/<- %ebp 4/r32/esp
10473     # . save registers
10474     50/push-eax
10475     56/push-esi
10476     # var container-type/esi: type-id
10477     (container-type *(ebp+8))  # => eax
10478     89/<- %esi 0/r32/eax
10479     # var tmp/eax: (handle typeinfo) = find-or-create-typeinfo(container-type)
10480     68/push 0/imm32
10481     68/push 0/imm32
10482     89/<- %eax 4/r32/esp
10483     (find-or-create-typeinfo %esi %eax)
10484     # var tmp-addr/eax: (addr typeinfo) = lookup(tmp)
10485     (lookup *eax *(eax+4))  # => eax
10486     # result = find-or-create-typeinfo-output-var(typeinfo, field-name)
10487 #?     (write-buffered Stderr "constant: ")
10488 #?     (write-slice-buffered Stderr *(ebp+0xc))
10489 #?     (write-buffered Stderr Newline)
10490 #?     (flush Stderr)
10491     (find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10))
10492 #?     8b/-> *(ebp+0x10) 0/r32/eax
10493 #?     (write-buffered Stderr "@")
10494 #?     (lookup *eax *(eax+4))
10495 #?     (write-int32-hex-buffered Stderr %eax)
10496 #?     (lookup *eax *(eax+4))
10497 #?     (write-buffered Stderr %eax)
10498 #?     (write-buffered Stderr Newline)
10499 #?     (flush Stderr)
10500 #?     (write-buffered Stderr "offset: ")
10501 #?     8b/-> *(eax+0x14) 0/r32/eax
10502 #?     (write-int32-hex-buffered Stderr %eax)
10503 #?     (write-buffered Stderr Newline)
10504 #?     (flush Stderr)
10505 $lookup-or-create-constant:end:
10506     # . reclaim locals
10507     81 0/subop/add %esp 8/imm32
10508     # . restore registers
10509     5e/pop-to-esi
10510     58/pop-to-eax
10511     # . epilogue
10512     89/<- %esp 5/r32/ebp
10513     5d/pop-to-ebp
10514     c3/return
10515 
10516 # if addr var:
10517 #   container->var->type->right->left->value
10518 # otherwise
10519 #   container->var->type->value
10520 container-type:  # container: (addr stmt-var) -> result/eax: type-id
10521     # . prologue
10522     55/push-ebp
10523     89/<- %ebp 4/r32/esp
10524     #
10525     8b/-> *(ebp+8) 0/r32/eax
10526     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10527     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10528     {
10529       81 7/subop/compare *(eax+8) 0/imm32  # Type-tree-right
10530       74/jump-if-= break/disp8
10531       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
10532       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
10533     }
10534     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
10535 $container-type:end:
10536     # . epilogue
10537     89/<- %esp 5/r32/ebp
10538     5d/pop-to-ebp
10539     c3/return
10540 
10541 is-container?:  # t: type-id -> result/eax: boolean
10542     # . prologue
10543     55/push-ebp
10544     89/<- %ebp 4/r32/esp
10545     #
10546     8b/-> *(ebp+8) 0/r32/eax
10547     c1/shift 4/subop/left %eax 2/imm8
10548     3b/compare 0/r32/eax *Primitive-type-ids
10549     0f 9d/set-if->= %al
10550     81 4/subop/and %eax 0xff/imm32
10551 $is-container?:end:
10552     # . epilogue
10553     89/<- %esp 5/r32/ebp
10554     5d/pop-to-ebp
10555     c3/return
10556 
10557 find-or-create-typeinfo:  # t: type-id, out: (addr handle typeinfo)
10558     # . prologue
10559     55/push-ebp
10560     89/<- %ebp 4/r32/esp
10561     # . save registers
10562     50/push-eax
10563     51/push-ecx
10564     52/push-edx
10565     57/push-edi
10566     # edi = out
10567     8b/-> *(ebp+0xc) 7/r32/edi
10568     # var fields/ecx: (handle table (handle array byte) (handle typeinfo-entry))
10569     68/push 0/imm32
10570     68/push 0/imm32
10571     89/<- %ecx 4/r32/esp
10572     # find-typeinfo(t, out)
10573     (find-typeinfo *(ebp+8) %edi)
10574     {
10575       # if (*out != 0) break
10576       81 7/subop/compare *edi 0/imm32
10577       0f 85/jump-if-!= break/disp32
10578 $find-or-create-typeinfo:create:
10579       # *out = allocate
10580       (allocate Heap *Typeinfo-size %edi)
10581       # var tmp/eax: (addr typeinfo) = lookup(*out)
10582       (lookup *edi *(edi+4))  # => eax
10583 #?     (write-buffered Stderr "created typeinfo at ")
10584 #?     (write-int32-hex-buffered Stderr %eax)
10585 #?     (write-buffered Stderr " for type-id ")
10586 #?     (write-int32-hex-buffered Stderr *(ebp+8))
10587 #?     (write-buffered Stderr Newline)
10588 #?     (flush Stderr)
10589       # tmp->id = t
10590       8b/-> *(ebp+8) 2/r32/edx
10591       89/<- *eax 2/r32/edx  # Typeinfo-id
10592       # tmp->fields = new table
10593       # . fields = new table
10594       (new-stream Heap 0x40 *Typeinfo-fields-row-size %ecx)
10595       # . tmp->fields = fields
10596       8b/-> *ecx 2/r32/edx
10597       89/<- *(eax+4) 2/r32/edx  # Typeinfo-fields
10598       8b/-> *(ecx+4) 2/r32/edx
10599       89/<- *(eax+8) 2/r32/edx  # Typeinfo-fields
10600       # tmp->next = Program->types
10601       8b/-> *_Program-types 1/r32/ecx
10602       89/<- *(eax+0x10) 1/r32/ecx  # Typeinfo-next
10603       8b/-> *_Program-types->payload 1/r32/ecx
10604       89/<- *(eax+0x14) 1/r32/ecx  # Typeinfo-next
10605       # Program->types = out
10606       8b/-> *edi 1/r32/ecx
10607       89/<- *_Program-types 1/r32/ecx
10608       8b/-> *(edi+4) 1/r32/ecx
10609       89/<- *_Program-types->payload 1/r32/ecx
10610     }
10611 $find-or-create-typeinfo:end:
10612     # . reclaim locals
10613     81 0/subop/add %esp 8/imm32
10614     # . restore registers
10615     5f/pop-to-edi
10616     5a/pop-to-edx
10617     59/pop-to-ecx
10618     58/pop-to-eax
10619     # . epilogue
10620     89/<- %esp 5/r32/ebp
10621     5d/pop-to-ebp
10622     c3/return
10623 
10624 find-typeinfo:  # t: type-id, out: (addr handle typeinfo)
10625     # . prologue
10626     55/push-ebp
10627     89/<- %ebp 4/r32/esp
10628     # . save registers
10629     50/push-eax
10630     51/push-ecx
10631     52/push-edx
10632     57/push-edi
10633     # ecx = t
10634     8b/-> *(ebp+8) 1/r32/ecx
10635     # edi = out
10636     8b/-> *(ebp+0xc) 7/r32/edi
10637     # *out = Program->types
10638     8b/-> *_Program-types 0/r32/eax
10639     89/<- *edi 0/r32/eax
10640     8b/-> *_Program-types->payload 0/r32/eax
10641     89/<- *(edi+4) 0/r32/eax
10642     {
10643 $find-typeinfo:loop:
10644       # if (*out == 0) break
10645       81 7/subop/compare *edi 0/imm32
10646       74/jump-if-= break/disp8
10647 $find-typeinfo:check:
10648       # var tmp/eax: (addr typeinfo) = lookup(*out)
10649       (lookup *edi *(edi+4))  # => eax
10650       # if (tmp->id == t) break
10651       39/compare *eax 1/r32/ecx  # Typeinfo-id
10652       74/jump-if-= break/disp8
10653 $find-typeinfo:continue:
10654       # *out = tmp->next
10655       8b/-> *(eax+0x10) 2/r32/edx  # Typeinfo-next
10656       89/<- *edi 2/r32/edx
10657       8b/-> *(eax+0x14) 2/r32/edx  # Typeinfo-next
10658       89/<- *(edi+4) 2/r32/edx
10659       #
10660       eb/jump loop/disp8
10661     }
10662 $find-typeinfo:end:
10663     # . restore registers
10664     5f/pop-to-edi
10665     5a/pop-to-edx
10666     59/pop-to-ecx
10667     58/pop-to-eax
10668     # . epilogue
10669     89/<- %esp 5/r32/ebp
10670     5d/pop-to-ebp
10671     c3/return
10672 
10673 find-or-create-typeinfo-output-var:  # T: (addr typeinfo), f: (addr slice), out: (addr handle var)
10674     # . prologue
10675     55/push-ebp
10676     89/<- %ebp 4/r32/esp
10677     # . save registers
10678     50/push-eax
10679     52/push-edx
10680     57/push-edi
10681     # var dest/edi: (handle typeinfo-entry)
10682     68/push 0/imm32
10683     68/push 0/imm32
10684     89/<- %edi 4/r32/esp
10685     # find-or-create-typeinfo-fields(T, f, dest)
10686     (find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi)
10687     # var dest-addr/edi: (addr typeinfo-entry) = lookup(dest)
10688     (lookup *edi *(edi+4))  # => eax
10689     89/<- %edi 0/r32/eax
10690     # if dest-addr->output-var doesn't exist, create it
10691     {
10692       81 7/subop/compare *(edi+0xc) 0/imm32  # Typeinfo-entry-output-var
10693       0f 85/jump-if-!= break/disp32
10694       # dest-addr->output-var = new var(dummy name, type, -1 offset)
10695       # . var name/eax: (handle array byte) = "field"
10696       68/push 0/imm32
10697       68/push 0/imm32
10698       89/<- %eax 4/r32/esp
10699       (slice-to-string Heap *(ebp+0xc) %eax)
10700       # . new var
10701       8d/copy-address *(edi+0xc) 2/r32/edx
10702       (new-var Heap  *eax *(eax+4)  %edx)
10703       # . reclaim name
10704       81 0/subop/add %esp 8/imm32
10705       # var result/edx: (addr var) = lookup(dest-addr->output-var)
10706       (lookup *(edi+0xc) *(edi+0x10))  # => eax
10707       89/<- %edx 0/r32/eax
10708       # result->type = new constant type
10709       8d/copy-address *(edx+8) 0/r32/eax  # Var-type
10710       (allocate Heap *Type-tree-size %eax)
10711       (lookup *(edx+8) *(edx+0xc))  # => eax
10712       c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
10713       c7 0/subop/copy *(eax+4) 6/imm32/constant  # Type-tree-value
10714       c7 0/subop/copy *(eax+8) 0/imm32  # Type-tree-left
10715       c7 0/subop/copy *(eax+0xc) 0/imm32  # Type-tree-right
10716       c7 0/subop/copy *(eax+0x10) 0/imm32  # Type-tree-right
10717       # result->offset isn't filled out yet
10718       c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized  # Var-offset
10719     }
10720     # out = dest-addr->output-var
10721     8b/-> *(ebp+0x10) 2/r32/edx
10722     8b/-> *(edi+0xc) 0/r32/eax  # Typeinfo-entry-output-var
10723     89/<- *edx 0/r32/eax
10724     8b/-> *(edi+0x10) 0/r32/eax  # Typeinfo-entry-output-var
10725     89/<- *(edx+4) 0/r32/eax
10726 $find-or-create-typeinfo-output-var:end:
10727     # . reclaim locals
10728     81 0/subop/add %esp 8/imm32
10729     # . restore registers
10730     5f/pop-to-edi
10731     5a/pop-to-edx
10732     58/pop-to-eax
10733     # . epilogue
10734     89/<- %esp 5/r32/ebp
10735     5d/pop-to-ebp
10736     c3/return
10737 
10738 find-or-create-typeinfo-fields:  # T: (addr typeinfo), f: (addr slice), out: (addr handle typeinfo-entry)
10739     # . prologue
10740     55/push-ebp
10741     89/<- %ebp 4/r32/esp
10742     # . save registers
10743     50/push-eax
10744     56/push-esi
10745     57/push-edi
10746     # eax = lookup(T->fields)
10747     8b/-> *(ebp+8) 0/r32/eax
10748     (lookup *(eax+4) *(eax+8))  # Typeinfo-fields Typeinfo-fields => eax
10749     # edi = out
10750     8b/-> *(ebp+0x10) 7/r32/edi
10751     # var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f)
10752     (get-or-insert-slice %eax *(ebp+0xc) *Typeinfo-fields-row-size Heap)  # => eax
10753     89/<- %esi 0/r32/eax
10754     # if src doesn't exist, allocate it
10755     {
10756       81 7/subop/compare *esi 0/imm32
10757       75/jump-if-!= break/disp8
10758       (allocate Heap *Typeinfo-entry-size %esi)
10759 #?       (write-buffered Stderr "handle at ")
10760 #?       (write-int32-hex-buffered Stderr %esi)
10761 #?       (write-buffered Stderr ": ")
10762 #?       (write-int32-hex-buffered Stderr *esi)
10763 #?       (write-buffered Stderr " ")
10764 #?       (write-int32-hex-buffered Stderr *(esi+4))
10765 #?       (write-buffered Stderr Newline)
10766 #?       (flush Stderr)
10767 #?       (lookup *esi *(esi+4))
10768 #?       (write-buffered Stderr "created typeinfo fields at ")
10769 #?       (write-int32-hex-buffered Stderr %esi)
10770 #?       (write-buffered Stderr " for ")
10771 #?       (write-int32-hex-buffered Stderr *(ebp+8))
10772 #?       (write-buffered Stderr Newline)
10773 #?       (flush Stderr)
10774     }
10775     # *out = src
10776     # . *edi = *src
10777     8b/-> *esi 0/r32/eax
10778     89/<- *edi 0/r32/eax
10779     8b/-> *(esi+4) 0/r32/eax
10780     89/<- *(edi+4) 0/r32/eax
10781 $find-or-create-typeinfo-fields:end:
10782     # . restore registers
10783     5f/pop-to-edi
10784     5e/pop-to-esi
10785     58/pop-to-eax
10786     # . epilogue
10787     89/<- %esp 5/r32/ebp
10788     5d/pop-to-ebp
10789     c3/return
10790 
10791 populate-mu-type:  # in: (addr stream byte), t: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
10792     # pseudocode:
10793     #   var line: (stream byte 512)
10794     #   curr-index = 0
10795     #   while true
10796     #     clear-stream(line)
10797     #     read-line-buffered(in, line)
10798     #     if line->write == 0
10799     #       abort
10800     #     word-slice = next-mu-token(line)
10801     #     if slice-empty?(word-slice)               # end of line
10802     #       continue
10803     #     if slice-equal?(word-slice, "}")
10804     #       break
10805     #     var v: (handle var) = parse-var-with-type(word-slice, line)
10806     #     var r: (handle typeinfo-fields) = find-or-create-typeinfo-fields(t, word-slice/v->name)
10807     #     TODO: ensure that r->first is null
10808     #     r->index = curr-index
10809     #     curr-index++
10810     #     r->input-var = v
10811     #     if r->output-var == 0
10812     #       r->output-var = new literal
10813     #     TODO: ensure nothing else in line
10814     # t->total-size-in-bytes = -2 (not yet initialized)
10815     #
10816     # . prologue
10817     55/push-ebp
10818     89/<- %ebp 4/r32/esp
10819     # var curr-index: int at *(ebp-4)
10820     68/push 0/imm32
10821     # . save registers
10822     50/push-eax
10823     51/push-ecx
10824     52/push-edx
10825     53/push-ebx
10826     56/push-esi
10827     57/push-edi
10828     # edi = t
10829     8b/-> *(ebp+0xc) 7/r32/edi
10830     # var line/ecx: (stream byte 512)
10831     81 5/subop/subtract %esp 0x200/imm32
10832     68/push 0x200/imm32/size
10833     68/push 0/imm32/read
10834     68/push 0/imm32/write
10835     89/<- %ecx 4/r32/esp
10836     # var word-slice/edx: slice
10837     68/push 0/imm32/end
10838     68/push 0/imm32/start
10839     89/<- %edx 4/r32/esp
10840     # var v/esi: (handle var)
10841     68/push 0/imm32
10842     68/push 0/imm32
10843     89/<- %esi 4/r32/esp
10844     # var r/ebx: (handle typeinfo-entry)
10845     68/push 0/imm32
10846     68/push 0/imm32
10847     89/<- %ebx 4/r32/esp
10848     {
10849 $populate-mu-type:line-loop:
10850       (clear-stream %ecx)
10851       (read-line-buffered *(ebp+8) %ecx)
10852       # if (line->write == 0) abort
10853       81 7/subop/compare *ecx 0/imm32
10854       0f 84/jump-if-= $populate-mu-type:error1/disp32
10855 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
10861       (next-mu-token %ecx %edx)
10862       # if slice-empty?(word-slice) continue
10863       (slice-empty? %edx)  # => eax
10864       3d/compare-eax-and 0/imm32
10865       0f 85/jump-if-!= loop/disp32
10866       # if slice-equal?(word-slice, "}") break
10867       (slice-equal? %edx "}")
10868       3d/compare-eax-and 0/imm32
10869       0f 85/jump-if-!= break/disp32
10870 $populate-mu-type:parse-element:
10871       # v = parse-var-with-type(word-slice, first-line)
10872       # must do this first to strip the trailing ':' from word-slice before
10873       # using it in find-or-create-typeinfo-fields below
10874       # TODO: clean up that mutation in parse-var-with-type
10875       (parse-var-with-type %edx %ecx %esi *(ebp+0x10) *(ebp+0x14))
10876       # if v is an addr, abort
10877       (lookup *esi *(esi+4))  # => eax
10878       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10879       (is-mu-addr-type? %eax)  # => eax
10880       3d/compare-eax-and 0/imm32/false
10881       0f 85/jump-if-!= $populate-mu-type:error2/disp32
10882       # if v is an array, abort  (we could support it, but initialization gets complex)
10883       (lookup *esi *(esi+4))  # => eax
10884       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10885       (is-mu-array-type? %eax)  # => eax
10886       3d/compare-eax-and 0/imm32/false
10887       0f 85/jump-if-!= $populate-mu-type:error3/disp32
10888       # if v is a slice, abort
10889       (lookup *esi *(esi+4))  # => eax
10890       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10891       (is-simple-mu-type? %eax 0xc)  # slice => eax
10892       3d/compare-eax-and 0/imm32/false
10893       0f 85/jump-if-!= $populate-mu-type:error4/disp32
10894       # if v is a stream, abort  (we could support it, but initialization gets even more complex)
10895       (lookup *esi *(esi+4))  # => eax
10896       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10897       (is-mu-stream-type? %eax)  # => eax
10898       3d/compare-eax-and 0/imm32/false
10899       0f 85/jump-if-!= $populate-mu-type:error5/disp32
10900       # var tmp/ecx
10901       51/push-ecx
10902 $populate-mu-type:create-typeinfo-fields:
10903       # var r/ebx: (handle typeinfo-entry)
10904       (find-or-create-typeinfo-fields %edi %edx %ebx)
10905       # r->index = curr-index
10906       (lookup *ebx *(ebx+4))  # => eax
10907       8b/-> *(ebp-4) 1/r32/ecx
10908 #?       (write-buffered Stderr "saving index ")
10909 #?       (write-int32-hex-buffered Stderr %ecx)
10910 #?       (write-buffered Stderr " at ")
10911 #?       (write-int32-hex-buffered Stderr %edi)
10912 #?       (write-buffered Stderr Newline)
10913 #?       (flush Stderr)
10914       89/<- *(eax+8) 1/r32/ecx  # Typeinfo-entry-index
10915       # ++curr-index
10916       ff 0/subop/increment *(ebp-4)
10917 $populate-mu-type:set-input-type:
10918       # r->input-var = v
10919       8b/-> *esi 1/r32/ecx
10920       89/<- *eax 1/r32/ecx  # Typeinfo-entry-input-var
10921       8b/-> *(esi+4) 1/r32/ecx
10922       89/<- *(eax+4) 1/r32/ecx  # Typeinfo-entry-input-var
10923       # restore line
10924       59/pop-to-ecx
10925       {
10926 $populate-mu-type:create-output-type:
10927         # if (r->output-var == 0) create a new var with some placeholder data
10928         81 7/subop/compare *(eax+0xc) 0/imm32  # Typeinfo-entry-output-var
10929         75/jump-if-!= break/disp8
10930         8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
10931         (new-literal Heap %edx %eax)
10932       }
10933       e9/jump loop/disp32
10934     }
10935 $populate-mu-type:invalidate-total-size-in-bytes:
10936     # Offsets and total size may not be accurate here since we may not yet
10937     # have encountered the element types.
10938     # We'll recompute them separately after parsing the entire program.
10939     c7 0/subop/copy *(edi+0xc) -2/imm32/uninitialized  # Typeinfo-total-size-in-bytes
10940 $populate-mu-type:end:
10941     # . reclaim locals
10942     81 0/subop/add %esp 0x224/imm32
10943     # . restore registers
10944     5f/pop-to-edi
10945     5e/pop-to-esi
10946     5b/pop-to-ebx
10947     5a/pop-to-edx
10948     59/pop-to-ecx
10949     58/pop-to-eax
10950     # reclaim curr-index
10951     81 0/subop/add %esp 4/imm32
10952     # . epilogue
10953     89/<- %esp 5/r32/ebp
10954     5d/pop-to-ebp
10955     c3/return
10956 
10957 $populate-mu-type:error1:
10958     # error("incomplete type definition '" t->name "'\n")
10959     (write-buffered *(ebp+0x10) "incomplete type definition '")
10960     (type-name *edi)  # Typeinfo-id => eax
10961     (write-buffered *(ebp+0x10) %eax)
10962     (write-buffered *(ebp+0x10) "\n")
10963     (flush *(ebp+0x10))
10964     (stop *(ebp+0x14) 1)
10965     # never gets here
10966 
10967 $populate-mu-type:error2:
10968     (write-buffered *(ebp+0x10) "type ")
10969     (type-name *edi)  # Typeinfo-id => eax
10970     (write-buffered *(ebp+0x10) %eax)
10971     (write-buffered *(ebp+0x10) ": 'addr' elements not allowed\n")
10972     (flush *(ebp+0x10))
10973     (stop *(ebp+0x14) 1)
10974     # never gets here
10975 
10976 $populate-mu-type:error3:
10977     (write-buffered *(ebp+0x10) "type ")
10978     (type-name *edi)  # Typeinfo-id => eax
10979     (write-buffered *(ebp+0x10) %eax)
10980     (write-buffered *(ebp+0x10) ": 'array' elements not allowed for now\n")
10981     (flush *(ebp+0x10))
10982     (stop *(ebp+0x14) 1)
10983     # never gets here
10984 
10985 $populate-mu-type:error4:
10986     (write-buffered *(ebp+0x10) "type ")
10987     (type-name *edi)  # Typeinfo-id => eax
10988     (write-buffered *(ebp+0x10) %eax)
10989     (write-buffered *(ebp+0x10) ": 'slice' elements not allowed\n")
10990     (flush *(ebp+0x10))
10991     (stop *(ebp+0x14) 1)
10992     # never gets here
10993 
10994 $populate-mu-type:error5:
10995     (write-buffered *(ebp+0x10) "type ")
10996     (type-name *edi)  # Typeinfo-id => eax
10997     (write-buffered *(ebp+0x10) %eax)
10998     (write-buffered *(ebp+0x10) ": 'stream' elements not allowed for now\n")
10999     (flush *(ebp+0x10))
11000     (stop *(ebp+0x14) 1)
11001     # never gets here
11002 
11003 type-name:  # index: int -> result/eax: (addr array byte)
11004     # . prologue
11005     55/push-ebp
11006     89/<- %ebp 4/r32/esp
11007     #
11008     (index Type-id *(ebp+8))
11009 $type-name:end:
11010     # . epilogue
11011     89/<- %esp 5/r32/ebp
11012     5d/pop-to-ebp
11013     c3/return
11014 
11015 index:  # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte)
11016     # . prologue
11017     55/push-ebp
11018     89/<- %ebp 4/r32/esp
11019     # . save registers
11020     56/push-esi
11021     # TODO: bounds-check index
11022     # esi = arr
11023     8b/-> *(ebp+8) 6/r32/esi
11024     # eax = index
11025     8b/-> *(ebp+0xc) 0/r32/eax
11026     # eax = *(arr + 12 + index)
11027     8b/-> *(esi+eax<<2+0xc) 0/r32/eax
11028 $index:end:
11029     # . restore registers
11030     5e/pop-to-esi
11031     # . epilogue
11032     89/<- %esp 5/r32/ebp
11033     5d/pop-to-ebp
11034     c3/return
11035 
11036 #######################################################
11037 # Compute type sizes
11038 #######################################################
11039 
11040 # Compute the sizes of all user-defined types.
11041 # We'll need the sizes of their elements, which may be other user-defined
11042 # types, which we will compute as needed.
11043 
11044 # Initially, all user-defined types have their sizes set to -2 (invalid)
11045 populate-mu-type-sizes:  # err: (addr buffered-file), ed: (addr exit-descriptor)
11046     # . prologue
11047     55/push-ebp
11048     89/<- %ebp 4/r32/esp
11049 $populate-mu-type-sizes:total-sizes:
11050     # var curr/eax: (addr typeinfo) = lookup(Program->types)
11051     (lookup *_Program-types *_Program-types->payload)  # => eax
11052     {
11053       # if (curr == null) break
11054       3d/compare-eax-and 0/imm32/null
11055       74/jump-if-= break/disp8
11056       (populate-mu-type-sizes-in-type %eax *(ebp+8) *(ebp+0xc))
11057       # curr = lookup(curr->next)
11058       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
11059       eb/jump loop/disp8
11060     }
11061 $populate-mu-type-sizes:offsets:
11062     # curr = *Program->types
11063     (lookup *_Program-types *_Program-types->payload)  # => eax
11064     {
11065       # if (curr == null) break
11066       3d/compare-eax-and 0/imm32/null
11067       74/jump-if-= break/disp8
11068       (populate-mu-type-offsets %eax *(ebp+8) *(ebp+0xc))
11069       # curr = curr->next
11070       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
11071       eb/jump loop/disp8
11072     }
11073 $populate-mu-type-sizes:end:
11074     # . epilogue
11075     89/<- %esp 5/r32/ebp
11076     5d/pop-to-ebp
11077     c3/return
11078 
11079 # compute sizes of all fields, recursing as necessary
11080 # sum up all their sizes to arrive at total size
11081 # fields may be out of order, but that doesn't affect the answer
11082 populate-mu-type-sizes-in-type:  # T: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
11083     # . prologue
11084     55/push-ebp
11085     89/<- %ebp 4/r32/esp
11086     # . save registers
11087     50/push-eax
11088     51/push-ecx
11089     52/push-edx
11090     56/push-esi
11091     57/push-edi
11092     # esi = T
11093     8b/-> *(ebp+8) 6/r32/esi
11094     # if T is already computed, return
11095     81 7/subop/compare *(esi+0xc) 0/imm32  # Typeinfo-total-size-in-bytes
11096     0f 8d/jump-if->= $populate-mu-type-sizes-in-type:end/disp32
11097     # if T is being computed, abort
11098     81 7/subop/compare *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
11099     0f 84/jump-if-= $populate-mu-type-sizes-in-type:abort/disp32
11100     # tag T (-2 to -1) to avoid infinite recursion
11101     c7 0/subop/copy *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
11102     # var total-size/edi: int = 0
11103     bf/copy-to-edi 0/imm32
11104     # - for every field, if it's a user-defined type, compute its size
11105     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
11106     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
11107     89/<- %ecx 0/r32/eax
11108     # var table-size/edx: int = table->write
11109     8b/-> *ecx 2/r32/edx  # stream-write
11110     # var curr/ecx: (addr table_row) = table->data
11111     8d/copy-address *(ecx+0xc) 1/r32/ecx
11112     # var max/edx: (addr table_row) = table->data + table->write
11113     8d/copy-address *(ecx+edx) 2/r32/edx
11114     {
11115 $populate-mu-type-sizes-in-type:loop:
11116       # if (curr >= max) break
11117       39/compare %ecx 2/r32/edx
11118       73/jump-if-addr>= break/disp8
11119       # var t/eax: (addr typeinfo-entry) = lookup(curr->value)
11120       (lookup *(ecx+8) *(ecx+0xc))  # => eax
11121       # if (t->input-var == 0) silently ignore it; we'll emit a nice error message while type-checking
11122       81 7/subop/compare *eax 0/imm32  # Typeinfo-entry-input-var
11123       74/jump-if-= $populate-mu-type-sizes-in-type:end/disp8
11124       # compute size of t->input-var
11125       (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
11126       (compute-size-of-var %eax *(ebp+0xc) *(ebp+0x10))  # => eax
11127       # result += eax
11128       01/add-to %edi 0/r32/eax
11129       # curr += row-size
11130       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
11131       #
11132       eb/jump loop/disp8
11133     }
11134     # - save result
11135     89/<- *(esi+0xc) 7/r32/edi  # Typeinfo-total-size-in-bytes
11136 $populate-mu-type-sizes-in-type:end:
11137     # . restore registers
11138     5f/pop-to-edi
11139     5e/pop-to-esi
11140     5a/pop-to-edx
11141     59/pop-to-ecx
11142     58/pop-to-eax
11143     # . epilogue
11144     89/<- %esp 5/r32/ebp
11145     5d/pop-to-ebp
11146     c3/return
11147 
11148 $populate-mu-type-sizes-in-type:abort:
11149     (write-buffered *(ebp+0xc) "cycle in type definitions\n")
11150     (flush *(ebp+0xc))
11151     (stop *(ebp+0x10) 1)
11152     # never gets here
11153 
11154 # Analogous to size-of, except we need to compute what size-of can just read
11155 # off the right data structures.
11156 compute-size-of-var:  # in: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
11157     # . prologue
11158     55/push-ebp
11159     89/<- %ebp 4/r32/esp
11160     # . push registers
11161     51/push-ecx
11162     # var t/ecx: (addr type-tree) = lookup(v->type)
11163     8b/-> *(ebp+8) 1/r32/ecx
11164     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
11165     89/<- %ecx 0/r32/eax
11166     # if (t->is-atom == false) t = lookup(t->left)
11167     {
11168       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
11169       75/jump-if-!= break/disp8
11170       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
11171       89/<- %ecx 0/r32/eax
11172     }
11173     # TODO: ensure t is an atom
11174     (compute-size-of-type-id *(ecx+4) *(ebp+0xc) *(ebp+0x10))  # Type-tree-value => eax
11175 $compute-size-of-var:end:
11176     # . restore registers
11177     59/pop-to-ecx
11178     # . epilogue
11179     89/<- %esp 5/r32/ebp
11180     5d/pop-to-ebp
11181     c3/return
11182 
11183 compute-size-of-type-id:  # t: type-id, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
11184     # . prologue
11185     55/push-ebp
11186     89/<- %ebp 4/r32/esp
11187     # . save registers
11188     51/push-ecx
11189     # var out/ecx: (handle typeinfo)
11190     68/push 0/imm32
11191     68/push 0/imm32
11192     89/<- %ecx 4/r32/esp
11193     # eax = t
11194     8b/-> *(ebp+8) 0/r32/eax
11195     # if t is a literal, return 0
11196     3d/compare-eax-and 0/imm32/literal
11197     0f 84/jump-if-= $compute-size-of-type-id:end/disp32  # eax changes type from type-id to int
11198     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
11199     3d/compare-eax-and 8/imm32/byte
11200     {
11201       75/jump-if-!= break/disp8
11202       b8/copy-to-eax 4/imm32
11203       eb/jump $compute-size-of-type-id:end/disp8
11204     }
11205     # if t is a handle, return 8
11206     3d/compare-eax-and 4/imm32/handle
11207     {
11208       75/jump-if-!= break/disp8
11209       b8/copy-to-eax 8/imm32
11210       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
11211     }
11212     # if t is a slice, return 8
11213     3d/compare-eax-and 0xc/imm32/slice
11214     {
11215       75/jump-if-!= break/disp8
11216       b8/copy-to-eax 8/imm32
11217       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
11218     }
11219     # if t is a user-defined type, compute its size
11220     # TODO: support non-atom type
11221     (find-typeinfo %eax %ecx)
11222     {
11223       81 7/subop/compare *ecx 0/imm32
11224       74/jump-if-= break/disp8
11225 $compute-size-of-type-id:user-defined:
11226       (lookup *ecx *(ecx+4))  # => eax
11227       (populate-mu-type-sizes-in-type %eax *(ebp+0xc) *(ebp+0x10))
11228       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
11229       eb/jump $compute-size-of-type-id:end/disp8
11230     }
11231     # otherwise return the word size
11232     b8/copy-to-eax 4/imm32
11233 $compute-size-of-type-id:end:
11234     # . reclaim locals
11235     81 0/subop/add %esp 8/imm32
11236     # . restore registers
11237     59/pop-to-ecx
11238     # . epilogue
11239     89/<- %esp 5/r32/ebp
11240     5d/pop-to-ebp
11241     c3/return
11242 
11243 # at this point we have total sizes for all user-defined types
11244 # compute offsets for each element
11245 # complication: fields may be out of order
11246 populate-mu-type-offsets:  # in: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
11247     # . prologue
11248     55/push-ebp
11249     89/<- %ebp 4/r32/esp
11250     # . save registers
11251     50/push-eax
11252     51/push-ecx
11253     52/push-edx
11254     53/push-ebx
11255     56/push-esi
11256     57/push-edi
11257 #?     (dump-typeinfos "aaa\n")
11258     # var curr-offset/edi: int = 0
11259     bf/copy-to-edi 0/imm32
11260     # var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(in->fields)
11261     8b/-> *(ebp+8) 1/r32/ecx
11262     (lookup *(ecx+4) *(ecx+8))  # Typeinfo-fields Typeinfo-fields => eax
11263     89/<- %ecx 0/r32/eax
11264     # var num-elems/edx: int = table->write / Typeinfo-fields-row-size
11265     8b/-> *ecx 2/r32/edx  # stream-write
11266     c1 5/subop/shift-right-logical  %edx 4/imm8
11267     # var i/ebx: int = 0
11268     bb/copy-to-ebx 0/imm32
11269     {
11270 $populate-mu-type-offsets:loop:
11271       39/compare %ebx 2/r32/edx
11272       0f 8d/jump-if->= break/disp32
11273 #?       (write-buffered Stderr "looking up index ")
11274 #?       (write-int32-hex-buffered Stderr %ebx)
11275 #?       (write-buffered Stderr " in ")
11276 #?       (write-int32-hex-buffered Stderr *(ebp+8))
11277 #?       (write-buffered Stderr Newline)
11278 #?       (flush Stderr)
11279       # var v/esi: (addr typeinfo-entry)
11280       (locate-typeinfo-entry-with-index %ecx %ebx *(ebp+0xc) *(ebp+0x10))  # => eax
11281       89/<- %esi 0/r32/eax
11282       # if v is null, silently move on; we'll emit a nice error message while type-checking
11283       81 7/subop/compare %esi 0/imm32  # Typeinfo-entry-input-var
11284       74/jump-if-= $populate-mu-type-offsets:end/disp8
11285       # if (v->input-var == 0) silently ignore v; we'll emit a nice error message while type-checking
11286       81 7/subop/compare *esi 0/imm32  # Typeinfo-entry-input-var
11287       74/jump-if-= $populate-mu-type-offsets:end/disp8
11288       # v->output-var->offset = curr-offset
11289       # . eax: (addr var)
11290       (lookup *(esi+0xc) *(esi+0x10))  # Typeinfo-entry-output-var Typeinfo-entry-output-var => eax
11291       89/<- *(eax+0x14) 7/r32/edi  # Var-offset
11292       # curr-offset += size-of(v->input-var)
11293       (lookup *esi *(esi+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
11294       (size-of %eax)  # => eax
11295       01/add-to %edi 0/r32/eax
11296       # ++i
11297       43/increment-ebx
11298       e9/jump loop/disp32
11299     }
11300 $populate-mu-type-offsets:end:
11301     # . restore registers
11302     5f/pop-to-edi
11303     5e/pop-to-esi
11304     5b/pop-to-ebx
11305     5a/pop-to-edx
11306     59/pop-to-ecx
11307     58/pop-to-eax
11308     # . epilogue
11309     89/<- %esp 5/r32/ebp
11310     5d/pop-to-ebp
11311     c3/return
11312 
11313 locate-typeinfo-entry-with-index:  # table: (addr table (handle array byte) (handle typeinfo-entry)), idx: int, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: (addr typeinfo-entry)
11314     # . prologue
11315     55/push-ebp
11316     89/<- %ebp 4/r32/esp
11317     # . save registers
11318     51/push-ecx
11319     52/push-edx
11320     53/push-ebx
11321     56/push-esi
11322     57/push-edi
11323     # esi = table
11324     8b/-> *(ebp+8) 6/r32/esi
11325     # var curr/ecx: (addr row (handle array byte) (handle typeinfo-entry)) = table->data
11326     8d/copy-address *(esi+0xc) 1/r32/ecx
11327     # var max/edx: (addr byte) = &table->data[table->write]
11328     8b/-> *esi 2/r32/edx
11329     8d/copy-address *(ecx+edx) 2/r32/edx
11330     {
11331 $locate-typeinfo-entry-with-index:loop:
11332       39/compare %ecx 2/r32/edx
11333       73/jump-if-addr>= break/disp8
11334       # var v/eax: (addr typeinfo-entry)
11335       (lookup *(ecx+8) *(ecx+0xc))  # => eax
11336       # if (v->index == idx) return v
11337       8b/-> *(eax+8) 3/r32/ebx  # Typeinfo-entry-index
11338 #?       (write-buffered Stderr "comparing ")
11339 #?       (write-int32-hex-buffered Stderr %ebx)
11340 #?       (write-buffered Stderr " and ")
11341 #?       (write-int32-hex-buffered Stderr *(ebp+0xc))
11342 #?       (write-buffered Stderr Newline)
11343 #?       (flush Stderr)
11344       39/compare *(ebp+0xc) 3/r32/ebx
11345       74/jump-if-= $locate-typeinfo-entry-with-index:end/disp8
11346       # curr += Typeinfo-entry-size
11347       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-entry-size
11348       #
11349       eb/jump loop/disp8
11350     }
11351     # return 0
11352     b8/copy-to-eax 0/imm32
11353 $locate-typeinfo-entry-with-index:end:
11354 #?     (write-buffered Stderr "returning ")
11355 #?     (write-int32-hex-buffered Stderr %eax)
11356 #?     (write-buffered Stderr Newline)
11357 #?     (flush Stderr)
11358     # . restore registers
11359     5f/pop-to-edi
11360     5e/pop-to-esi
11361     5b/pop-to-ebx
11362     5a/pop-to-edx
11363     59/pop-to-ecx
11364     # . epilogue
11365     89/<- %esp 5/r32/ebp
11366     5d/pop-to-ebp
11367     c3/return
11368 
11369 dump-typeinfos:  # hdr: (addr array byte)
11370     # . prologue
11371     55/push-ebp
11372     89/<- %ebp 4/r32/esp
11373     # . save registers
11374     50/push-eax
11375     #
11376     (write-buffered Stderr *(ebp+8))
11377     (flush Stderr)
11378     # var curr/eax: (addr typeinfo) = lookup(Program->types)
11379     (lookup *_Program-types *_Program-types->payload)  # => eax
11380     {
11381       # if (curr == null) break
11382       3d/compare-eax-and 0/imm32
11383       74/jump-if-= break/disp8
11384       (write-buffered Stderr "---\n")
11385       (flush Stderr)
11386       (dump-typeinfo %eax)
11387       # curr = lookup(curr->next)
11388       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
11389       eb/jump loop/disp8
11390     }
11391 $dump-typeinfos:end:
11392     # . restore registers
11393     58/pop-to-eax
11394     # . epilogue
11395     89/<- %esp 5/r32/ebp
11396     5d/pop-to-ebp
11397     c3/return
11398 
11399 dump-typeinfo:  # in: (addr typeinfo)
11400     # . prologue
11401     55/push-ebp
11402     89/<- %ebp 4/r32/esp
11403     # . save registers
11404     50/push-eax
11405     51/push-ecx
11406     52/push-edx
11407     53/push-ebx
11408     56/push-esi
11409     57/push-edi
11410     # esi = in
11411     8b/-> *(ebp+8) 6/r32/esi
11412     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
11413     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
11414     89/<- %ecx 0/r32/eax
11415     (write-buffered Stderr "id:")
11416     (write-int32-hex-buffered Stderr *esi)
11417     (write-buffered Stderr "\n")
11418     (write-buffered Stderr "fields @ ")
11419     (write-int32-hex-buffered Stderr %ecx)
11420     (write-buffered Stderr Newline)
11421     (flush Stderr)
11422     (write-buffered Stderr "  write: ")
11423     (write-int32-hex-buffered Stderr *ecx)
11424     (write-buffered Stderr Newline)
11425     (flush Stderr)
11426     (write-buffered Stderr "  read: ")
11427     (write-int32-hex-buffered Stderr *(ecx+4))
11428     (write-buffered Stderr Newline)
11429     (flush Stderr)
11430     (write-buffered Stderr "  size: ")
11431     (write-int32-hex-buffered Stderr *(ecx+8))
11432     (write-buffered Stderr Newline)
11433     (flush Stderr)
11434     # var table-size/edx: int = table->write
11435     8b/-> *ecx 2/r32/edx  # stream-write
11436     # var curr/ecx: (addr table_row) = table->data
11437     8d/copy-address *(ecx+0xc) 1/r32/ecx
11438     # var max/edx: (addr table_row) = table->data + table->write
11439     8d/copy-address *(ecx+edx) 2/r32/edx
11440     {
11441 $dump-typeinfo:loop:
11442       # if (curr >= max) break
11443       39/compare %ecx 2/r32/edx
11444       0f 83/jump-if-addr>= break/disp32
11445       (write-buffered Stderr "  row:\n")
11446       (write-buffered Stderr "    key: ")
11447       (write-int32-hex-buffered Stderr *ecx)
11448       (write-buffered Stderr ",")
11449       (write-int32-hex-buffered Stderr *(ecx+4))
11450       (write-buffered Stderr " = '")
11451       (lookup *ecx *(ecx+4))
11452       (write-buffered Stderr %eax)
11453       (write-buffered Stderr "' @ ")
11454       (write-int32-hex-buffered Stderr %eax)
11455       (write-buffered Stderr Newline)
11456       (flush Stderr)
11457       (write-buffered Stderr "    value: ")
11458       (write-int32-hex-buffered Stderr *(ecx+8))
11459       (write-buffered Stderr ",")
11460       (write-int32-hex-buffered Stderr *(ecx+0xc))
11461       (write-buffered Stderr " = typeinfo-entry@")
11462       (lookup *(ecx+8) *(ecx+0xc))
11463       (write-int32-hex-buffered Stderr %eax)
11464       (write-buffered Stderr Newline)
11465       (flush Stderr)
11466       (write-buffered Stderr "        input var@")
11467       (dump-var 5 %eax)
11468       (lookup *(ecx+8) *(ecx+0xc))
11469       (write-buffered Stderr "        index: ")
11470       (write-int32-hex-buffered Stderr *(eax+8))
11471       (write-buffered Stderr Newline)
11472       (flush Stderr)
11473       (write-buffered Stderr "        output var@")
11474       8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
11475       (dump-var 5 %eax)
11476       (flush Stderr)
11477       # curr += row-size
11478       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
11479       #
11480       e9/jump loop/disp32
11481     }
11482 $dump-typeinfo:end:
11483     # . restore registers
11484     5f/pop-to-edi
11485     5e/pop-to-esi
11486     5b/pop-to-ebx
11487     5a/pop-to-edx
11488     59/pop-to-ecx
11489     58/pop-to-eax
11490     # . epilogue
11491     89/<- %esp 5/r32/ebp
11492     5d/pop-to-ebp
11493     c3/return
11494 
11495 dump-var:  # indent: int, v: (addr handle var)
11496     # . prologue
11497     55/push-ebp
11498     89/<- %ebp 4/r32/esp
11499     # . save registers
11500     50/push-eax
11501     53/push-ebx
11502     # eax = v
11503     8b/-> *(ebp+0xc) 0/r32/eax
11504     #
11505     (write-int32-hex-buffered Stderr *eax)
11506     (write-buffered Stderr ",")
11507     (write-int32-hex-buffered Stderr *(eax+4))
11508     (write-buffered Stderr "->")
11509     (lookup *eax *(eax+4))
11510     (write-int32-hex-buffered Stderr %eax)
11511     (write-buffered Stderr Newline)
11512     (flush Stderr)
11513     {
11514       3d/compare-eax-and 0/imm32
11515       0f 84/jump-if-= break/disp32
11516       (emit-indent Stderr *(ebp+8))
11517       (write-buffered Stderr "name: ")
11518       89/<- %ebx 0/r32/eax
11519       (write-int32-hex-buffered Stderr *ebx)  # Var-name
11520       (write-buffered Stderr ",")
11521       (write-int32-hex-buffered Stderr *(ebx+4))  # Var-name
11522       (write-buffered Stderr "->")
11523       (lookup *ebx *(ebx+4))  # Var-name
11524       (write-int32-hex-buffered Stderr %eax)
11525       {
11526         3d/compare-eax-and 0/imm32
11527         74/jump-if-= break/disp8
11528         (write-buffered Stderr Space)
11529         (write-buffered Stderr %eax)
11530       }
11531       (write-buffered Stderr Newline)
11532       (flush Stderr)
11533       (emit-indent Stderr *(ebp+8))
11534       (write-buffered Stderr "block depth: ")
11535       (write-int32-hex-buffered Stderr *(ebx+0x10))  # Var-block-depth
11536       (write-buffered Stderr Newline)
11537       (flush Stderr)
11538       (emit-indent Stderr *(ebp+8))
11539       (write-buffered Stderr "stack offset: ")
11540       (write-int32-hex-buffered Stderr *(ebx+0x14))  # Var-offset
11541       (write-buffered Stderr Newline)
11542       (flush Stderr)
11543       (emit-indent Stderr *(ebp+8))
11544       (write-buffered Stderr "reg: ")
11545       (write-int32-hex-buffered Stderr *(ebx+0x18))  # Var-register
11546       (write-buffered Stderr ",")
11547       (write-int32-hex-buffered Stderr *(ebx+0x1c))  # Var-register
11548       (write-buffered Stderr "->")
11549       (flush Stderr)
11550       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register
11551       (write-int32-hex-buffered Stderr %eax)
11552       {
11553         3d/compare-eax-and 0/imm32
11554         74/jump-if-= break/disp8
11555         (write-buffered Stderr Space)
11556         (write-buffered Stderr %eax)
11557       }
11558       (write-buffered Stderr Newline)
11559       (flush Stderr)
11560     }
11561 $dump-var:end:
11562     # . restore registers
11563     5b/pop-to-ebx
11564     58/pop-to-eax
11565     # . epilogue
11566     89/<- %esp 5/r32/ebp
11567     5d/pop-to-ebp
11568     c3/return
11569 
11570 #######################################################
11571 # Type-checking
11572 #######################################################
11573 
11574 check-mu-types:  # err: (addr buffered-file), ed: (addr exit-descriptor)
11575     # . prologue
11576     55/push-ebp
11577     89/<- %ebp 4/r32/esp
11578     # . save registers
11579     50/push-eax
11580     # var curr/eax: (addr function) = lookup(Program->functions)
11581     (lookup *_Program-functions *_Program-functions->payload)  # => eax
11582     {
11583 $check-mu-types:loop:
11584       # if (curr == null) break
11585       3d/compare-eax-and 0/imm32
11586       0f 84/jump-if-= break/disp32
11587 +--  8 lines: #?       # dump curr->name ------------------------------------------------------------------------------------------------------------------------------------------------
11595       (check-mu-function %eax *(ebp+8) *(ebp+0xc))
11596       # curr = lookup(curr->next)
11597       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
11598       e9/jump loop/disp32
11599     }
11600 $check-mu-types:end:
11601     # . restore registers
11602     58/pop-to-eax
11603     # . epilogue
11604     89/<- %esp 5/r32/ebp
11605     5d/pop-to-ebp
11606     c3/return
11607 
11608 check-mu-function:  # fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11609     # . prologue
11610     55/push-ebp
11611     89/<- %ebp 4/r32/esp
11612     # . save registers
11613     50/push-eax
11614     # eax = f
11615     8b/-> *(ebp+8) 0/r32/eax
11616     # TODO: anything to check in header?
11617     # var body/eax: (addr block) = lookup(f->body)
11618     (lookup *(eax+0x18) *(eax+0x1c))  # Function-body Function-body => eax
11619     (check-mu-block %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10))
11620 $check-mu-function:end:
11621     # . restore registers
11622     58/pop-to-eax
11623     # . epilogue
11624     89/<- %esp 5/r32/ebp
11625     5d/pop-to-ebp
11626     c3/return
11627 
11628 check-mu-block:  # block: (addr block), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11629     # . prologue
11630     55/push-ebp
11631     89/<- %ebp 4/r32/esp
11632     # . save registers
11633     50/push-eax
11634     # eax = block
11635     8b/-> *(ebp+8) 0/r32/eax
11636     # var stmts/eax: (addr list stmt) = lookup(block->statements)
11637     (lookup *(eax+4) *(eax+8))  # Block-stmts Block-stmts => eax
11638     #
11639     {
11640 $check-mu-block:check-empty:
11641       3d/compare-eax-and 0/imm32
11642       0f 84/jump-if-= break/disp32
11643       # emit block->statements
11644       (check-mu-stmt-list %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11645     }
11646 $check-mu-block:end:
11647     # . restore registers
11648     58/pop-to-eax
11649     # . epilogue
11650     89/<- %esp 5/r32/ebp
11651     5d/pop-to-ebp
11652     c3/return
11653 
11654 check-mu-stmt-list:  # stmts: (addr list stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11655     # . prologue
11656     55/push-ebp
11657     89/<- %ebp 4/r32/esp
11658     # . save registers
11659     50/push-eax
11660     56/push-esi
11661     # esi = stmts
11662     8b/-> *(ebp+8) 6/r32/esi
11663     {
11664 $check-mu-stmt-list:loop:
11665       81 7/subop/compare %esi 0/imm32
11666       0f 84/jump-if-= break/disp32
11667       # var curr-stmt/eax: (addr stmt) = lookup(stmts->value)
11668       (lookup *esi *(esi+4))  # List-value List-value => eax
11669       {
11670 $check-mu-stmt-list:check-for-block:
11671         81 7/subop/compare *eax 0/imm32/block  # Stmt-tag
11672         75/jump-if-!= break/disp8
11673 $check-mu-stmt-list:block:
11674         (check-mu-block %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11675         eb/jump $check-mu-stmt-list:continue/disp8
11676       }
11677       {
11678 $check-mu-stmt-list:check-for-stmt1:
11679         81 7/subop/compare *eax 1/imm32/stmt1  # Stmt-tag
11680         0f 85/jump-if-!= break/disp32
11681 $check-mu-stmt-list:stmt1:
11682         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11683         eb/jump $check-mu-stmt-list:continue/disp8
11684       }
11685       {
11686 $check-mu-stmt-list:check-for-reg-var-def:
11687         81 7/subop/compare *eax 3/imm32/reg-var-def  # Stmt-tag
11688         0f 85/jump-if-!= break/disp32
11689 $check-mu-stmt-list:reg-var-def:
11690         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11691         eb/jump $check-mu-stmt-list:continue/disp8
11692       }
11693 $check-mu-stmt-list:continue:
11694       # TODO: raise an error on unrecognized Stmt-tag
11695       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
11696       89/<- %esi 0/r32/eax
11697       e9/jump loop/disp32
11698     }
11699 $check-mu-stmt-list:end:
11700     # . restore registers
11701     5e/pop-to-esi
11702     58/pop-to-eax
11703     # . epilogue
11704     89/<- %esp 5/r32/ebp
11705     5d/pop-to-ebp
11706     c3/return
11707 
11708 check-mu-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11709     # . prologue
11710     55/push-ebp
11711     89/<- %ebp 4/r32/esp
11712     # . save registers
11713     50/push-eax
11714     # - if stmt's operation matches a primitive, check against it
11715     (has-primitive-name? *(ebp+8))  # => eax
11716     3d/compare-eax-and 0/imm32/false
11717     {
11718       74/jump-if-= break/disp8
11719       (check-mu-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11720       e9/jump $check-mu-stmt:end/disp32
11721     }
11722     # - otherwise find a function to check against
11723     # var f/eax: (addr function) = lookup(*Program->functions)
11724     (lookup *_Program-functions *_Program-functions->payload)  # => eax
11725     (find-matching-function %eax *(ebp+8))  # => eax
11726     3d/compare-eax-and 0/imm32
11727     {
11728       74/jump-if-= break/disp8
11729       (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11730       eb/jump $check-mu-stmt:end/disp8
11731     }
11732     # var f/eax: (addr function) = lookup(*Program->signatures)
11733     (lookup *_Program-signatures *_Program-signatures->payload)  # => eax
11734     (find-matching-function %eax *(ebp+8))  # => eax
11735     3d/compare-eax-and 0/imm32
11736     {
11737       74/jump-if-= break/disp8
11738       (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11739       eb/jump $check-mu-stmt:end/disp8
11740     }
11741     # - otherwise abort
11742     e9/jump $check-mu-stmt:unknown-call/disp32
11743 $check-mu-stmt:end:
11744     # . restore registers
11745     58/pop-to-eax
11746     # . epilogue
11747     89/<- %esp 5/r32/ebp
11748     5d/pop-to-ebp
11749     c3/return
11750 
11751 $check-mu-stmt:unknown-call:
11752     (write-buffered *(ebp+0x10) "unknown function '")
11753     8b/-> *(ebp+8) 0/r32/eax
11754     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
11755     (write-buffered *(ebp+0x10) %eax)
11756     (write-buffered *(ebp+0x10) "'\n")
11757     (flush *(ebp+0x10))
11758     (stop *(ebp+0x14) 1)
11759     # never gets here
11760 
11761 has-primitive-name?:  # stmt: (addr stmt) -> result/eax: boolean
11762     # . prologue
11763     55/push-ebp
11764     89/<- %ebp 4/r32/esp
11765     # . save registers
11766     51/push-ecx
11767     56/push-esi
11768     # var name/esi: (addr array byte) = lookup(stmt->operation)
11769     8b/-> *(ebp+8) 6/r32/esi
11770     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
11771     89/<- %esi 0/r32/eax
11772     # if (name == "get") return true
11773     (string-equal? %esi "get")  # => eax
11774     3d/compare-eax-and 0/imm32/false
11775     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11776     # if (name == "index") return true
11777     (string-equal? %esi "index")  # => eax
11778     3d/compare-eax-and 0/imm32/false
11779     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11780     # if (name == "length") return true
11781     (string-equal? %esi "length")  # => eax
11782     3d/compare-eax-and 0/imm32/false
11783     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11784     # if (name == "compute-offset") return true
11785     (string-equal? %esi "compute-offset")  # => eax
11786     3d/compare-eax-and 0/imm32/false
11787     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11788     # if (name == "allocate") return true
11789     (string-equal? %esi "allocate")  # => eax
11790     3d/compare-eax-and 0/imm32/false
11791     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11792     # if (name == "populate") return true
11793     (string-equal? %esi "populate")  # => eax
11794     3d/compare-eax-and 0/imm32/false
11795     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11796     # if (name == "populate-stream") return true
11797     (string-equal? %esi "populate-stream")  # => eax
11798     3d/compare-eax-and 0/imm32/false
11799     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11800     # if (name == "read-from-stream") return true
11801     (string-equal? %esi "read-from-stream")  # => eax
11802     3d/compare-eax-and 0/imm32/false
11803     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11804     # if (name == "write-to-stream") return true
11805     (string-equal? %esi "write-to-stream")  # => eax
11806     3d/compare-eax-and 0/imm32/false
11807     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11808     # var curr/ecx: (addr primitive) = Primitives
11809     b9/copy-to-ecx Primitives/imm32
11810     {
11811 $has-primitive-name?:loop:
11812       # if (curr == null) break
11813       81 7/subop/compare %ecx 0/imm32
11814       74/jump-if-= break/disp8
11815       # if (primitive->name == name) return true
11816       (lookup *ecx *(ecx+4))  # Primitive-name Primitive-name => eax
11817       (string-equal? %esi %eax)  # => eax
11818       3d/compare-eax-and 0/imm32/false
11819       75/jump-if-!= $has-primitive-name?:end/disp8
11820 $has-primitive-name?:next-primitive:
11821       # curr = curr->next
11822       (lookup *(ecx+0x38) *(ecx+0x3c))  # Primitive-next Primitive-next => eax
11823       89/<- %ecx 0/r32/eax
11824       #
11825       e9/jump loop/disp32
11826     }
11827     # return null
11828     b8/copy-to-eax 0/imm32
11829 $has-primitive-name?:end:
11830     # . restore registers
11831     5e/pop-to-esi
11832     59/pop-to-ecx
11833     # . epilogue
11834     89/<- %esp 5/r32/ebp
11835     5d/pop-to-ebp
11836     c3/return
11837 
11838 check-mu-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11839     # . prologue
11840     55/push-ebp
11841     89/<- %ebp 4/r32/esp
11842     # . save registers
11843     50/push-eax
11844     51/push-ecx
11845     # var op/ecx: (addr array byte) = lookup(stmt->operation)
11846     8b/-> *(ebp+8) 0/r32/eax
11847     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
11848     89/<- %ecx 0/r32/eax
11849     # if (op == "copy") check-mu-copy-stmt
11850     {
11851       (string-equal? %ecx "copy")  # => eax
11852       3d/compare-eax-and 0/imm32/false
11853       74/jump-if-= break/disp8
11854       (check-mu-copy-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11855       e9/jump $check-mu-primitive:end/disp32
11856     }
11857     # if (op == "copy-to") check-mu-copy-to-stmt
11858     {
11859       (string-equal? %ecx "copy-to")  # => eax
11860       3d/compare-eax-and 0/imm32/false
11861       74/jump-if-= break/disp8
11862       (check-mu-copy-to-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11863       e9/jump $check-mu-primitive:end/disp32
11864     }
11865     # if (op == "compare") check-mu-compare-stmt
11866     {
11867       (string-equal? %ecx "compare")  # => eax
11868       3d/compare-eax-and 0/imm32/false
11869       74/jump-if-= break/disp8
11870       (check-mu-compare-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11871       e9/jump $check-mu-primitive:end/disp32
11872     }
11873     # if (op == "address") check-mu-address-stmt
11874     {
11875       (string-equal? %ecx "address")  # => eax
11876       3d/compare-eax-and 0/imm32/false
11877       74/jump-if-= break/disp8
11878       (check-mu-address-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11879       e9/jump $check-mu-primitive:end/disp32
11880     }
11881     # if (op == "get") check-mu-get-stmt
11882     {
11883       (string-equal? %ecx "get")  # => eax
11884       3d/compare-eax-and 0/imm32/false
11885       74/jump-if-= break/disp8
11886       (check-mu-get-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11887       e9/jump $check-mu-primitive:end/disp32
11888     }
11889     # if (op == "index") check-mu-index-stmt
11890     {
11891       (string-equal? %ecx "index")  # => eax
11892       3d/compare-eax-and 0/imm32/false
11893       74/jump-if-= break/disp8
11894       (check-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11895       e9/jump $check-mu-primitive:end/disp32
11896     }
11897     # if (op == "length") check-mu-length-stmt
11898     {
11899       (string-equal? %ecx "length")  # => eax
11900       3d/compare-eax-and 0/imm32/false
11901       74/jump-if-= break/disp8
11902       (check-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11903       e9/jump $check-mu-primitive:end/disp32
11904     }
11905     # if (op == "compute-offset") check-mu-compute-offset-stmt
11906     {
11907       (string-equal? %ecx "compute-offset")  # => eax
11908       3d/compare-eax-and 0/imm32/false
11909       74/jump-if-= break/disp8
11910       (check-mu-compute-offset-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11911       e9/jump $check-mu-primitive:end/disp32
11912     }
11913     # if (op == "allocate") check-mu-allocate-stmt
11914     {
11915       (string-equal? %ecx "allocate")  # => eax
11916       3d/compare-eax-and 0/imm32/false
11917       74/jump-if-= break/disp8
11918       (check-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11919       e9/jump $check-mu-primitive:end/disp32
11920     }
11921     # if (op == "populate") check-mu-populate-stmt
11922     {
11923       (string-equal? %ecx "populate")  # => eax
11924       3d/compare-eax-and 0/imm32/false
11925       74/jump-if-= break/disp8
11926       (check-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11927       e9/jump $check-mu-primitive:end/disp32
11928     }
11929     # if (op == "populate-stream") check-mu-populate-stream-stmt
11930     {
11931       (string-equal? %ecx "populate-stream")  # => eax
11932       3d/compare-eax-and 0/imm32/false
11933       74/jump-if-= break/disp8
11934       (check-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11935       e9/jump $check-mu-primitive:end/disp32
11936     }
11937     # if (op == "read-from-stream") check-mu-read-from-stream-stmt
11938     {
11939       (string-equal? %ecx "read-from-stream")  # => eax
11940       3d/compare-eax-and 0/imm32/false
11941       74/jump-if-= break/disp8
11942       (check-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11943       e9/jump $check-mu-primitive:end/disp32
11944     }
11945     # if (op == "write-to-stream") check-mu-write-to-stream-stmt
11946     {
11947       (string-equal? %ecx "write-to-stream")  # => eax
11948       3d/compare-eax-and 0/imm32/false
11949       74/jump-if-= break/disp8
11950       (check-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11951       e9/jump $check-mu-primitive:end/disp32
11952     }
11953     # otherwise check-numberlike-stmt
11954     (check-mu-numberlike-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11955 $check-mu-primitive:end:
11956     # . restore registers
11957     59/pop-to-ecx
11958     58/pop-to-eax
11959     # . epilogue
11960     89/<- %esp 5/r32/ebp
11961     5d/pop-to-ebp
11962     c3/return
11963 
11964 # by default, Mu primitives should only operate on 'number-like' types
11965 check-mu-numberlike-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11966     # . prologue
11967     55/push-ebp
11968     89/<- %ebp 4/r32/esp
11969     # . save registers
11970     50/push-eax
11971     51/push-ecx
11972     56/push-esi
11973     # esi = stmt
11974     8b/-> *(ebp+8) 6/r32/esi
11975     # var gas/ecx: int = 2
11976     b9/copy-to-ecx 2/imm32
11977     # - check at most 1 output
11978     # var output/eax: (addr stmt-var) = stmt->outputs
11979     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
11980     {
11981       3d/compare-eax-and 0/imm32
11982       74/jump-if-= break/disp8
11983 $check-mu-numberlike-primitive:output:
11984       (check-mu-numberlike-output %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11985       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
11986       3d/compare-eax-and 0/imm32
11987       0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-outputs/disp32
11988       # check output is in a register
11989       # --gas
11990       49/decrement-ecx
11991     }
11992     # - check first inout
11993     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11994     {
11995       3d/compare-eax-and 0/imm32
11996       0f 84/jump-if-= $check-mu-numberlike-primitive:end/disp32
11997 $check-mu-numberlike-primitive:first-inout:
11998       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11999       # --gas
12000       49/decrement-ecx
12001     }
12002     # - check second inout
12003     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12004     {
12005       3d/compare-eax-and 0/imm32
12006       74/jump-if-= $check-mu-numberlike-primitive:end/disp8
12007 $check-mu-numberlike-primitive:second-inout:
12008       # is a second inout allowed?
12009       81 7/subop/compare %ecx 0/imm32
12010       0f 84/jump-if-= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
12011 $check-mu-numberlike-primitive:second-inout-permitted:
12012       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12013     }
12014 $check-mu-numberlike-primitive:third-inout:
12015     # if there's a third arg, raise an error
12016     81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
12017     0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
12018 $check-mu-numberlike-primitive:end:
12019     # . restore registers
12020     5e/pop-to-esi
12021     59/pop-to-ecx
12022     58/pop-to-eax
12023     # . epilogue
12024     89/<- %esp 5/r32/ebp
12025     5d/pop-to-ebp
12026     c3/return
12027 
12028 $check-mu-numberlike-primitive:error-too-many-inouts:
12029     (write-buffered *(ebp+0x10) "fn ")
12030     8b/-> *(ebp+0xc) 0/r32/eax
12031     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12032     (write-buffered *(ebp+0x10) %eax)
12033     (write-buffered *(ebp+0x10) ": stmt ")
12034     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
12035     (write-buffered *(ebp+0x10) %eax)
12036     (write-buffered *(ebp+0x10) ": too many inouts; most primitives support at most two arguments, across inouts and outputs\n")
12037     (flush *(ebp+0x10))
12038     (stop *(ebp+0x14) 1)
12039     # never gets here
12040 
12041 $check-mu-numberlike-primitive:error-too-many-outputs:
12042     (write-buffered *(ebp+0x10) "fn ")
12043     8b/-> *(ebp+0xc) 0/r32/eax
12044     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12045     (write-buffered *(ebp+0x10) %eax)
12046     (write-buffered *(ebp+0x10) ": stmt ")
12047     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
12048     (write-buffered *(ebp+0x10) %eax)
12049     (write-buffered *(ebp+0x10) ": too many outputs; most primitives support at most one output\n")
12050     (flush *(ebp+0x10))
12051     (stop *(ebp+0x14) 1)
12052     # never gets here
12053 
12054 check-mu-numberlike-arg:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12055     # . prologue
12056     55/push-ebp
12057     89/<- %ebp 4/r32/esp
12058     # . save registers
12059     50/push-eax
12060     56/push-esi
12061     # var t/esi: (addr type-tree) = lookup(v->value->type)
12062     8b/-> *(ebp+8) 0/r32/eax
12063     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12064     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12065     89/<- %esi 0/r32/eax
12066 $check-mu-numberlike-arg:check-literal:
12067     # if t is an int, return
12068     (is-simple-mu-type? %esi 0)  # literal => eax
12069     3d/compare-eax-and 0/imm32/false
12070     75/jump-if-!= $check-mu-numberlike-arg:end/disp8
12071 $check-mu-numberlike-arg:check-addr:
12072     # if t is an addr and v is dereferenced, return
12073     {
12074       (is-mu-addr-type? %esi)  # => eax
12075       3d/compare-eax-and 0/imm32/false
12076       74/jump-if-= break/disp8
12077       8b/-> *(ebp+8) 0/r32/eax
12078       8b/-> *(eax+0x10) 0/r32/eax
12079       3d/compare-eax-and 0/imm32/false
12080       75/jump-if-!= $check-mu-numberlike-arg:end/disp8
12081     }
12082 $check-mu-numberlike-arg:output-checks:
12083     (check-mu-numberlike-output *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
12084 $check-mu-numberlike-arg:end:
12085     # . restore registers
12086     5e/pop-to-esi
12087     58/pop-to-eax
12088     # . epilogue
12089     89/<- %esp 5/r32/ebp
12090     5d/pop-to-ebp
12091     c3/return
12092 
12093 check-mu-numberlike-output:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12094     # . prologue
12095     55/push-ebp
12096     89/<- %ebp 4/r32/esp
12097     # . save registers
12098     50/push-eax
12099     56/push-esi
12100     # var t/esi: (addr type-tree) = lookup(v->value->type)
12101     8b/-> *(ebp+8) 0/r32/eax
12102     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12103     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12104     89/<- %esi 0/r32/eax
12105 $check-mu-numberlike-output:check-int:
12106     # if t is an int, return
12107     (is-simple-mu-type? %esi 1)  # int => eax
12108     3d/compare-eax-and 0/imm32/false
12109     75/jump-if-!= $check-mu-numberlike-output:end/disp8
12110 $check-mu-numberlike-output:check-boolean:
12111     # if t is a boolean, return
12112     (is-simple-mu-type? %esi 5)  # boolean => eax
12113     3d/compare-eax-and 0/imm32/false
12114     75/jump-if-!= $check-mu-numberlike-output:end/disp8
12115 $check-mu-numberlike-output:check-byte:
12116     # if t is a byte, return
12117     (is-simple-mu-type? %esi 8)  # byte => eax
12118     3d/compare-eax-and 0/imm32/false
12119     75/jump-if-!= $check-mu-numberlike-output:end/disp8
12120     e9/jump $check-mu-numberlike-output:fail/disp32
12121 $check-mu-numberlike-output:end:
12122     # . restore registers
12123     5e/pop-to-esi
12124     58/pop-to-eax
12125     # . epilogue
12126     89/<- %esp 5/r32/ebp
12127     5d/pop-to-ebp
12128     c3/return
12129 
12130 $check-mu-numberlike-output:fail:
12131     # otherwise raise an error
12132     (write-buffered *(ebp+0x14) "fn ")
12133     8b/-> *(ebp+0x10) 0/r32/eax
12134     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12135     (write-buffered *(ebp+0x14) %eax)
12136     (write-buffered *(ebp+0x14) ": stmt ")
12137     8b/-> *(ebp+0xc) 0/r32/eax
12138     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
12139     (write-buffered *(ebp+0x14) %eax)
12140     (write-buffered *(ebp+0x14) ": only non-addr scalar args permitted\n")
12141     (flush *(ebp+0x14))
12142     (stop *(ebp+0x18) 1)
12143     # never gets here
12144 
12145 check-mu-copy-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12146     # . prologue
12147     55/push-ebp
12148     89/<- %ebp 4/r32/esp
12149     # . save registers
12150 $check-mu-copy-stmt:end:
12151     # . restore registers
12152     # . epilogue
12153     89/<- %esp 5/r32/ebp
12154     5d/pop-to-ebp
12155     c3/return
12156 
12157 check-mu-copy-to-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12158     # . prologue
12159     55/push-ebp
12160     89/<- %ebp 4/r32/esp
12161     # . save registers
12162 $check-mu-copy-to-stmt:end:
12163     # . restore registers
12164     # . epilogue
12165     89/<- %esp 5/r32/ebp
12166     5d/pop-to-ebp
12167     c3/return
12168 
12169 check-mu-compare-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12170     # . prologue
12171     55/push-ebp
12172     89/<- %ebp 4/r32/esp
12173     # . save registers
12174 $check-mu-compare-stmt:end:
12175     # . restore registers
12176     # . epilogue
12177     89/<- %esp 5/r32/ebp
12178     5d/pop-to-ebp
12179     c3/return
12180 
12181 check-mu-address-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12182     # . prologue
12183     55/push-ebp
12184     89/<- %ebp 4/r32/esp
12185     # . save registers
12186 $check-mu-address-stmt:end:
12187     # . restore registers
12188     # . epilogue
12189     89/<- %esp 5/r32/ebp
12190     5d/pop-to-ebp
12191     c3/return
12192 
12193 check-mu-get-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12194     # . prologue
12195     55/push-ebp
12196     89/<- %ebp 4/r32/esp
12197     # . save registers
12198     50/push-eax
12199     51/push-ecx
12200     52/push-edx
12201     53/push-ebx
12202     56/push-esi
12203     57/push-edi
12204     # esi = stmt
12205     8b/-> *(ebp+8) 6/r32/esi
12206     # - check for 0 inouts
12207     # var base/ecx: (addr var) = stmt->inouts->value
12208     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12209     3d/compare-eax-and 0/imm32/false
12210     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
12211     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12212     89/<- %ecx 0/r32/eax
12213 $check-mu-get-stmt:check-base:
12214     # - check base type
12215     # if it's an 'addr', check that it's in a register
12216     # var base-type/ebx: (addr type-tree) = lookup(base->type)
12217     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
12218     89/<- %ebx 0/r32/eax
12219     {
12220       81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
12221       0f 85/jump-if-!= break/disp32
12222 $check-mu-get-stmt:base-is-compound:
12223       # if (type->left != addr) break
12224       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
12225       (is-simple-mu-type? %eax 2)  # => eax
12226       3d/compare-eax-and 0/imm32/false
12227       74/jump-if-= break/disp8
12228 $check-mu-get-stmt:base-is-addr:
12229       # now check for register
12230       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
12231       0f 84/jump-if-= $check-mu-get-stmt:error-base-type-addr-but-not-register/disp32
12232 $check-mu-get-stmt:base-is-addr-in-register:
12233       # type->left is now an addr; skip it
12234       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
12235       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
12236       0f 85/jump-if-!= $check-mu-get-stmt:error-bad-base/disp32
12237 $check-mu-get-stmt:base-is-addr-to-atom-in-register:
12238       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
12239       89/<- %ebx 0/r32/eax
12240     }
12241 $check-mu-get-stmt:check-base-typeinfo:
12242     # ensure type is a container
12243     # var base-type-id/ebx: type-id = base-type->value
12244     8b/-> *(ebx+4) 3/r32/ebx  # Type-tree-value
12245     (is-container? %ebx)  # => eax
12246     3d/compare-eax-and 0/imm32/false
12247     0f 84/jump-if-= $check-mu-get-stmt:error-bad-base/disp32
12248     # var base-typeinfo/edx: (addr typeinfo) = find-typeinfo(base-type-id)
12249     # . var container/ecx: (handle typeinfo)
12250     68/push 0/imm32
12251     68/push 0/imm32
12252     89/<- %ecx 4/r32/esp
12253     # .
12254     (find-typeinfo %ebx %ecx)
12255     (lookup *ecx *(ecx+4))  # => eax
12256     # . reclaim container
12257     81 0/subop/add %esp 8/imm32
12258     # .
12259     89/<- %edx 0/r32/eax
12260     # var offset/ecx: (addr stmt-var) = stmt->inouts->next
12261     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12262     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12263     89/<- %ecx 0/r32/eax
12264     # - check for 1 inout
12265     3d/compare-eax-and 0/imm32/false
12266     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
12267     # var offset/ecx: (addr var) = lookup(offset->value)
12268     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12269     89/<- %ecx 0/r32/eax
12270     # - check for valid field
12271     81 7/subop/compare *(ecx+0x14) -1/imm32/uninitialized  # Var-offset
12272     0f 84/jump-if-= $check-mu-get-stmt:error-bad-field/disp32
12273     # - check for too many inouts
12274     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12275     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12276     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12277     3d/compare-eax-and 0/imm32/false
12278     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-inouts/disp32
12279     # var output/edi: (addr var) = stmt->outputs->value
12280     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12281     # - check for 0 outputs
12282     3d/compare-eax-and 0/imm32/false
12283     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-outputs/disp32
12284     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12285     89/<- %edi 0/r32/eax
12286 $check-mu-get-stmt:check-output-type:
12287     # - check output type
12288     # must be in register
12289     (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
12290     3d/compare-eax-and 0/imm32
12291     0f 84/jump-if-= $check-mu-get-stmt:error-output-not-in-register/disp32
12292     # must have a non-atomic type
12293     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
12294     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
12295     0f 85/jump-if-!= $check-mu-get-stmt:error-output-type-not-address/disp32
12296     # type must start with (addr ...)
12297     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
12298     (is-simple-mu-type? %eax 2)  # => eax
12299     3d/compare-eax-and 0/imm32/false
12300     0f 84/jump-if-= $check-mu-get-stmt:error-output-type-not-address/disp32
12301 $check-mu-get-stmt:check-output-type-match:
12302     # payload of addr type must match 'type' definition
12303     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
12304     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
12305     # if (payload->right == null) payload = payload->left
12306     81 7/subop/compare *(eax+0xc) 0/imm32/null  # Type-tree-right
12307     {
12308       75/jump-if-!= break/disp8
12309       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
12310     }
12311     89/<- %edi 0/r32/eax
12312     # . var output-name/ecx: (addr array byte)
12313     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
12314     89/<- %ecx 0/r32/eax
12315     # . var base-typeinfo-entry/eax: (addr handle typeinfo-entry)
12316     (lookup *(edx+4) *(edx+8))  # Typeinfo-fields Typeinfo-fields => eax
12317     (get %eax %ecx 0x10)  # => eax
12318     # .
12319     (lookup *eax *(eax+4))  # => eax
12320     (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
12321     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12322     # .
12323     (type-equal? %edi %eax)  # => eax
12324     3d/compare-eax-and 0/imm32/false
12325     0f 84/jump-if-= $check-mu-get-stmt:error-bad-output-type/disp32
12326     # - check for too many outputs
12327     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12328     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12329     3d/compare-eax-and 0/imm32/false
12330     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-outputs/disp32
12331 $check-mu-get-stmt:end:
12332     # . restore registers
12333     5f/pop-to-edi
12334     5e/pop-to-esi
12335     5b/pop-to-ebx
12336     5a/pop-to-edx
12337     59/pop-to-ecx
12338     58/pop-to-eax
12339     # . epilogue
12340     89/<- %esp 5/r32/ebp
12341     5d/pop-to-ebp
12342     c3/return
12343 
12344 $check-mu-get-stmt:error-too-few-inouts:
12345     (write-buffered *(ebp+0x10) "fn ")
12346     8b/-> *(ebp+0xc) 0/r32/eax
12347     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12348     (write-buffered *(ebp+0x10) %eax)
12349     (write-buffered *(ebp+0x10) ": stmt get: too few inouts (2 required)\n")
12350     (flush *(ebp+0x10))
12351     (stop *(ebp+0x14) 1)
12352     # never gets here
12353 
12354 $check-mu-get-stmt:error-too-many-inouts:
12355     (write-buffered *(ebp+0x10) "fn ")
12356     8b/-> *(ebp+0xc) 0/r32/eax
12357     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12358     (write-buffered *(ebp+0x10) %eax)
12359     (write-buffered *(ebp+0x10) ": stmt get: too many inouts (2 required)\n")
12360     (flush *(ebp+0x10))
12361     (stop *(ebp+0x14) 1)
12362     # never gets here
12363 
12364 $check-mu-get-stmt:error-too-few-outputs:
12365     (write-buffered *(ebp+0x10) "fn ")
12366     8b/-> *(ebp+0xc) 0/r32/eax
12367     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12368     (write-buffered *(ebp+0x10) %eax)
12369     (write-buffered *(ebp+0x10) ": stmt get: must have an output\n")
12370     (flush *(ebp+0x10))
12371     (stop *(ebp+0x14) 1)
12372     # never gets here
12373 
12374 $check-mu-get-stmt:error-too-many-outputs:
12375     (write-buffered *(ebp+0x10) "fn ")
12376     8b/-> *(ebp+0xc) 0/r32/eax
12377     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12378     (write-buffered *(ebp+0x10) %eax)
12379     (write-buffered *(ebp+0x10) ": stmt get: too many outputs (1 required)\n")
12380     (flush *(ebp+0x10))
12381     (stop *(ebp+0x14) 1)
12382     # never gets here
12383 
12384 $check-mu-get-stmt:error-bad-base:
12385     # error("fn " fn ": stmt get: var '" base->name "' must have a 'type' definition\n")
12386     (write-buffered *(ebp+0x10) "fn ")
12387     8b/-> *(ebp+0xc) 0/r32/eax
12388     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12389     (write-buffered *(ebp+0x10) %eax)
12390     (write-buffered *(ebp+0x10) ": stmt get: var '")
12391     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12392     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12393     (lookup *eax *(eax+4))  # Var-name Var-name => eax
12394     (write-buffered *(ebp+0x10) %eax)
12395     (write-buffered *(ebp+0x10) "' must have a 'type' definition\n")
12396     (flush *(ebp+0x10))
12397     (stop *(ebp+0x14) 1)
12398     # never gets here
12399 
12400 $check-mu-get-stmt:error-base-type-addr-but-not-register:
12401     (write-buffered *(ebp+0x10) "fn ")
12402     8b/-> *(ebp+0xc) 0/r32/eax
12403     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12404     (write-buffered *(ebp+0x10) %eax)
12405     (write-buffered *(ebp+0x10) ": stmt get: var '")
12406     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12407     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12408     (lookup *eax *(eax+4))  # Var-name Var-name => eax
12409     (write-buffered *(ebp+0x10) %eax)
12410     (write-buffered *(ebp+0x10) "' is an 'addr' type, and so must live in a register\n")
12411     (flush *(ebp+0x10))
12412     (stop *(ebp+0x14) 1)
12413     # never gets here
12414 
12415 $check-mu-get-stmt:error-bad-field:
12416     # error("fn " fn ": stmt get: type " type " has no member called '" curr->name "'\n")
12417     (write-buffered *(ebp+0x10) "fn ")
12418     8b/-> *(ebp+0xc) 0/r32/eax
12419     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12420     (write-buffered *(ebp+0x10) %eax)
12421     (write-buffered *(ebp+0x10) ": stmt get: type '")
12422     # . write(Type-id->data[tmp])
12423     bf/copy-to-edi Type-id/imm32
12424     (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
12425     # .
12426     (write-buffered *(ebp+0x10) "' has no member called '")
12427     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
12428     (write-buffered *(ebp+0x10) %eax)
12429     (write-buffered *(ebp+0x10) "'\n")
12430     (flush *(ebp+0x10))
12431     (stop *(ebp+0x14) 1)
12432     # never gets here
12433 
12434 $check-mu-get-stmt:error-output-not-in-register:
12435     (write-buffered *(ebp+0x10) "fn ")
12436     8b/-> *(ebp+0xc) 0/r32/eax
12437     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12438     (write-buffered *(ebp+0x10) %eax)
12439     (write-buffered *(ebp+0x10) ": stmt get: output '")
12440     (lookup *edi *(edi+4))  # Var-name Var-name => eax
12441     (write-buffered *(ebp+0x10) %eax)
12442     (write-buffered *(ebp+0x10) "' is not in a register\n")
12443     (flush *(ebp+0x10))
12444     (stop *(ebp+0x14) 1)
12445     # never gets here
12446 
12447 $check-mu-get-stmt:error-output-type-not-address:
12448     (write-buffered *(ebp+0x10) "fn ")
12449     8b/-> *(ebp+0xc) 0/r32/eax
12450     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12451     (write-buffered *(ebp+0x10) %eax)
12452     (write-buffered *(ebp+0x10) ": stmt get: output must be an address\n")
12453     (flush *(ebp+0x10))
12454     (stop *(ebp+0x14) 1)
12455     # never gets here
12456 
12457 $check-mu-get-stmt:error-bad-output-type:
12458     (write-buffered *(ebp+0x10) "fn ")
12459     8b/-> *(ebp+0xc) 0/r32/eax
12460     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12461     (write-buffered *(ebp+0x10) %eax)
12462     (write-buffered *(ebp+0x10) ": stmt get: wrong output type for member '")
12463     (write-buffered *(ebp+0x10) %ecx)
12464     (write-buffered *(ebp+0x10) "' of type '")
12465     bf/copy-to-edi Type-id/imm32
12466     (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
12467     (write-buffered *(ebp+0x10) "'\n")
12468     (flush *(ebp+0x10))
12469     (stop *(ebp+0x14) 1)
12470     # never gets here
12471 
12472 check-mu-index-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12473     # . prologue
12474     55/push-ebp
12475     89/<- %ebp 4/r32/esp
12476     # . save registers
12477 $check-mu-index-stmt:end:
12478     # . restore registers
12479     # . epilogue
12480     89/<- %esp 5/r32/ebp
12481     5d/pop-to-ebp
12482     c3/return
12483 
12484 check-mu-length-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12485     # . prologue
12486     55/push-ebp
12487     89/<- %ebp 4/r32/esp
12488     # . save registers
12489 $check-mu-length-stmt:end:
12490     # . restore registers
12491     # . epilogue
12492     89/<- %esp 5/r32/ebp
12493     5d/pop-to-ebp
12494     c3/return
12495 
12496 check-mu-compute-offset-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12497     # . prologue
12498     55/push-ebp
12499     89/<- %ebp 4/r32/esp
12500     # . save registers
12501 $check-mu-compute-offset-stmt:end:
12502     # . restore registers
12503     # . epilogue
12504     89/<- %esp 5/r32/ebp
12505     5d/pop-to-ebp
12506     c3/return
12507 
12508 check-mu-allocate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12509     # . prologue
12510     55/push-ebp
12511     89/<- %ebp 4/r32/esp
12512     # . save registers
12513 $check-mu-allocate-stmt:end:
12514     # . restore registers
12515     # . epilogue
12516     89/<- %esp 5/r32/ebp
12517     5d/pop-to-ebp
12518     c3/return
12519 
12520 check-mu-populate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12521     # . prologue
12522     55/push-ebp
12523     89/<- %ebp 4/r32/esp
12524     # . save registers
12525 $check-mu-populate-stmt:end:
12526     # . restore registers
12527     # . epilogue
12528     89/<- %esp 5/r32/ebp
12529     5d/pop-to-ebp
12530     c3/return
12531 
12532 check-mu-populate-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12533     # . prologue
12534     55/push-ebp
12535     89/<- %ebp 4/r32/esp
12536     # . save registers
12537 $check-mu-populate-stream-stmt:end:
12538     # . restore registers
12539     # . epilogue
12540     89/<- %esp 5/r32/ebp
12541     5d/pop-to-ebp
12542     c3/return
12543 
12544 check-mu-read-from-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12545     # . prologue
12546     55/push-ebp
12547     89/<- %ebp 4/r32/esp
12548     # . save registers
12549 $check-mu-read-from-stream-stmt:end:
12550     # . restore registers
12551     # . epilogue
12552     89/<- %esp 5/r32/ebp
12553     5d/pop-to-ebp
12554     c3/return
12555 
12556 check-mu-write-to-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12557     # . prologue
12558     55/push-ebp
12559     89/<- %ebp 4/r32/esp
12560     # . save registers
12561 $check-mu-write-to-stream-stmt:end:
12562     # . restore registers
12563     # . epilogue
12564     89/<- %esp 5/r32/ebp
12565     5d/pop-to-ebp
12566     c3/return
12567 
12568 check-mu-call:  # stmt: (addr stmt), callee: (addr function), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12569     # . prologue
12570     55/push-ebp
12571     89/<- %ebp 4/r32/esp
12572     # var type-parameters: (addr table (handle array byte) (addr type-tree) 8)
12573     68/push 0/imm32
12574     # var type-parameters-storage: (table (handle array byte) (addr type-tree) 8)
12575     81 5/subop/subtract %esp 0x60/imm32
12576     68/push 0x60/imm32/size
12577     68/push 0/imm32/read
12578     68/push 0/imm32/write
12579     # save a pointer to type-parameters-storage at type-parameters
12580     89/<- *(ebp-4) 4/r32/esp
12581     (clear-stream *(ebp-4))
12582     # . save registers
12583     50/push-eax
12584     51/push-ecx
12585     52/push-edx
12586     53/push-ebx
12587     56/push-esi
12588     57/push-edi
12589     # esi = stmt
12590     8b/-> *(ebp+8) 6/r32/esi
12591     # edi = callee
12592     8b/-> *(ebp+0xc) 7/r32/edi
12593     # var inouts/ecx: (addr stmt-var) = lookup(stmt->inouts)
12594     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12595     89/<- %ecx 0/r32/eax
12596     # var expected/edx: (addr list var) = lookup(f->inouts)
12597     (lookup *(edi+8) *(edi+0xc))  # Function-inouts Function-inouts => eax
12598     89/<- %edx 0/r32/eax
12599     {
12600 $check-mu-call:check-for-inouts:
12601       # if (inouts == 0) break
12602       81 7/subop/compare %ecx 0/imm32
12603       0f 84/jump-if-= break/disp32
12604       # if (expected == 0) error
12605       81 7/subop/compare %edx 0/imm32
12606       0f 84/jump-if-= break/disp32
12607 $check-mu-call:check-inout-type:
12608       # var v/eax: (addr v) = lookup(inouts->value)
12609       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12610       # var t/ebx: (addr type-tree) = lookup(v->type)
12611       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12612       89/<- %ebx 0/r32/eax
12613       # if (inouts->is-deref?) t = t->right  # TODO: check that t->left is an addr
12614       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
12615       {
12616         74/jump-if-= break/disp8
12617         (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
12618         89/<- %ebx 0/r32/eax
12619         # if t->right is null, t = t->left
12620         81 7/subop/compare *(ebx+0xc) 0/imm32  # Type-tree-right
12621         75/jump-if-!= break/disp8
12622         (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
12623         89/<- %ebx 0/r32/eax
12624       }
12625       # var v2/eax: (addr v) = lookup(expected->value)
12626       (lookup *edx *(edx+4))  # List-value List-value => eax
12627       # var t2/eax: (addr type-tree) = lookup(v2->type)
12628       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12629       # if (t != t2) error
12630       (type-match? %eax %ebx *(ebp-4))  # => eax
12631       3d/compare-eax-and 0/imm32/false
12632       {
12633         0f 85/jump-if-!= break/disp32
12634         (write-buffered *(ebp+0x14) "fn ")
12635         8b/-> *(ebp+0x10) 0/r32/eax
12636         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12637         (write-buffered *(ebp+0x14) %eax)
12638         (write-buffered *(ebp+0x14) ": call ")
12639         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12640         (write-buffered *(ebp+0x14) %eax)
12641         (write-buffered *(ebp+0x14) ": type for inout '")
12642         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12643         (lookup *eax *(eax+4))  # Var-name Var-name => eax
12644         (write-buffered *(ebp+0x14) %eax)
12645         (write-buffered *(ebp+0x14) "' is not right\n")
12646         (flush *(ebp+0x14))
12647         (stop *(ebp+0x18) 1)
12648       }
12649 $check-mu-call:continue-to-next-inout:
12650       # inouts = lookup(inouts->next)
12651       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
12652       89/<- %ecx 0/r32/eax
12653       # expected = lookup(expected->next)
12654       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
12655       89/<- %edx 0/r32/eax
12656       #
12657       e9/jump loop/disp32
12658     }
12659 $check-mu-call:check-inout-count:
12660     # if (inouts == expected) proceed
12661     39/compare %ecx 2/r32/edx
12662     {
12663       0f 84/jump-if-= break/disp32
12664       # exactly one of the two is null
12665       # if (inouts == 0) error("too many inouts")
12666       {
12667         81 7/subop/compare %ecx 0/imm32
12668         0f 84/jump-if-= break/disp32
12669         (write-buffered *(ebp+0x14) "fn ")
12670         8b/-> *(ebp+0x10) 0/r32/eax
12671         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12672         (write-buffered *(ebp+0x14) %eax)
12673         (write-buffered *(ebp+0x14) ": call ")
12674         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12675         (write-buffered *(ebp+0x14) %eax)
12676         (write-buffered *(ebp+0x14) ": too many inouts\n")
12677         (flush *(ebp+0x14))
12678         (stop *(ebp+0x18) 1)
12679       }
12680       # if (expected == 0) error("too few inouts")
12681       {
12682         81 7/subop/compare %edx 0/imm32
12683         0f 84/jump-if-= break/disp32
12684         (write-buffered *(ebp+0x14) "fn ")
12685         8b/-> *(ebp+0x10) 0/r32/eax
12686         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12687         (write-buffered *(ebp+0x14) %eax)
12688         (write-buffered *(ebp+0x14) ": call ")
12689         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12690         (write-buffered *(ebp+0x14) %eax)
12691         (write-buffered *(ebp+0x14) ": too few inouts\n")
12692         (flush *(ebp+0x14))
12693         (stop *(ebp+0x18) 1)
12694       }
12695     }
12696 $check-mu-call:check-outputs:
12697     # var outputs/ecx: (addr stmt-var) = lookup(stmt->outputs)
12698     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12699     89/<- %ecx 0/r32/eax
12700     # var expected/edx: (addr list var) = lookup(f->outputs)
12701     (lookup *(edi+0x10) *(edi+0x14))  # Function-outputs Function-outputs => eax
12702     89/<- %edx 0/r32/eax
12703     {
12704 $check-mu-call:check-for-outputs:
12705       # if (outputs == 0) break
12706       81 7/subop/compare %ecx 0/imm32
12707       0f 84/jump-if-= break/disp32
12708       # if (expected == 0) error
12709       81 7/subop/compare %edx 0/imm32
12710       0f 84/jump-if-= break/disp32
12711 $check-mu-call:check-output-type:
12712       # var v/eax: (addr v) = lookup(outputs->value)
12713       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12714       # var t/ebx: (addr type-tree) = lookup(v->type)
12715       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12716       89/<- %ebx 0/r32/eax
12717       # if (outputs->is-deref?) t = t->right  # TODO: check that t->left is an addr
12718       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
12719       {
12720         74/jump-if-= break/disp8
12721         (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
12722         89/<- %ebx 0/r32/eax
12723       }
12724       # var v2/eax: (addr v) = lookup(expected->value)
12725       (lookup *edx *(edx+4))  # List-value List-value => eax
12726       # var t2/eax: (addr type-tree) = lookup(v2->type)
12727       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12728       # if (t != t2) error
12729       (type-match? %eax %ebx *(ebp-4))  # => eax
12730       3d/compare-eax-and 0/imm32/false
12731       {
12732         0f 85/jump-if-!= break/disp32
12733         (write-buffered *(ebp+0x14) "fn ")
12734         8b/-> *(ebp+0x10) 0/r32/eax
12735         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12736         (write-buffered *(ebp+0x14) %eax)
12737         (write-buffered *(ebp+0x14) ": call ")
12738         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12739         (write-buffered *(ebp+0x14) %eax)
12740         (write-buffered *(ebp+0x14) ": type for output '")
12741         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12742         (lookup *eax *(eax+4))  # Var-name Var-name => eax
12743         (write-buffered *(ebp+0x14) %eax)
12744         (write-buffered *(ebp+0x14) "' is not right\n")
12745         (flush *(ebp+0x14))
12746         (stop *(ebp+0x18) 1)
12747       }
12748 $check-mu-call:check-output-register:
12749       # var v/eax: (addr v) = lookup(outputs->value)
12750       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12751       # var r/ebx: (addr array byte) = lookup(v->register)
12752       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
12753       89/<- %ebx 0/r32/eax
12754       # var v2/eax: (addr v) = lookup(expected->value)
12755       (lookup *edx *(edx+4))  # Stmt-var-value Stmt-var-value => eax
12756       # var r2/eax: (addr array byte) = lookup(v2->register)
12757       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
12758       # if (r != r2) error
12759       (string-equal? %eax %ebx)  # => eax
12760       3d/compare-eax-and 0/imm32/false
12761       {
12762         0f 85/jump-if-!= break/disp32
12763         (write-buffered *(ebp+0x14) "fn ")
12764         8b/-> *(ebp+0x10) 0/r32/eax
12765         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12766         (write-buffered *(ebp+0x14) %eax)
12767         (write-buffered *(ebp+0x14) ": call ")
12768         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12769         (write-buffered *(ebp+0x14) %eax)
12770         (write-buffered *(ebp+0x14) ": register for output '")
12771         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12772         (lookup *eax *(eax+4))  # Var-name Var-name => eax
12773         (write-buffered *(ebp+0x14) %eax)
12774         (write-buffered *(ebp+0x14) "' is not right\n")
12775         (flush *(ebp+0x14))
12776         (stop *(ebp+0x18) 1)
12777       }
12778 $check-mu-call:continue-to-next-output:
12779       # outputs = lookup(outputs->next)
12780       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
12781       89/<- %ecx 0/r32/eax
12782       # expected = lookup(expected->next)
12783       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
12784       89/<- %edx 0/r32/eax
12785       #
12786       e9/jump loop/disp32
12787     }
12788 $check-mu-call:check-output-count:
12789     # if (outputs == expected) proceed
12790     39/compare %ecx 2/r32/edx
12791     {
12792       0f 84/jump-if-= break/disp32
12793       # exactly one of the two is null
12794       # if (outputs == 0) error("too many outputs")
12795       {
12796         81 7/subop/compare %ecx 0/imm32
12797         0f 84/jump-if-= break/disp32
12798         (write-buffered *(ebp+0x14) "fn ")
12799         8b/-> *(ebp+0x10) 0/r32/eax
12800         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12801         (write-buffered *(ebp+0x14) %eax)
12802         (write-buffered *(ebp+0x14) ": call ")
12803         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12804         (write-buffered *(ebp+0x14) %eax)
12805         (write-buffered *(ebp+0x14) ": too many outputs\n")
12806         (flush *(ebp+0x14))
12807         (stop *(ebp+0x18) 1)
12808       }
12809       # if (expected == 0) error("too few outputs")
12810       {
12811         81 7/subop/compare %edx 0/imm32
12812         0f 84/jump-if-= break/disp32
12813         (write-buffered *(ebp+0x14) "fn ")
12814         8b/-> *(ebp+0x10) 0/r32/eax
12815         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12816         (write-buffered *(ebp+0x14) %eax)
12817         (write-buffered *(ebp+0x14) ": call ")
12818         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12819         (write-buffered *(ebp+0x14) %eax)
12820         (write-buffered *(ebp+0x14) ": too few outputs\n")
12821         (flush *(ebp+0x14))
12822         (stop *(ebp+0x18) 1)
12823       }
12824     }
12825 $check-mu-call:end:
12826     # . restore registers
12827     5f/pop-to-edi
12828     5e/pop-to-esi
12829     5b/pop-to-ebx
12830     5a/pop-to-edx
12831     59/pop-to-ecx
12832     58/pop-to-eax
12833     # . reclaim locals exclusively on the stack
12834     81 0/subop/add %esp 0x70/imm32
12835     # . epilogue
12836     89/<- %esp 5/r32/ebp
12837     5d/pop-to-ebp
12838     c3/return
12839 
12840 # like type-equal? but takes literals into account
12841 type-match?:  # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
12842     # . prologue
12843     55/push-ebp
12844     89/<- %ebp 4/r32/esp
12845     # if (call == literal) return true  # TODO: more precise
12846     (is-simple-mu-type? *(ebp+0xc) 0)  # literal => eax
12847     3d/compare-eax-and 0/imm32/false
12848     b8/copy-to-eax 1/imm32/true
12849     75/jump-if-!= $type-match?:end/disp8
12850 $type-match?:baseline:
12851     # otherwise fall back
12852     (type-component-match? *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
12853 $type-match?:end:
12854     # . epilogue
12855     89/<- %esp 5/r32/ebp
12856     5d/pop-to-ebp
12857     c3/return
12858 
12859 type-component-match?:  # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
12860     # . prologue
12861     55/push-ebp
12862     89/<- %ebp 4/r32/esp
12863     # . save registers
12864     51/push-ecx
12865     52/push-edx
12866     53/push-ebx
12867     # ecx = def
12868     8b/-> *(ebp+8) 1/r32/ecx
12869     # edx = call
12870     8b/-> *(ebp+0xc) 2/r32/edx
12871 $type-component-match?:compare-addr:
12872     # if (def == call) return true
12873     8b/-> %ecx 0/r32/eax  # Var-type
12874     39/compare %edx 0/r32/eax  # Var-type
12875     b8/copy-to-eax 1/imm32/true
12876     0f 84/jump-if-= $type-component-match?:end/disp32
12877     # if def is a type parameter, just check in type-parameters
12878     {
12879 $type-component-match?:check-type-parameter:
12880       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
12881       74/jump-if-= break/disp8
12882       81 7/subop/compare *(ecx+4) 0xa/imm32/type-parameter  # Type-tree-value
12883       75/jump-if-!= break/disp8
12884 $type-component-match?:type-parameter:
12885       (type-parameter-match? *(ecx+8) *(ecx+0xc)  %edx  *(ebp+0x10))  # => eax
12886       e9/jump $type-component-match?:end/disp32
12887     }
12888     # if def is a list containing just a type parameter, just check in type-parameters
12889     {
12890 $type-component-match?:check-list-type-parameter:
12891       # if def is a list..
12892       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
12893       75/jump-if-!= break/disp8
12894       #   ..that's a singleton
12895       81 7/subop/compare *(ecx+0xc) 0/imm32  # Type-tree-left
12896       75/jump-if-!= break/disp8
12897       #   ..and whose head is a type parameter
12898       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12899       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
12900       74/jump-if-= break/disp8
12901       81 7/subop/compare *(eax+4) 0xa/imm32/type-parameter  # Type-tree-value
12902       75/jump-if-!= break/disp8
12903 $type-component-match?:list-type-parameter:
12904       (type-parameter-match? *(eax+8) *(eax+0xc)  %edx  *(ebp+0x10))  # => eax
12905       e9/jump $type-component-match?:end/disp32
12906     }
12907 $type-component-match?:compare-atom-state:
12908     # if (def->is-atom? != call->is-atom?) return false
12909     8b/-> *ecx 3/r32/ebx  # Type-tree-is-atom
12910     39/compare *edx 3/r32/ebx  # Type-tree-is-atom
12911     b8/copy-to-eax 0/imm32/false
12912     0f 85/jump-if-!= $type-component-match?:end/disp32
12913     # if def->is-atom? return (def->value == call->value)
12914     {
12915 $type-component-match?:check-atom:
12916       81 7/subop/compare %ebx 0/imm32/false
12917       74/jump-if-= break/disp8
12918 $type-component-match?:is-atom:
12919       8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
12920       39/compare *(edx+4) 0/r32/eax  # Type-tree-value
12921       0f 94/set-if-= %al
12922       81 4/subop/and %eax 0xff/imm32
12923       e9/jump $type-component-match?:end/disp32
12924     }
12925 $type-component-match?:check-left:
12926     # if (!type-component-match?(def->left, call->left)) return false
12927     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12928     89/<- %ebx 0/r32/eax
12929     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
12930     (type-component-match? %ebx %eax *(ebp+0x10))  # => eax
12931     3d/compare-eax-and 0/imm32/false
12932     74/jump-if-= $type-component-match?:end/disp8
12933 $type-component-match?:check-right:
12934     # return type-component-match?(def->right, call->right)
12935     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
12936     89/<- %ebx 0/r32/eax
12937     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
12938     (type-component-match? %ebx %eax *(ebp+0x10))  # => eax
12939 $type-component-match?:end:
12940     # . restore registers
12941     5b/pop-to-ebx
12942     5a/pop-to-edx
12943     59/pop-to-ecx
12944     # . epilogue
12945     89/<- %esp 5/r32/ebp
12946     5d/pop-to-ebp
12947     c3/return
12948 
12949 type-parameter-match?:  # type-parameter-name: (handle array byte), type: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
12950     # . prologue
12951     55/push-ebp
12952     89/<- %ebp 4/r32/esp
12953     # . save registers
12954     51/push-ecx
12955     #
12956     (get-or-insert-handle *(ebp+0x14)  *(ebp+8) *(ebp+0xc)  0xc)  # => eax
12957     # if parameter wasn't saved, save it
12958     {
12959       81 7/subop/compare *eax 0/imm32
12960       75/jump-if-!= break/disp8
12961       8b/-> *(ebp+0x10) 1/r32/ecx
12962       89/<- *eax 1/r32/ecx
12963     }
12964     #
12965     (type-equal? *(ebp+0x10) *eax)  # => eax
12966 $type-parameter-match?:end:
12967     # . restore registers
12968     59/pop-to-ecx
12969     # . epilogue
12970     89/<- %esp 5/r32/ebp
12971     5d/pop-to-ebp
12972     c3/return
12973 
12974 size-of:  # v: (addr var) -> result/eax: int
12975     # . prologue
12976     55/push-ebp
12977     89/<- %ebp 4/r32/esp
12978     # . save registers
12979     51/push-ecx
12980     # var t/ecx: (addr type-tree) = lookup(v->type)
12981     8b/-> *(ebp+8) 1/r32/ecx
12982 #?     (write-buffered Stderr "size-of ")
12983 #?     (write-int32-hex-buffered Stderr %ecx)
12984 #?     (write-buffered Stderr Newline)
12985 #?     (write-buffered Stderr "type allocid: ")
12986 #?     (write-int32-hex-buffered Stderr *(ecx+8))
12987 #?     (write-buffered Stderr Newline)
12988 #?     (flush Stderr)
12989     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
12990     89/<- %ecx 0/r32/eax
12991     # if is-mu-array?(t) return size-of-array(t)
12992     {
12993       (is-mu-array? %ecx)  # => eax
12994       3d/compare-eax-and 0/imm32/false
12995       74/jump-if-= break/disp8
12996       (size-of-array %ecx)  # => eax
12997       eb/jump $size-of:end/disp8
12998     }
12999     # if is-mu-stream?(t) return size-of-stream(t)
13000     {
13001       (is-mu-stream? %ecx)  # => eax
13002       3d/compare-eax-and 0/imm32/false
13003       74/jump-if-= break/disp8
13004       (size-of-stream %ecx)  # => eax
13005       eb/jump $size-of:end/disp8
13006     }
13007     # if (!t->is-atom?) t = lookup(t->left)
13008     {
13009       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
13010       75/jump-if-!= break/disp8
13011       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
13012       89/<- %ecx 0/r32/eax
13013     }
13014     # TODO: assert t->is-atom?
13015     (size-of-type-id *(ecx+4))  # Type-tree-value => eax
13016 $size-of:end:
13017     # . restore registers
13018     59/pop-to-ecx
13019     # . epilogue
13020     89/<- %esp 5/r32/ebp
13021     5d/pop-to-ebp
13022     c3/return
13023 
13024 size-of-deref:  # v: (addr var) -> result/eax: int
13025     # . prologue
13026     55/push-ebp
13027     89/<- %ebp 4/r32/esp
13028     # . save registers
13029     51/push-ecx
13030     # var t/ecx: (addr type-tree) = lookup(v->type)
13031     8b/-> *(ebp+8) 1/r32/ecx
13032     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
13033     89/<- %ecx 0/r32/eax
13034     # TODO: assert(t is an addr)
13035     # t = lookup(t->right)
13036     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
13037     89/<- %ecx 0/r32/eax
13038     # if is-mu-array?(t) return size-of-array(t)
13039     {
13040       (is-mu-array? %ecx)  # => eax
13041       3d/compare-eax-and 0/imm32/false
13042       74/jump-if-= break/disp8
13043       (size-of-array %ecx)  # => eax
13044       eb/jump $size-of-deref:end/disp8
13045     }
13046     # if is-mu-stream?(t) return size-of-stream(t)
13047     {
13048       (is-mu-stream? %ecx)  # => eax
13049       3d/compare-eax-and 0/imm32/false
13050       74/jump-if-= break/disp8
13051       (size-of-stream %ecx)  # => eax
13052       eb/jump $size-of-deref:end/disp8
13053     }
13054     # if (!t->is-atom?) t = lookup(t->left)
13055     {
13056       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
13057       75/jump-if-!= break/disp8
13058       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
13059       89/<- %ecx 0/r32/eax
13060     }
13061     # TODO: assert t->is-atom?
13062     (size-of-type-id *(ecx+4))  # Type-tree-value => eax
13063 $size-of-deref:end:
13064     # . restore registers
13065     59/pop-to-ecx
13066     # . epilogue
13067     89/<- %esp 5/r32/ebp
13068     5d/pop-to-ebp
13069     c3/return
13070 
13071 is-mu-array?:  # t: (addr type-tree) -> result/eax: boolean
13072     # . prologue
13073     55/push-ebp
13074     89/<- %ebp 4/r32/esp
13075     # . save registers
13076     51/push-ecx
13077     # ecx = t
13078     8b/-> *(ebp+8) 1/r32/ecx
13079     # if t->is-atom?, return false
13080     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
13081     75/jump-if-!= $is-mu-array?:return-false/disp8
13082     # if !t->left->is-atom?, return false
13083     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
13084     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
13085     74/jump-if-= $is-mu-array?:return-false/disp8
13086     # return t->left->value == array
13087     81 7/subop/compare *(eax+4) 3/imm32/array-type-id  # Type-tree-value
13088     0f 94/set-if-= %al
13089     81 4/subop/and %eax 0xff/imm32
13090     eb/jump $is-mu-array?:end/disp8
13091 $is-mu-array?:return-false:
13092     b8/copy-to-eax 0/imm32/false
13093 $is-mu-array?:end:
13094     # . restore registers
13095     59/pop-to-ecx
13096     # . epilogue
13097     89/<- %esp 5/r32/ebp
13098     5d/pop-to-ebp
13099     c3/return
13100 
13101 # size of a statically allocated array where the size is part of the type expression
13102 size-of-array:  # a: (addr type-tree) -> result/eax: int
13103     # . prologue
13104     55/push-ebp
13105     89/<- %ebp 4/r32/esp
13106     # . save registers
13107     51/push-ecx
13108     52/push-edx
13109     #
13110     8b/-> *(ebp+8) 1/r32/ecx
13111     # TODO: assert that a->left is 'array'
13112     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
13113     89/<- %ecx 0/r32/eax
13114     # var elem-type/edx: type-id = a->right->left->value
13115     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
13116     8b/-> *(eax+4) 2/r32/edx  # Type-tree-value
13117     # TODO: assert that a->right->right->left->value == size
13118     # var array-size/ecx: int = a->right->right->left->value-size
13119     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
13120     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
13121     8b/-> *(eax+8) 1/r32/ecx  # Type-tree-value-size
13122     # return 4 + array-size * size-of(elem-type)
13123     (size-of-type-id-as-array-element %edx)  # => eax
13124     f7 4/subop/multiply-into-eax %ecx
13125     05/add-to-eax 4/imm32  # for array size
13126 $size-of-array:end:
13127     # . restore registers
13128     5a/pop-to-edx
13129     59/pop-to-ecx
13130     # . epilogue
13131     89/<- %esp 5/r32/ebp
13132     5d/pop-to-ebp
13133     c3/return
13134 
13135 is-mu-stream?:  # t: (addr type-tree) -> result/eax: boolean
13136     # . prologue
13137     55/push-ebp
13138     89/<- %ebp 4/r32/esp
13139     # . save registers
13140     51/push-ecx
13141     # ecx = t
13142     8b/-> *(ebp+8) 1/r32/ecx
13143     # if t->is-atom?, return false
13144     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
13145     75/jump-if-!= $is-mu-stream?:return-false/disp8
13146     # if !t->left->is-atom?, return false
13147     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
13148     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
13149     74/jump-if-= $is-mu-stream?:return-false/disp8
13150     # return t->left->value == stream
13151     81 7/subop/compare *(eax+4) 0xb/imm32/stream-type-id  # Type-tree-value
13152     0f 94/set-if-= %al
13153     81 4/subop/and %eax 0xff/imm32
13154     eb/jump $is-mu-stream?:end/disp8
13155 $is-mu-stream?:return-false:
13156     b8/copy-to-eax 0/imm32/false
13157 $is-mu-stream?:end:
13158     # . restore registers
13159     59/pop-to-ecx
13160     # . epilogue
13161     89/<- %esp 5/r32/ebp
13162     5d/pop-to-ebp
13163     c3/return
13164 
13165 # size of a statically allocated stream where the size is part of the type expression
13166 size-of-stream:  # a: (addr type-tree) -> result/eax: int
13167     # . prologue
13168     55/push-ebp
13169     89/<- %ebp 4/r32/esp
13170     #
13171     (size-of-array *(ebp+8))  # assumes we ignore the actual type name 'array' in the type
13172     05/add-to-eax 8/imm32  # for read/write pointers
13173 $size-of-stream:end:
13174     # . epilogue
13175     89/<- %esp 5/r32/ebp
13176     5d/pop-to-ebp
13177     c3/return
13178 
13179 size-of-type-id:  # t: type-id -> result/eax: int
13180     # . prologue
13181     55/push-ebp
13182     89/<- %ebp 4/r32/esp
13183     # . save registers
13184     51/push-ecx
13185     # var out/ecx: (handle typeinfo)
13186     68/push 0/imm32
13187     68/push 0/imm32
13188     89/<- %ecx 4/r32/esp
13189     # eax = t
13190     8b/-> *(ebp+8) 0/r32/eax
13191     # if t is a literal, return 0
13192     3d/compare-eax-and 0/imm32
13193     0f 84/jump-if-= $size-of-type-id:end/disp32  # eax changes type from type-id to int
13194     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
13195     3d/compare-eax-and 8/imm32/byte
13196     {
13197       75/jump-if-!= break/disp8
13198       b8/copy-to-eax 4/imm32
13199       eb/jump $size-of-type-id:end/disp8
13200     }
13201     # if t is a handle, return 8
13202     3d/compare-eax-and 4/imm32/handle
13203     {
13204       75/jump-if-!= break/disp8
13205       b8/copy-to-eax 8/imm32
13206       eb/jump $size-of-type-id:end/disp8  # eax changes type from type-id to int
13207     }
13208     # if t is a user-defined type, return its size
13209     # TODO: support non-atom type
13210     (find-typeinfo %eax %ecx)
13211     {
13212       81 7/subop/compare *ecx 0/imm32
13213       74/jump-if-= break/disp8
13214 $size-of-type-id:user-defined:
13215       (lookup *ecx *(ecx+4))  # => eax
13216       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
13217       eb/jump $size-of-type-id:end/disp8
13218     }
13219     # otherwise return the word size
13220     b8/copy-to-eax 4/imm32
13221 $size-of-type-id:end:
13222     # . reclaim locals
13223     81 0/subop/add %esp 8/imm32
13224     # . restore registers
13225     59/pop-to-ecx
13226     # . epilogue
13227     89/<- %esp 5/r32/ebp
13228     5d/pop-to-ebp
13229     c3/return
13230 
13231 type-equal?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
13232     # . prologue
13233     55/push-ebp
13234     89/<- %ebp 4/r32/esp
13235     # . save registers
13236     51/push-ecx
13237     52/push-edx
13238     53/push-ebx
13239     # ecx = a
13240     8b/-> *(ebp+8) 1/r32/ecx
13241     # edx = b
13242     8b/-> *(ebp+0xc) 2/r32/edx
13243 $type-equal?:compare-addr:
13244     # if (a == b) return true
13245     8b/-> %ecx 0/r32/eax  # Var-type
13246     39/compare %edx 0/r32/eax  # Var-type
13247     b8/copy-to-eax 1/imm32/true
13248     0f 84/jump-if-= $type-equal?:end/disp32
13249 $type-equal?:compare-atom-state:
13250     # if (a->is-atom? != b->is-atom?) return false
13251     8b/-> *ecx 3/r32/ebx  # Type-tree-is-atom
13252     39/compare *edx 3/r32/ebx  # Type-tree-is-atom
13253     b8/copy-to-eax 0/imm32/false
13254     0f 85/jump-if-!= $type-equal?:end/disp32
13255     # if a->is-atom? return (a->value == b->value)
13256     {
13257 $type-equal?:check-atom:
13258       81 7/subop/compare %ebx 0/imm32/false
13259       74/jump-if-= break/disp8
13260 $type-equal?:is-atom:
13261       8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
13262       39/compare *(edx+4) 0/r32/eax  # Type-tree-value
13263       0f 94/set-if-= %al
13264       81 4/subop/and %eax 0xff/imm32
13265       e9/jump $type-equal?:end/disp32
13266     }
13267 $type-equal?:check-left:
13268     # if (!type-equal?(a->left, b->left)) return false
13269     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
13270     89/<- %ebx 0/r32/eax
13271     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
13272     (type-equal? %eax %ebx)  # => eax
13273     3d/compare-eax-and 0/imm32/false
13274     74/jump-if-= $type-equal?:end/disp8
13275 $type-equal?:check-right:
13276     # return type-equal?(a->right, b->right)
13277     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
13278     89/<- %ebx 0/r32/eax
13279     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
13280     (type-equal? %eax %ebx)  # => eax
13281 $type-equal?:end:
13282     # . restore registers
13283     5b/pop-to-ebx
13284     5a/pop-to-edx
13285     59/pop-to-ecx
13286     # . epilogue
13287     89/<- %esp 5/r32/ebp
13288     5d/pop-to-ebp
13289     c3/return
13290 
13291 #######################################################
13292 # Code-generation
13293 #######################################################
13294 
13295 == data
13296 
13297 # Global state added to each var record when performing code-generation.
13298 Curr-local-stack-offset:  # (addr int)
13299     0/imm32
13300 
13301 == code
13302 
13303 emit-subx:  # out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
13304     # . prologue
13305     55/push-ebp
13306     89/<- %ebp 4/r32/esp
13307     # . save registers
13308     50/push-eax
13309     # var curr/eax: (addr function) = *Program->functions
13310     (lookup *_Program-functions *_Program-functions->payload)  # => eax
13311     {
13312       # if (curr == null) break
13313       3d/compare-eax-and 0/imm32
13314       0f 84/jump-if-= break/disp32
13315       (emit-subx-function *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))
13316       # curr = lookup(curr->next)
13317       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
13318       e9/jump loop/disp32
13319     }
13320 $emit-subx:end:
13321     # . restore registers
13322     58/pop-to-eax
13323     # . epilogue
13324     89/<- %esp 5/r32/ebp
13325     5d/pop-to-ebp
13326     c3/return
13327 
13328 emit-subx-function:  # out: (addr buffered-file), f: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13329     # . prologue
13330     55/push-ebp
13331     89/<- %ebp 4/r32/esp
13332     # some preprocessing
13333     (populate-mu-type-offsets-in-inouts *(ebp+0xc))
13334     # . save registers
13335     50/push-eax
13336     51/push-ecx
13337     52/push-edx
13338     # initialize some global state
13339     c7 0/subop/copy *Curr-block-depth 1/imm32  # Important: keep this in sync with the parse phase
13340     c7 0/subop/copy *Curr-local-stack-offset 0/imm32
13341     # ecx = f
13342     8b/-> *(ebp+0xc) 1/r32/ecx
13343     # var vars/edx: (stack (addr var) 256)
13344     81 5/subop/subtract %esp 0xc00/imm32
13345     68/push 0xc00/imm32/size
13346     68/push 0/imm32/top
13347     89/<- %edx 4/r32/esp
13348     # var name/eax: (addr array byte) = lookup(f->name)
13349     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
13350     #
13351     (write-buffered *(ebp+8) %eax)
13352     (write-buffered *(ebp+8) ":\n")
13353     (emit-subx-prologue *(ebp+8))
13354     # var body/eax: (addr block) = lookup(f->body)
13355     (lookup *(ecx+0x18) *(ecx+0x1c))  # Function-body Function-body => eax
13356     #
13357     (emit-subx-block *(ebp+8) %eax %edx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13358     (emit-subx-epilogue *(ebp+8))
13359     # TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have
13360     # been cleaned up
13361 $emit-subx-function:end:
13362     # . reclaim locals
13363     81 0/subop/add %esp 0xc08/imm32
13364     # . restore registers
13365     5a/pop-to-edx
13366     59/pop-to-ecx
13367     58/pop-to-eax
13368     # . epilogue
13369     89/<- %esp 5/r32/ebp
13370     5d/pop-to-ebp
13371     c3/return
13372 
13373 populate-mu-type-offsets-in-inouts:  # f: (addr function)
13374     # . prologue
13375     55/push-ebp
13376     89/<- %ebp 4/r32/esp
13377     # . save registers
13378     50/push-eax
13379     51/push-ecx
13380     52/push-edx
13381     53/push-ebx
13382     57/push-edi
13383     # var next-offset/edx: int = 8
13384     ba/copy-to-edx 8/imm32
13385     # var curr/ecx: (addr list var) = lookup(f->inouts)
13386     8b/-> *(ebp+8) 1/r32/ecx
13387     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
13388     89/<- %ecx 0/r32/eax
13389     {
13390 $populate-mu-type-offsets-in-inouts:loop:
13391       81 7/subop/compare %ecx 0/imm32
13392       74/jump-if-= break/disp8
13393       # var v/ebx: (addr var) = lookup(curr->value)
13394       (lookup *ecx *(ecx+4))  # List-value List-value => eax
13395       89/<- %ebx 0/r32/eax
13396 #?       (lookup *ebx *(ebx+4))
13397 #?       (write-buffered Stderr "setting offset of fn inout ")
13398 #?       (write-buffered Stderr %eax)
13399 #?       (write-buffered Stderr "@")
13400 #?       (write-int32-hex-buffered Stderr %ebx)
13401 #?       (write-buffered Stderr " to ")
13402 #?       (write-int32-hex-buffered Stderr %edx)
13403 #?       (write-buffered Stderr Newline)
13404 #?       (flush Stderr)
13405       # v->offset = next-offset
13406       89/<- *(ebx+0x14) 2/r32/edx  # Var-offset
13407       # next-offset += size-of(v)
13408       (size-of %ebx)  # => eax
13409       01/add-to %edx 0/r32/eax
13410       # curr = lookup(curr->next)
13411       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
13412       89/<- %ecx 0/r32/eax
13413       #
13414       eb/jump loop/disp8
13415     }
13416 $populate-mu-type-offsets-in-inouts:end:
13417     # . restore registers
13418     5f/pop-to-edi
13419     5b/pop-to-ebx
13420     5a/pop-to-edx
13421     59/pop-to-ecx
13422     58/pop-to-eax
13423     # . epilogue
13424     89/<- %esp 5/r32/ebp
13425     5d/pop-to-ebp
13426     c3/return
13427 
13428 emit-subx-stmt-list:  # out: (addr buffered-file), stmts: (addr list stmt), vars: (addr stack live-var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13429     # . prologue
13430     55/push-ebp
13431     89/<- %ebp 4/r32/esp
13432     # . save registers
13433     50/push-eax
13434     51/push-ecx
13435     53/push-ebx
13436     56/push-esi
13437     # esi = stmts
13438     8b/-> *(ebp+0xc) 6/r32/esi
13439     #
13440     {
13441 $emit-subx-stmt-list:loop:
13442       81 7/subop/compare %esi 0/imm32
13443       0f 84/jump-if-= break/disp32
13444       # var curr-stmt/ecx: (addr stmt) = lookup(stmts->value)
13445       (lookup *esi *(esi+4))  # List-value List-value => eax
13446       89/<- %ecx 0/r32/eax
13447       {
13448 $emit-subx-stmt-list:check-for-block:
13449         81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
13450         75/jump-if-!= break/disp8
13451 $emit-subx-stmt-list:block:
13452         (emit-subx-block *(ebp+8) %ecx *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
13453       }
13454       {
13455 $emit-subx-stmt-list:check-for-stmt:
13456         81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
13457         0f 85/jump-if-!= break/disp32
13458 $emit-subx-stmt-list:stmt1:
13459         {
13460           (is-mu-branch? %ecx)  # => eax
13461           3d/compare-eax-and 0/imm32/false
13462           0f 84/jump-if-= break/disp32
13463 $emit-subx-stmt-list:branch-stmt:
13464 +-- 27 lines: # unconditional loops -----------------------------------------------------------------------------------------------------------------------------------------------------
13491 +-- 16 lines: # unconditional breaks ----------------------------------------------------------------------------------------------------------------------------------------------------
13507 +-- 38 lines: # simple conditional branches without a target ----------------------------------------------------------------------------------------------------------------------------
13545 +-- 19 lines: # conditional branches with an explicit target ----------------------------------------------------------------------------------------------------------------------------
13564         }
13565 $emit-subx-stmt-list:1-to-1:
13566         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
13567         e9/jump $emit-subx-stmt-list:continue/disp32
13568       }
13569       {
13570 $emit-subx-stmt-list:check-for-var-def:
13571         81 7/subop/compare *ecx 2/imm32/var-def  # Stmt-tag
13572         75/jump-if-!= break/disp8
13573 $emit-subx-stmt-list:var-def:
13574         (emit-subx-var-def *(ebp+8) %ecx)
13575         (push *(ebp+0x10) *(ecx+4))  # Vardef-var
13576         (push *(ebp+0x10) *(ecx+8))  # Vardef-var
13577         (push *(ebp+0x10) 0)  # Live-var-register-spilled = 0 for vars on the stack
13578         #
13579         eb/jump $emit-subx-stmt-list:continue/disp8
13580       }
13581       {
13582 $emit-subx-stmt-list:check-for-reg-var-def:
13583         81 7/subop/compare *ecx 3/imm32/reg-var-def  # Stmt-tag
13584         0f 85/jump-if-!= break/disp32
13585 $emit-subx-stmt-list:reg-var-def:
13586         # TODO: ensure that there's exactly one output
13587         (push-output-and-maybe-emit-spill *(ebp+8) %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
13588         # emit the instruction as usual
13589         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
13590         #
13591         eb/jump $emit-subx-stmt-list:continue/disp8
13592       }
13593 $emit-subx-stmt-list:continue:
13594       # TODO: raise an error on unrecognized Stmt-tag
13595       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
13596       89/<- %esi 0/r32/eax
13597       e9/jump loop/disp32
13598     }
13599 $emit-subx-stmt-list:emit-cleanup:
13600     (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
13601 $emit-subx-stmt-list:clean-up:
13602     (clean-up-blocks *(ebp+0x10) *Curr-block-depth *(ebp+0x14))
13603 $emit-subx-stmt-list:end:
13604     # . restore registers
13605     5e/pop-to-esi
13606     5b/pop-to-ebx
13607     59/pop-to-ecx
13608     58/pop-to-eax
13609     # . epilogue
13610     89/<- %esp 5/r32/ebp
13611     5d/pop-to-ebp
13612     c3/return
13613 
13614 # 'later-stmts' includes 'stmt', but will behave the same even without it; reg-var-def stmts are guaranteed not to write to function outputs.
13615 push-output-and-maybe-emit-spill:  # out: (addr buffered-file), stmt: (addr reg-var-def), vars: (addr stack (handle var)), later-stmts: (addr list stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13616     # . prologue
13617     55/push-ebp
13618     89/<- %ebp 4/r32/esp
13619     # . save registers
13620     50/push-eax
13621     51/push-ecx
13622     52/push-edx
13623     # ecx = stmt
13624     8b/-> *(ebp+0xc) 1/r32/ecx
13625     # var sv/eax: (addr stmt-var) = lookup(curr-stmt->outputs)
13626     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
13627     # TODO: assert !sv->is-deref?
13628     # var v/ecx: (addr var) = lookup(sv->value)
13629     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13630     89/<- %ecx 0/r32/eax
13631     # v->block-depth = *Curr-block-depth
13632     8b/-> *Curr-block-depth 0/r32/eax
13633     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
13634 #?     (write-buffered Stderr "var ")
13635 #?     (lookup *ecx *(ecx+4))
13636 #?     (write-buffered Stderr %eax)
13637 #?     (write-buffered Stderr " at depth ")
13638 #?     (write-int32-hex-buffered Stderr *(ecx+0x10))
13639 #?     (write-buffered Stderr Newline)
13640 #?     (flush Stderr)
13641     # ensure that v is in a register
13642     81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13643     0f 84/jump-if-= $push-output-and-maybe-emit-spill:abort/disp32
13644     # var emit-spill?/edx: boolean = not-yet-spilled-this-block? && will-not-write-some-register?(fn)
13645     (not-yet-spilled-this-block? %ecx *(ebp+0x10))  # => eax
13646     89/<- %edx 0/r32/eax
13647     3d/compare-eax-and 0/imm32/false
13648     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
13649     (will-not-write-some-register? %ecx *(ebp+0x14) *(ebp+0x18))  # => eax
13650     89/<- %edx 0/r32/eax
13651     # check emit-spill?
13652     3d/compare-eax-and 0/imm32/false
13653     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
13654     # TODO: assert(size-of(output) == 4)
13655     # *Curr-local-stack-offset -= 4
13656     81 5/subop/subtract *Curr-local-stack-offset 4/imm32
13657     # emit spill
13658     (emit-indent *(ebp+8) *Curr-block-depth)
13659     (write-buffered *(ebp+8) "ff 6/subop/push %")
13660     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
13661     (write-buffered *(ebp+8) %eax)
13662     (write-buffered *(ebp+8) Newline)
13663 $push-output-and-maybe-emit-spill:push:
13664     8b/-> *(ebp+0xc) 1/r32/ecx
13665     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
13666     # push(vars, {sv->value, emit-spill?})
13667     (push *(ebp+0x10) *eax)  # Stmt-var-value
13668     (push *(ebp+0x10) *(eax+4))  # Stmt-var-value
13669     (push *(ebp+0x10) %edx)
13670 $push-output-and-maybe-emit-spill:end:
13671     # . restore registers
13672     5a/pop-to-edx
13673     59/pop-to-ecx
13674     58/pop-to-eax
13675     # . epilogue
13676     89/<- %esp 5/r32/ebp
13677     5d/pop-to-ebp
13678     c3/return
13679 
13680 $push-output-and-maybe-emit-spill:abort:
13681     # error("var '" var->name "' initialized from an instruction must live in a register\n")
13682     (write-buffered *(ebp+0x1c) "var '")
13683     (write-buffered *(ebp+0x1c) *eax)  # Var-name
13684     (write-buffered *(ebp+0x1c) "' initialized from an instruction must live in a register\n")
13685     (flush *(ebp+0x1c))
13686     (stop *(ebp+0x20) 1)
13687     # never gets here
13688 
13689 emit-subx-cleanup-and-unconditional-nonlocal-branch:  # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack live-var)
13690     # . prologue
13691     55/push-ebp
13692     89/<- %ebp 4/r32/esp
13693     # . save registers
13694     50/push-eax
13695     51/push-ecx
13696     # ecx = stmt
13697     8b/-> *(ebp+0xc) 1/r32/ecx
13698     # var target/eax: (addr array byte) = curr-stmt->inouts->value->name
13699     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13700     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13701     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13702     # clean up until target block
13703     (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %eax)
13704     # emit jump to target block
13705     (emit-indent *(ebp+8) *Curr-block-depth)
13706     (write-buffered *(ebp+8) "e9/jump ")
13707     (write-buffered *(ebp+8) %eax)
13708     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
13709     (string-starts-with? %eax "break")
13710     3d/compare-eax-and 0/imm32/false
13711     {
13712       74/jump-if-= break/disp8
13713       (write-buffered *(ebp+8) ":break/disp32\n")
13714     }
13715     3d/compare-eax-and 0/imm32/false  # just in case the function call modified flags
13716     {
13717       75/jump-if-!= break/disp8
13718       (write-buffered *(ebp+8) ":loop/disp32\n")
13719     }
13720 $emit-subx-cleanup-and-unconditional-nonlocal-branch:end:
13721     # . restore registers
13722     59/pop-to-ecx
13723     58/pop-to-eax
13724     # . epilogue
13725     89/<- %esp 5/r32/ebp
13726     5d/pop-to-ebp
13727     c3/return
13728 
13729 is-mu-branch?:  # stmt: (addr stmt1) -> result/eax: boolean
13730     # . prologue
13731     55/push-ebp
13732     89/<- %ebp 4/r32/esp
13733     # . save registers
13734     51/push-ecx
13735     # ecx = lookup(stmt->operation)
13736     8b/-> *(ebp+8) 1/r32/ecx
13737     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
13738     89/<- %ecx 0/r32/eax
13739     # if (stmt->operation starts with "loop") return true
13740     (string-starts-with? %ecx "loop")  # => eax
13741     3d/compare-eax-and 0/imm32/false
13742     75/jump-if-not-equal $is-mu-branch?:end/disp8
13743     # otherwise return (stmt->operation starts with "break")
13744     (string-starts-with? %ecx "break")  # => eax
13745 $is-mu-branch?:end:
13746     # . restore registers
13747     59/pop-to-ecx
13748     # . epilogue
13749     89/<- %esp 5/r32/ebp
13750     5d/pop-to-ebp
13751     c3/return
13752 
13753 emit-reverse-break:  # out: (addr buffered-file), stmt: (addr stmt1)
13754     # . prologue
13755     55/push-ebp
13756     89/<- %ebp 4/r32/esp
13757     # . save registers
13758     50/push-eax
13759     # eax = stmt
13760     8b/-> *(ebp+0xc) 0/r32/eax
13761     #
13762     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
13763     (get Reverse-branch %eax 0x10 "reverse-branch: ")  # => eax: (addr handle array byte)
13764     (emit-indent *(ebp+8) *Curr-block-depth)
13765     (lookup *eax *(eax+4))  # => eax
13766     (write-buffered *(ebp+8) %eax)
13767     (write-buffered *(ebp+8) " break/disp32\n")
13768 $emit-reverse-break:end:
13769     # . restore registers
13770     58/pop-to-eax
13771     # . epilogue
13772     89/<- %esp 5/r32/ebp
13773     5d/pop-to-ebp
13774     c3/return
13775 
13776 == data
13777 
13778 # Table from Mu branch instructions to the reverse SubX opcodes for them.
13779 Reverse-branch:  # (table (handle array byte) (handle array byte))
13780   # a table is a stream
13781   0x140/imm32/write
13782   0/imm32/read
13783   0x140/imm32/size
13784   # data
13785   0x11/imm32/alloc-id   _string-break-if-=/imm32                0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
13786   0x11/imm32/alloc-id   _string-loop-if-=/imm32                 0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
13787   0x11/imm32/alloc-id   _string-break-if-!=/imm32               0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
13788   0x11/imm32/alloc-id   _string-loop-if-!=/imm32                0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
13789   0x11/imm32/alloc-id   _string-break-if-</imm32                0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
13790   0x11/imm32/alloc-id   _string-loop-if-</imm32                 0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
13791   0x11/imm32/alloc-id   _string-break-if->/imm32                0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
13792   0x11/imm32/alloc-id   _string-loop-if->/imm32                 0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
13793   0x11/imm32/alloc-id   _string-break-if-<=/imm32               0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
13794   0x11/imm32/alloc-id   _string-loop-if-<=/imm32                0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
13795   0x11/imm32/alloc-id   _string-break-if->=/imm32               0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
13796   0x11/imm32/alloc-id   _string-loop-if->=/imm32                0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
13797   0x11/imm32/alloc-id   _string-break-if-addr</imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
13798   0x11/imm32/alloc-id   _string-loop-if-addr</imm32             0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
13799   0x11/imm32/alloc-id   _string-break-if-addr>/imm32            0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
13800   0x11/imm32/alloc-id   _string-loop-if-addr>/imm32             0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
13801   0x11/imm32/alloc-id   _string-break-if-addr<=/imm32           0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
13802   0x11/imm32/alloc-id   _string-loop-if-addr<=/imm32            0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
13803   0x11/imm32/alloc-id   _string-break-if-addr>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
13804   0x11/imm32/alloc-id   _string-loop-if-addr>=/imm32            0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
13805 
13806 == code
13807 
13808 emit-unconditional-jump-to-depth:  # out: (addr buffered-file), vars: (addr stack live-var), depth: int, label-suffix: (addr array byte)
13809     # . prologue
13810     55/push-ebp
13811     89/<- %ebp 4/r32/esp
13812     # . save registers
13813     50/push-eax
13814     51/push-ecx
13815     52/push-edx
13816     53/push-ebx
13817     56/push-esi
13818     # ecx = vars
13819     8b/-> *(ebp+0xc) 1/r32/ecx
13820     # var eax: int = vars->top
13821     8b/-> *ecx 0/r32/eax
13822     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
13823     8d/copy-address *(ecx+eax-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
13824     # var min/ecx: (addr handle var) = vars->data
13825     8d/copy-address *(ecx+8) 1/r32/ecx
13826     # edx = depth
13827     8b/-> *(ebp+0x10) 2/r32/edx
13828     {
13829 $emit-unconditional-jump-to-depth:loop:
13830       # if (curr < min) break
13831       39/compare %esi 1/r32/ecx
13832       0f 82/jump-if-addr< break/disp32
13833       # var v/ebx: (addr var) = lookup(*curr)
13834       (lookup *esi *(esi+4))  # => eax
13835       89/<- %ebx 0/r32/eax
13836       # if (v->block-depth < until-block-depth) break
13837       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
13838       0f 8c/jump-if-< break/disp32
13839       {
13840 $emit-unconditional-jump-to-depth:check:
13841         # if v->block-depth != until-block-depth, continue
13842         39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
13843         0f 85/jump-if-!= break/disp32
13844 $emit-unconditional-jump-to-depth:depth-found:
13845         # if v is not a literal, continue
13846         (size-of %ebx)  # => eax
13847         3d/compare-eax-and 0/imm32
13848         0f 85/jump-if-!= break/disp32
13849 $emit-unconditional-jump-to-depth:label-found:
13850         # emit unconditional jump, then return
13851         (emit-indent *(ebp+8) *Curr-block-depth)
13852         (write-buffered *(ebp+8) "e9/jump ")
13853         (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
13854         (write-buffered *(ebp+8) %eax)
13855         (write-buffered *(ebp+8) ":")
13856         (write-buffered *(ebp+8) *(ebp+0x14))
13857         (write-buffered *(ebp+8) "/disp32\n")
13858         eb/jump $emit-unconditional-jump-to-depth:end/disp8
13859       }
13860       # curr -= 12
13861       81 5/subop/subtract %esi 0xc/imm32
13862       e9/jump loop/disp32
13863     }
13864     # TODO: error if no label at 'depth' was found
13865 $emit-unconditional-jump-to-depth:end:
13866     # . restore registers
13867     5e/pop-to-esi
13868     5b/pop-to-ebx
13869     5a/pop-to-edx
13870     59/pop-to-ecx
13871     58/pop-to-eax
13872     # . epilogue
13873     89/<- %esp 5/r32/ebp
13874     5d/pop-to-ebp
13875     c3/return
13876 
13877 # emit clean-up code for 'vars' until some block depth
13878 # doesn't actually modify 'vars' so we need traverse manually inside the stack
13879 emit-cleanup-code-until-depth:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-depth: int
13880     # . prologue
13881     55/push-ebp
13882     89/<- %ebp 4/r32/esp
13883     # . save registers
13884     50/push-eax
13885     51/push-ecx
13886     52/push-edx
13887     53/push-ebx
13888     56/push-esi
13889 #?     (write-buffered Stderr "--- cleanup\n")
13890 #?     (flush Stderr)
13891     # ecx = vars
13892     8b/-> *(ebp+0xc) 1/r32/ecx
13893     # var esi: int = vars->top
13894     8b/-> *ecx 6/r32/esi
13895     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
13896     8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
13897     # var min/ecx: (addr handle var) = vars->data
13898     81 0/subop/add %ecx 8/imm32
13899     # edx = until-block-depth
13900     8b/-> *(ebp+0x10) 2/r32/edx
13901     {
13902 $emit-cleanup-code-until-depth:loop:
13903       # if (curr < min) break
13904       39/compare %esi 1/r32/ecx
13905       0f 82/jump-if-addr< break/disp32
13906       # var v/ebx: (addr var) = lookup(*curr)
13907       (lookup *esi *(esi+4))  # => eax
13908       89/<- %ebx 0/r32/eax
13909 #?       (lookup *ebx *(ebx+4))  # Var-name
13910 #?       (write-buffered Stderr "var ")
13911 #?       (write-buffered Stderr %eax)
13912 #?       (write-buffered Stderr Newline)
13913 #?       (flush Stderr)
13914       # if (v->block-depth < until-block-depth) break
13915       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
13916       0f 8c/jump-if-< break/disp32
13917       # if v is in a register
13918       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
13919       {
13920         0f 84/jump-if-= break/disp32
13921         {
13922 $emit-cleanup-code-until-depth:check-for-previous-spill:
13923           8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
13924           3d/compare-eax-and 0/imm32/false
13925           74/jump-if-= break/disp8
13926 $emit-cleanup-code-until-depth:reclaim-var-in-register:
13927           (emit-indent *(ebp+8) *Curr-block-depth)
13928           (write-buffered *(ebp+8) "8f 0/subop/pop %")
13929           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
13930           (write-buffered *(ebp+8) %eax)
13931           (write-buffered *(ebp+8) Newline)
13932         }
13933         eb/jump $emit-cleanup-code-until-depth:continue/disp8
13934       }
13935       # otherwise v is on the stack
13936       {
13937         75/jump-if-!= break/disp8
13938 $emit-cleanup-code-until-depth:var-on-stack:
13939         (size-of %ebx)  # => eax
13940         # don't emit code for labels
13941         3d/compare-eax-and 0/imm32
13942         74/jump-if-= break/disp8
13943 $emit-cleanup-code-until-depth:reclaim-var-on-stack:
13944         (emit-indent *(ebp+8) *Curr-block-depth)
13945         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
13946         (write-int32-hex-buffered *(ebp+8) %eax)
13947         (write-buffered *(ebp+8) "/imm32\n")
13948       }
13949 $emit-cleanup-code-until-depth:continue:
13950       # curr -= 12
13951       81 5/subop/subtract %esi 0xc/imm32
13952       e9/jump loop/disp32
13953     }
13954 $emit-cleanup-code-until-depth:end:
13955     # . restore registers
13956     5e/pop-to-esi
13957     5b/pop-to-ebx
13958     5a/pop-to-edx
13959     59/pop-to-ecx
13960     58/pop-to-eax
13961     # . epilogue
13962     89/<- %esp 5/r32/ebp
13963     5d/pop-to-ebp
13964     c3/return
13965 
13966 # emit clean-up code for 'vars' until a given label is encountered
13967 # doesn't actually modify 'vars' so we need traverse manually inside the stack
13968 emit-cleanup-code-until-target:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-label: (addr array byte)
13969     # . prologue
13970     55/push-ebp
13971     89/<- %ebp 4/r32/esp
13972     # . save registers
13973     50/push-eax
13974     51/push-ecx
13975     52/push-edx
13976     53/push-ebx
13977     # ecx = vars
13978     8b/-> *(ebp+0xc) 1/r32/ecx
13979     # var eax: int = vars->top
13980     8b/-> *ecx 0/r32/eax
13981     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
13982     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
13983     # var min/ecx: (addr handle var) = vars->data
13984     81 0/subop/add %ecx 8/imm32
13985     {
13986 $emit-cleanup-code-until-target:loop:
13987       # if (curr < min) break
13988       39/compare %edx 1/r32/ecx
13989       0f 82/jump-if-addr< break/disp32
13990       # var v/ebx: (handle var) = lookup(*curr)
13991       (lookup *edx *(edx+4))  # => eax
13992       89/<- %ebx 0/r32/eax
13993       # if (v->name == until-block-label) break
13994       (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
13995       (string-equal? %eax *(ebp+0x10))  # => eax
13996       3d/compare-eax-and 0/imm32/false
13997       0f 85/jump-if-!= break/disp32
13998       # if v is in a register
13999       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
14000       {
14001         0f 84/jump-if-= break/disp32
14002         {
14003 $emit-cleanup-code-until-target:check-for-previous-spill:
14004           8b/-> *(edx+8) 0/r32/eax  # Live-var-register-spilled
14005           3d/compare-eax-and 0/imm32/false
14006           74/jump-if-= break/disp8
14007 $emit-cleanup-code-until-target:reclaim-var-in-register:
14008           (emit-indent *(ebp+8) *Curr-block-depth)
14009           (write-buffered *(ebp+8) "8f 0/subop/pop %")
14010           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
14011           (write-buffered *(ebp+8) %eax)
14012           (write-buffered *(ebp+8) Newline)
14013         }
14014         eb/jump $emit-cleanup-code-until-target:continue/disp8
14015       }
14016       # otherwise v is on the stack
14017       {
14018         75/jump-if-!= break/disp8
14019 $emit-cleanup-code-until-target:reclaim-var-on-stack:
14020         (size-of %ebx)  # => eax
14021         # don't emit code for labels
14022         3d/compare-eax-and 0/imm32
14023         74/jump-if-= break/disp8
14024         #
14025         (emit-indent *(ebp+8) *Curr-block-depth)
14026         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
14027         (write-int32-hex-buffered *(ebp+8) %eax)
14028         (write-buffered *(ebp+8) "/imm32\n")
14029       }
14030 $emit-cleanup-code-until-target:continue:
14031       # curr -= 12
14032       81 5/subop/subtract %edx 0xc/imm32
14033       e9/jump loop/disp32
14034     }
14035 $emit-cleanup-code-until-target:end:
14036     # . restore registers
14037     5b/pop-to-ebx
14038     5a/pop-to-edx
14039     59/pop-to-ecx
14040     58/pop-to-eax
14041     # . epilogue
14042     89/<- %esp 5/r32/ebp
14043     5d/pop-to-ebp
14044     c3/return
14045 
14046 # Return true if there isn't a variable in 'vars' with the same block-depth
14047 # and register as 'v'.
14048 # 'v' is guaranteed not to be within 'vars'.
14049 not-yet-spilled-this-block?:  # v: (addr var), vars: (addr stack live-var) -> result/eax: boolean
14050     # . prologue
14051     55/push-ebp
14052     89/<- %ebp 4/r32/esp
14053     # . save registers
14054     51/push-ecx
14055     52/push-edx
14056     53/push-ebx
14057     56/push-esi
14058     57/push-edi
14059     # ecx = vars
14060     8b/-> *(ebp+0xc) 1/r32/ecx
14061     # var eax: int = vars->top
14062     8b/-> *ecx 0/r32/eax
14063     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
14064     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
14065     # var min/ecx: (addr handle var) = vars->data
14066     8d/copy-address *(ecx+8) 1/r32/ecx
14067     # var depth/ebx: int = v->block-depth
14068     8b/-> *(ebp+8) 3/r32/ebx
14069     8b/-> *(ebx+0x10) 3/r32/ebx  # Var-block-depth
14070     # var needle/esi: (addr array byte) = v->register
14071     8b/-> *(ebp+8) 6/r32/esi
14072     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
14073     89/<- %esi 0/r32/eax
14074     {
14075 $not-yet-spilled-this-block?:loop:
14076       # if (curr < min) break
14077       39/compare %edx 1/r32/ecx
14078       0f 82/jump-if-addr< break/disp32
14079       # var cand/edi: (addr var) = lookup(*curr)
14080       (lookup *edx *(edx+4))  # => eax
14081       89/<- %edi 0/r32/eax
14082       # if (cand->block-depth < depth) break
14083       39/compare *(edi+0x10) 3/r32/ebx  # Var-block-depth
14084       0f 8c/jump-if-< break/disp32
14085       # var cand-reg/edi: (array array byte) = cand->reg
14086       (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
14087       89/<- %edi 0/r32/eax
14088       # if (cand-reg == null) continue
14089       {
14090 $not-yet-spilled-this-block?:check-reg:
14091         81 7/subop/compare %edi 0/imm32
14092         0f 84/jump-if-= break/disp32
14093         # if (cand-reg == needle) return true
14094         (string-equal? %esi %edi)  # => eax
14095         3d/compare-eax-and 0/imm32/false
14096         74/jump-if-= break/disp8
14097 $not-yet-spilled-this-block?:return-false:
14098         b8/copy-to-eax 0/imm32/false
14099         eb/jump $not-yet-spilled-this-block?:end/disp8
14100       }
14101 $not-yet-spilled-this-block?:continue:
14102       # curr -= 12
14103       81 5/subop/subtract %edx 0xc/imm32
14104       e9/jump loop/disp32
14105     }
14106 $not-yet-spilled-this-block?:return-true:
14107     # return true
14108     b8/copy-to-eax 1/imm32/true
14109 $not-yet-spilled-this-block?:end:
14110     # . restore registers
14111     5f/pop-to-edi
14112     5e/pop-to-esi
14113     5b/pop-to-ebx
14114     5a/pop-to-edx
14115     59/pop-to-ecx
14116     # . epilogue
14117     89/<- %esp 5/r32/ebp
14118     5d/pop-to-ebp
14119     c3/return
14120 
14121 # could the register of 'v' ever be written to by one of the vars in fn-outputs?
14122 will-not-write-some-register?:  # v: (addr var), stmts: (addr list stmt), fn: (addr function) -> result/eax: boolean
14123     # . prologue
14124     55/push-ebp
14125     89/<- %ebp 4/r32/esp
14126     # eax = v
14127     8b/-> *(ebp+8) 0/r32/eax
14128     # var reg/eax: (addr array byte) = lookup(v->register)
14129     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
14130     # var target/eax: (addr var) = find-register(fn-outputs, reg)
14131     (find-register *(ebp+0x10) %eax)  # => eax
14132     # if (target == 0) return true
14133     {
14134       3d/compare-eax-and 0/imm32
14135       75/jump-if-!= break/disp8
14136       b8/copy-to-eax 1/imm32/true
14137       eb/jump $will-not-write-some-register?:end/disp8
14138     }
14139     # return !assigns-in-stmts?(stmts, target)
14140     (assigns-in-stmts? *(ebp+0xc) %eax)  # => eax
14141     3d/compare-eax-and 0/imm32/false
14142     # assume: true = 1, so no need to mask with 0x000000ff
14143     0f 94/set-if-= %al
14144 $will-not-write-some-register?:end:
14145     # . epilogue
14146     89/<- %esp 5/r32/ebp
14147     5d/pop-to-ebp
14148     c3/return
14149 
14150 # return fn output with matching register
14151 # always returns false if 'reg' is null
14152 find-register:  # fn: (addr function), reg: (addr array byte) -> result/eax: (addr var)
14153     # . prologue
14154     55/push-ebp
14155     89/<- %ebp 4/r32/esp
14156     # . save registers
14157     51/push-ecx
14158     # var curr/ecx: (addr list var) = lookup(fn->outputs)
14159     8b/-> *(ebp+8) 1/r32/ecx
14160     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
14161     89/<- %ecx 0/r32/eax
14162     {
14163 $find-register:loop:
14164       # if (curr == 0) break
14165       81 7/subop/compare %ecx 0/imm32
14166       74/jump-if-= break/disp8
14167       # eax = curr->value->register
14168       (lookup *ecx *(ecx+4))  # List-value List-value => eax
14169       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
14170       # if (eax == reg) return curr->value
14171 $find-register:compare:
14172       (string-equal? *(ebp+0xc) %eax)  # => eax
14173       {
14174         3d/compare-eax-and 0/imm32/false
14175         74/jump-if-= break/disp8
14176 $find-register:found:
14177         (lookup *ecx *(ecx+4))  # List-value List-value => eax
14178         eb/jump $find-register:end/disp8
14179       }
14180       # curr = lookup(curr->next)
14181       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
14182       89/<- %ecx 0/r32/eax
14183       #
14184       eb/jump loop/disp8
14185     }
14186 $find-register:end:
14187     # . restore registers
14188     59/pop-to-ecx
14189     # . epilogue
14190     89/<- %esp 5/r32/ebp
14191     5d/pop-to-ebp
14192     c3/return
14193 
14194 assigns-in-stmts?:  # stmts: (addr list stmt), v: (addr var) -> result/eax: boolean
14195     # . prologue
14196     55/push-ebp
14197     89/<- %ebp 4/r32/esp
14198     # . save registers
14199     51/push-ecx
14200     # var curr/ecx: (addr list stmt) = stmts
14201     8b/-> *(ebp+8) 1/r32/ecx
14202     {
14203       # if (curr == 0) break
14204       81 7/subop/compare %ecx 0/imm32
14205       74/jump-if-= break/disp8
14206       # if assigns-in-stmt?(curr->value, v) return true
14207       (lookup *ecx *(ecx+4))  # List-value List-value => eax
14208       (assigns-in-stmt? %eax *(ebp+0xc))  # => eax
14209       3d/compare-eax-and 0/imm32/false
14210       75/jump-if-!= break/disp8
14211       # curr = lookup(curr->next)
14212       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
14213       89/<- %ecx 0/r32/eax
14214       #
14215       eb/jump loop/disp8
14216     }
14217 $assigns-in-stmts?:end:
14218     # . restore registers
14219     59/pop-to-ecx
14220     # . epilogue
14221     89/<- %esp 5/r32/ebp
14222     5d/pop-to-ebp
14223     c3/return
14224 
14225 assigns-in-stmt?:  # stmt: (addr stmt), v: (addr var) -> result/eax: boolean
14226     # . prologue
14227     55/push-ebp
14228     89/<- %ebp 4/r32/esp
14229     # . save registers
14230     51/push-ecx
14231     # ecx = stmt
14232     8b/-> *(ebp+8) 1/r32/ecx
14233     # if stmt is a stmt1, return assigns-in-stmt-vars?(stmt->outputs, v)
14234     {
14235       81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
14236       75/jump-if-!= break/disp8
14237       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
14238       (assigns-in-stmt-vars? %eax *(ebp+0xc))  # => eax
14239       eb/jump $assigns-in-stmt?:end/disp8
14240     }
14241     # if stmt is a block, return assigns-in-stmts?(stmt->stmts, v)
14242     {
14243       81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
14244       75/jump-if-!= break/disp8
14245       (lookup *(ecx+4) *(ecx+8))  # Block-stmts Block-stmts => eax
14246       (assigns-in-stmts? %eax *(ebp+0xc))  # => eax
14247       eb/jump $assigns-in-stmt?:end/disp8
14248     }
14249     # otherwise return false
14250     b8/copy 0/imm32/false
14251 $assigns-in-stmt?:end:
14252     # . restore registers
14253     59/pop-to-ecx
14254     # . epilogue
14255     89/<- %esp 5/r32/ebp
14256     5d/pop-to-ebp
14257     c3/return
14258 
14259 assigns-in-stmt-vars?:  # stmt-var: (addr stmt-var), v: (addr var) -> result/eax: boolean
14260     # . prologue
14261     55/push-ebp
14262     89/<- %ebp 4/r32/esp
14263     # . save registers
14264     51/push-ecx
14265     # var curr/ecx: (addr stmt-var) = stmt-var
14266     8b/-> *(ebp+8) 1/r32/ecx
14267     {
14268       # if (curr == 0) break
14269       81 7/subop/compare %ecx 0/imm32
14270       74/jump-if-= break/disp8
14271       # eax = lookup(curr->value)
14272       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14273       # if (eax == v  &&  curr->is-deref? == false) return true
14274       {
14275         39/compare *(ebp+0xc) 0/r32/eax
14276         75/jump-if-!= break/disp8
14277         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
14278         75/jump-if-!= break/disp8
14279         b8/copy-to-eax 1/imm32/true
14280         eb/jump $assigns-in-stmt-vars?:end/disp8
14281       }
14282       # curr = lookup(curr->next)
14283       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
14284       89/<- %ecx 0/r32/eax
14285       #
14286       eb/jump loop/disp8
14287     }
14288 $assigns-in-stmt-vars?:end:
14289     # . restore registers
14290     59/pop-to-ecx
14291     # . epilogue
14292     89/<- %esp 5/r32/ebp
14293     5d/pop-to-ebp
14294     c3/return
14295 
14296 # is there a var before 'v' with the same block-depth and register on the 'vars' stack?
14297 # v is guaranteed to be within vars
14298 # 'start' is provided as an optimization, a pointer within vars
14299 # *start == v
14300 same-register-spilled-before?:  # v: (addr var), vars: (addr stack (handle var)), start: (addr var) -> result/eax: boolean
14301     # . prologue
14302     55/push-ebp
14303     89/<- %ebp 4/r32/esp
14304     # . save registers
14305     51/push-ecx
14306     52/push-edx
14307     53/push-ebx
14308     56/push-esi
14309     57/push-edi
14310     # ecx = v
14311     8b/-> *(ebp+8) 1/r32/ecx
14312     # var reg/edx: (addr array byte) = lookup(v->register)
14313     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
14314     89/<- %edx 0/r32/eax
14315     # var depth/ebx: int = v->block-depth
14316     8b/-> *(ecx+0x10) 3/r32/ebx  # Var-block-depth
14317     # var min/ecx: (addr handle var) = vars->data
14318     8b/-> *(ebp+0xc) 1/r32/ecx
14319     81 0/subop/add %ecx 8/imm32
14320     # TODO: check that start >= min and start < &vars->data[top]
14321     # TODO: check that *start == v
14322     # var curr/esi: (addr handle var) = start
14323     8b/-> *(ebp+0x10) 6/r32/esi
14324     # curr -= 8
14325     81 5/subop/subtract %esi 8/imm32
14326     {
14327 $same-register-spilled-before?:loop:
14328       # if (curr < min) break
14329       39/compare %esi 1/r32/ecx
14330       0f 82/jump-if-addr< break/disp32
14331       # var x/eax: (addr var) = lookup(*curr)
14332       (lookup *esi *(esi+4))  # => eax
14333       # if (x->block-depth < depth) break
14334       39/compare *(eax+0x10) 3/r32/ebx  # Var-block-depth
14335       0f 8c/jump-if-< break/disp32
14336       # if (x->register == 0) continue
14337       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
14338       74/jump-if-= $same-register-spilled-before?:continue/disp8
14339       # if (x->register == reg) return true
14340       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
14341       (string-equal? %eax %edx)  # => eax
14342       3d/compare-eax-and 0/imm32/false
14343       b8/copy-to-eax 1/imm32/true
14344       75/jump-if-!= $same-register-spilled-before?:end/disp8
14345 $same-register-spilled-before?:continue:
14346       # curr -= 8
14347       81 5/subop/subtract %esi 8/imm32
14348       e9/jump loop/disp32
14349     }
14350 $same-register-spilled-before?:false:
14351     b8/copy-to-eax 0/imm32/false
14352 $same-register-spilled-before?:end:
14353     # . restore registers
14354     5f/pop-to-edi
14355     5e/pop-to-esi
14356     5b/pop-to-ebx
14357     5a/pop-to-edx
14358     59/pop-to-ecx
14359     # . epilogue
14360     89/<- %esp 5/r32/ebp
14361     5d/pop-to-ebp
14362     c3/return
14363 
14364 # Clean up global state for 'vars' until some block depth (inclusive).
14365 #
14366 # This would be a simple series of pops, if it wasn't for fn outputs, which
14367 # can occur anywhere in the stack.
14368 # So we have to _compact_ the entire array underlying the stack.
14369 #
14370 # We want to allow a fn output register to be written to by locals before the
14371 # output is set.
14372 # So fn outputs can't just be pushed at the start of the function.
14373 #
14374 # We want to allow other locals to shadow a fn output register after the
14375 # output is set.
14376 # So the output can't just always override anything in the stack. Sequence matters.
14377 clean-up-blocks:  # vars: (addr stack live-var), until-block-depth: int, fn: (addr function)
14378     # pseudocode:
14379     #   to = vars->top  (which points outside the stack)
14380     #   while true
14381     #     if to <= 0
14382     #       break
14383     #     var v = vars->data[to-1]
14384     #     if v.depth < until and !in-function-outputs?(fn, v)
14385     #       break
14386     #     --to
14387     #   from = to
14388     #   while true
14389     #     if from >= vars->top
14390     #       break
14391     #     assert(from >= to)
14392     #     v = vars->data[from]
14393     #     if in-function-outputs?(fn, v)
14394     #       if from > to
14395     #         vars->data[to] = vars->data[from]
14396     #       ++to
14397     #     ++from
14398     #   vars->top = to
14399     #
14400     # . prologue
14401     55/push-ebp
14402     89/<- %ebp 4/r32/esp
14403     # . save registers
14404     50/push-eax
14405     52/push-edx
14406     53/push-ebx
14407     56/push-esi
14408     57/push-edi
14409     # ebx = vars
14410     8b/-> *(ebp+8) 3/r32/ebx
14411     # edx = until-block-depth
14412     8b/-> *(ebp+0xc) 2/r32/edx
14413 $clean-up-blocks:phase1:
14414     # var to/edi: int = vars->top
14415     8b/-> *ebx 7/r32/edi
14416     {
14417 $clean-up-blocks:loop1:
14418       # if (to <= 0) break
14419       81 7/subop/compare %edi 0/imm32
14420       7e/jump-if-<= break/disp8
14421       # var v/eax: (addr var) = lookup(vars->data[to-1]->var)
14422       8d/copy-address *(ebx+edi-4) 0/r32/eax  # vars + 8 + to - 12
14423       (lookup *eax *(eax+4))  # => eax
14424       # if (v->block-depth >= until-block-depth) continue
14425       39/compare *(eax+0x10) 2/r32/edx  # Var-block-depth
14426       {
14427         7d/jump-if->= break/disp8
14428         # if (!in-function-outputs?(fn, v)) break
14429         (in-function-outputs? *(ebp+0x10) %eax)  # => eax
14430         3d/compare-eax-and 0/imm32/false
14431         74/jump-if-= $clean-up-blocks:phase2/disp8
14432       }
14433 $clean-up-blocks:loop1-continue:
14434       # --to
14435       81 5/subop/subtract %edi 0xc/imm32
14436       #
14437       eb/jump loop/disp8
14438     }
14439 $clean-up-blocks:phase2:
14440     # var from/esi: int = to
14441     89/<- %esi 7/r32/edi
14442     {
14443 $clean-up-blocks:loop2:
14444       # if (from >= vars->top) break
14445       3b/compare 6/r32/esi *ebx
14446       7d/jump-if->= break/disp8
14447       # var v/eax: (addr var) = lookup(vars->data[from]->var)
14448       8d/copy-address *(ebx+esi+8) 0/r32/eax
14449       (lookup *eax *(eax+4))  # => eax
14450       # if !in-function-outputs?(fn, v) continue
14451       (in-function-outputs? *(ebp+0x10) %eax)  # => eax
14452       3d/compare-eax-and 0/imm32/false
14453       74/jump-if-= $clean-up-blocks:loop2-continue/disp8
14454       # invariant: from >= to
14455       # if (from > to) vars->data[to] = vars->data[from]
14456       {
14457         39/compare %esi 7/r32/edi
14458         7e/jump-if-<= break/disp8
14459         56/push-esi
14460         57/push-edi
14461         # . var from/esi: (addr byte) = &vars->data[from]
14462         8d/copy-address *(ebx+esi+8) 6/r32/esi
14463         # . var to/edi: (addr byte) = &vars->data[to]
14464         8d/copy-address *(ebx+edi+8) 7/r32/edi
14465         # .
14466         8b/-> *esi 0/r32/eax
14467         89/<- *edi 0/r32/eax
14468         8b/-> *(esi+4) 0/r32/eax
14469         89/<- *(edi+4) 0/r32/eax
14470         8b/-> *(esi+8) 0/r32/eax
14471         89/<- *(edi+8) 0/r32/eax
14472         5f/pop-to-edi
14473         5e/pop-to-esi
14474       }
14475       # ++to
14476       81 0/subop/add %edi 0xc/imm32
14477 $clean-up-blocks:loop2-continue:
14478       # ++from
14479       81 0/subop/add %esi 0xc/imm32
14480       #
14481       eb/jump loop/disp8
14482     }
14483     89/<- *ebx 7/r32/edi
14484 $clean-up-blocks:end:
14485     # . restore registers
14486     5f/pop-to-edi
14487     5e/pop-to-esi
14488     5b/pop-to-ebx
14489     5a/pop-to-edx
14490     58/pop-to-eax
14491     # . epilogue
14492     89/<- %esp 5/r32/ebp
14493     5d/pop-to-ebp
14494     c3/return
14495 
14496 in-function-outputs?:  # fn: (addr function), target: (addr var) -> result/eax: boolean
14497     # . prologue
14498     55/push-ebp
14499     89/<- %ebp 4/r32/esp
14500     # . save registers
14501     51/push-ecx
14502     # var curr/ecx: (addr list var) = lookup(fn->outputs)
14503     8b/-> *(ebp+8) 1/r32/ecx
14504     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
14505     89/<- %ecx 0/r32/eax
14506     # while curr != null
14507     {
14508       81 7/subop/compare %ecx 0/imm32
14509       74/jump-if-= break/disp8
14510       # var v/eax: (addr var) = lookup(curr->value)
14511       (lookup *ecx *(ecx+4))  # List-value List-value => eax
14512       # if (v == target) return true
14513       39/compare *(ebp+0xc) 0/r32/eax
14514       b8/copy-to-eax 1/imm32/true
14515       74/jump-if-= $in-function-outputs?:end/disp8
14516       # curr = curr->next
14517       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
14518       89/<- %ecx 0/r32/eax
14519       #
14520       eb/jump loop/disp8
14521     }
14522     b8/copy-to-eax 0/imm32
14523 $in-function-outputs?:end:
14524     # . restore registers
14525     59/pop-to-ecx
14526     # . epilogue
14527     89/<- %esp 5/r32/ebp
14528     5d/pop-to-ebp
14529     c3/return
14530 
14531 emit-subx-var-def:  # out: (addr buffered-file), stmt: (addr stmt)
14532     # . prologue
14533     55/push-ebp
14534     89/<- %ebp 4/r32/esp
14535     # . save registers
14536     50/push-eax
14537     51/push-ecx
14538     52/push-edx
14539     # eax = stmt
14540     8b/-> *(ebp+0xc) 0/r32/eax
14541     # var v/ecx: (addr var)
14542     (lookup *(eax+4) *(eax+8))  # Vardef-var Vardef-var => eax
14543     89/<- %ecx 0/r32/eax
14544     # v->block-depth = *Curr-block-depth
14545     8b/-> *Curr-block-depth 0/r32/eax
14546     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
14547     # var n/edx: int = size-of(stmt->var)
14548     (size-of %ecx)  # => eax
14549     89/<- %edx 0/r32/eax
14550     # *Curr-local-stack-offset -= n
14551     29/subtract-from *Curr-local-stack-offset 2/r32/edx
14552     # v->offset = *Curr-local-stack-offset
14553     8b/-> *Curr-local-stack-offset 0/r32/eax
14554     89/<- *(ecx+0x14) 0/r32/eax  # Var-offset
14555     # if v is an array, do something special to initialize it
14556     {
14557       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
14558       (is-mu-array? %eax)  # => eax
14559       3d/compare-eax-and 0/imm32/false
14560       0f 84/jump-if-= break/disp32
14561       # var array-size-without-size/edx: int = n-4
14562       81 5/subop/subtract %edx 4/imm32
14563       #
14564       (emit-array-data-initialization *(ebp+8) %edx)
14565       e9/jump $emit-subx-var-def:end/disp32
14566     }
14567     # another special-case for initializing streams
14568     # a stream is an array with 2 extra pointers
14569     {
14570       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
14571       (is-mu-stream? %eax)  # => eax
14572       3d/compare-eax-and 0/imm32/false
14573       0f 84/jump-if-= break/disp32
14574       # var array-size-without-size/edx: int = n-12
14575       81 5/subop/subtract %edx 0xc/imm32
14576       (emit-array-data-initialization *(ebp+8) %edx)
14577       # emit read and write pointers
14578       (emit-indent *(ebp+8) *Curr-block-depth)
14579       (write-buffered *(ebp+8) "68/push 0/imm32\n")
14580       (emit-indent *(ebp+8) *Curr-block-depth)
14581       (write-buffered *(ebp+8) "68/push 0/imm32\n")
14582       #
14583       eb/jump $emit-subx-var-def:end/disp8
14584     }
14585     # while n > 0
14586     {
14587       81 7/subop/compare %edx 0/imm32
14588       7e/jump-if-<= break/disp8
14589       (emit-indent *(ebp+8) *Curr-block-depth)
14590       (write-buffered *(ebp+8) "68/push 0/imm32\n")
14591       # n -= 4
14592       81 5/subop/subtract %edx 4/imm32
14593       #
14594       eb/jump loop/disp8
14595     }
14596 $emit-subx-var-def:end:
14597     # . restore registers
14598     5a/pop-to-edx
14599     59/pop-to-ecx
14600     58/pop-to-eax
14601     # . epilogue
14602     89/<- %esp 5/r32/ebp
14603     5d/pop-to-ebp
14604     c3/return
14605 
14606 emit-array-data-initialization:  # out: (addr buffered-file), n: int
14607     # . prologue
14608     55/push-ebp
14609     89/<- %ebp 4/r32/esp
14610     #
14611     (emit-indent *(ebp+8) *Curr-block-depth)
14612     (write-buffered *(ebp+8) "(push-n-zero-bytes ")
14613     (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
14614     (write-buffered *(ebp+8) ")\n")
14615     (emit-indent *(ebp+8) *Curr-block-depth)
14616     (write-buffered *(ebp+8) "68/push ")
14617     (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
14618     (write-buffered *(ebp+8) "/imm32\n")
14619 $emit-array-data-initialization:end:
14620     # . epilogue
14621     89/<- %esp 5/r32/ebp
14622     5d/pop-to-ebp
14623     c3/return
14624 
14625 emit-subx-stmt:  # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
14626     # . prologue
14627     55/push-ebp
14628     89/<- %ebp 4/r32/esp
14629     # . save registers
14630     50/push-eax
14631     51/push-ecx
14632     # - some special-case primitives that don't actually use the 'primitives' data structure
14633     # var op/ecx: (addr array byte) = lookup(stmt->operation)
14634     8b/-> *(ebp+0xc) 1/r32/ecx
14635     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
14636     89/<- %ecx 0/r32/eax
14637     # array size
14638     {
14639       # if (!string-equal?(stmt->operation, "length")) break
14640       (string-equal? %ecx "length")  # => eax
14641       3d/compare-eax-and 0/imm32
14642       0f 84/jump-if-= break/disp32
14643       (translate-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14644       e9/jump $emit-subx-stmt:end/disp32
14645     }
14646     # index into array
14647     {
14648       # if (!string-equal?(stmt->operation, "index")) break
14649       (string-equal? %ecx "index")  # => eax
14650       3d/compare-eax-and 0/imm32
14651       0f 84/jump-if-= break/disp32
14652       (translate-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14653       e9/jump $emit-subx-stmt:end/disp32
14654     }
14655     # compute-offset for index into array
14656     {
14657       # if (!string-equal?(stmt->operation, "compute-offset")) break
14658       (string-equal? %ecx "compute-offset")  # => eax
14659       3d/compare-eax-and 0/imm32
14660       0f 84/jump-if-= break/disp32
14661       (translate-mu-compute-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14662       e9/jump $emit-subx-stmt:end/disp32
14663     }
14664     # get field from record
14665     {
14666       # if (!string-equal?(stmt->operation, "get")) break
14667       (string-equal? %ecx "get")  # => eax
14668       3d/compare-eax-and 0/imm32
14669       0f 84/jump-if-= break/disp32
14670       (translate-mu-get-stmt *(ebp+8) *(ebp+0xc))
14671       e9/jump $emit-subx-stmt:end/disp32
14672     }
14673     # allocate scalar
14674     {
14675       # if (!string-equal?(stmt->operation, "allocate")) break
14676       (string-equal? %ecx "allocate")  # => eax
14677       3d/compare-eax-and 0/imm32
14678       0f 84/jump-if-= break/disp32
14679       (translate-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14680       e9/jump $emit-subx-stmt:end/disp32
14681     }
14682     # allocate array
14683     {
14684       # if (!string-equal?(stmt->operation, "populate")) break
14685       (string-equal? %ecx "populate")  # => eax
14686       3d/compare-eax-and 0/imm32
14687       0f 84/jump-if-= break/disp32
14688       (translate-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14689       e9/jump $emit-subx-stmt:end/disp32
14690     }
14691     # allocate stream
14692     {
14693       # if (!string-equal?(stmt->operation, "populate-stream")) break
14694       (string-equal? %ecx "populate-stream")  # => eax
14695       3d/compare-eax-and 0/imm32
14696       0f 84/jump-if-= break/disp32
14697       (translate-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14698       e9/jump $emit-subx-stmt:end/disp32
14699     }
14700     # read from stream
14701     {
14702       # if (!string-equal?(stmt->operation, "read-from-stream")) break
14703       (string-equal? %ecx "read-from-stream")  # => eax
14704       3d/compare-eax-and 0/imm32
14705       0f 84/jump-if-= break/disp32
14706       (translate-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14707       e9/jump $emit-subx-stmt:end/disp32
14708     }
14709     # write to stream
14710     {
14711       # if (!string-equal?(stmt->operation, "write-to-stream")) break
14712       (string-equal? %ecx "write-to-stream")  # => eax
14713       3d/compare-eax-and 0/imm32
14714       0f 84/jump-if-= break/disp32
14715       (translate-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14716       e9/jump $emit-subx-stmt:end/disp32
14717     }
14718     # - if stmt matches a primitive, emit it
14719     {
14720 $emit-subx-stmt:check-for-primitive:
14721       # var curr/eax: (addr primitive)
14722       (find-matching-primitive *(ebp+0x10) *(ebp+0xc))  # primitives, stmt => eax
14723       3d/compare-eax-and 0/imm32
14724       74/jump-if-= break/disp8
14725 $emit-subx-stmt:primitive:
14726       (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax)  # out, stmt, curr
14727       e9/jump $emit-subx-stmt:end/disp32
14728     }
14729     # - otherwise emit a call
14730     # TODO: type-checking
14731 $emit-subx-stmt:call:
14732     (emit-call *(ebp+8) *(ebp+0xc))
14733 $emit-subx-stmt:end:
14734     # . restore registers
14735     59/pop-to-ecx
14736     58/pop-to-eax
14737     # . epilogue
14738     89/<- %esp 5/r32/ebp
14739     5d/pop-to-ebp
14740     c3/return
14741 
14742 translate-mu-length-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
14743     # . prologue
14744     55/push-ebp
14745     89/<- %ebp 4/r32/esp
14746     # . save registers
14747     50/push-eax
14748     51/push-ecx
14749     52/push-edx
14750     53/push-ebx
14751     56/push-esi
14752     # esi = stmt
14753     8b/-> *(ebp+0xc) 6/r32/esi
14754     # var base/ebx: (addr var) = stmt->inouts[0]->value
14755     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
14756     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14757     89/<- %ebx 0/r32/eax
14758     # var elemsize/ecx: int = array-element-size(base)
14759     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
14760     89/<- %ecx 0/r32/eax
14761     # var outreg/edx: (addr array byte) = stmt->outputs[0]->value->register
14762     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
14763     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14764     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
14765     89/<- %edx 0/r32/eax
14766     # if elemsize == 1
14767     {
14768       81 7/subop/compare %ecx 1/imm32
14769       75/jump-if-!= break/disp8
14770 $translate-mu-length-stmt:size-1:
14771       (emit-save-size-to *(ebp+8) %ebx %edx)
14772       e9/jump $translate-mu-length-stmt:end/disp32
14773     }
14774     # if elemsize is a power of 2 less than 256
14775     {
14776       (power-of-2? %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
14777       3d/compare-eax-and 0/imm32/false
14778       74/jump-if-= break/disp8
14779       81 7/subop/compare %ecx 0xff/imm32
14780       7f/jump-if-> break/disp8
14781 $translate-mu-length-stmt:size-power-of-2:
14782       (emit-save-size-to *(ebp+8) %ebx %edx)
14783       (emit-divide-by-shift-right *(ebp+8) %edx %ecx)
14784       e9/jump $translate-mu-length-stmt:end/disp32
14785     }
14786     # otherwise, the complex case
14787     # . emit register spills
14788     {
14789 $translate-mu-length-stmt:complex:
14790       (string-equal? %edx "eax")  # => eax
14791       3d/compare-eax-and 0/imm32/false
14792       75/break-if-!= break/disp8
14793       (emit-indent *(ebp+8) *Curr-block-depth)
14794       (write-buffered *(ebp+8) "50/push-eax\n")
14795     }
14796     {
14797       (string-equal? %edx "ecx")  # => eax
14798       3d/compare-eax-and 0/imm32/false
14799       75/break-if-!= break/disp8
14800       (emit-indent *(ebp+8) *Curr-block-depth)
14801       (write-buffered *(ebp+8) "51/push-ecx\n")
14802     }
14803     {
14804       (string-equal? %edx "edx")  # => eax
14805       3d/compare-eax-and 0/imm32/false
14806       75/break-if-!= break/disp8
14807       (emit-indent *(ebp+8) *Curr-block-depth)
14808       (write-buffered *(ebp+8) "52/push-edx\n")
14809     }
14810     # .
14811     (emit-save-size-to *(ebp+8) %ebx "eax")
14812     (emit-indent *(ebp+8) *Curr-block-depth)
14813     (write-buffered *(ebp+8) "31/xor %edx 2/r32/edx\n")
14814     (emit-indent *(ebp+8) *Curr-block-depth)
14815     (write-buffered *(ebp+8) "b9/copy-to-ecx ")
14816     (write-int32-hex-buffered *(ebp+8) %ecx)
14817     (write-buffered *(ebp+8) "/imm32\n")
14818     (emit-indent *(ebp+8) *Curr-block-depth)
14819     (write-buffered *(ebp+8) "f7 7/subop/idiv-eax-edx-by %ecx\n")
14820     {
14821       (string-equal? %edx "eax")  # => eax
14822       3d/compare-eax-and 0/imm32/false
14823       75/break-if-!= break/disp8
14824       (emit-indent *(ebp+8) *Curr-block-depth)
14825       (write-buffered *(ebp+8) "89/<- %")
14826       (write-buffered *(ebp+8) %edx)
14827       (write-buffered *(ebp+8) " 0/r32/eax\n")
14828     }
14829     # . emit register restores
14830     {
14831       (string-equal? %edx "edx")  # => eax
14832       3d/compare-eax-and 0/imm32/false
14833       75/break-if-!= break/disp8
14834       (emit-indent *(ebp+8) *Curr-block-depth)
14835       (write-buffered *(ebp+8) "5a/pop-to-edx\n")
14836     }
14837     {
14838       (string-equal? %edx "ecx")  # => eax
14839       3d/compare-eax-and 0/imm32/false
14840       75/break-if-!= break/disp8
14841       (emit-indent *(ebp+8) *Curr-block-depth)
14842       (write-buffered *(ebp+8) "59/pop-to-ecx\n")
14843     }
14844     {
14845       (string-equal? %edx "eax")  # => eax
14846       3d/compare-eax-and 0/imm32/false
14847       75/break-if-!= break/disp8
14848       (emit-indent *(ebp+8) *Curr-block-depth)
14849       (write-buffered *(ebp+8) "58/pop-to-eax\n")
14850     }
14851 $translate-mu-length-stmt:end:
14852     # . restore registers
14853     5e/pop-to-esi
14854     5b/pop-to-ebx
14855     5a/pop-to-edx
14856     59/pop-to-ecx
14857     58/pop-to-eax
14858     # . epilogue
14859     89/<- %esp 5/r32/ebp
14860     5d/pop-to-ebp
14861     c3/return
14862 
14863 array-element-size:  # arr: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
14864     # . prologue
14865     55/push-ebp
14866     89/<- %ebp 4/r32/esp
14867     #
14868     (array-element-type-id *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
14869     (size-of-type-id-as-array-element %eax)  # => eax
14870 $array-element-size:end:
14871     # . epilogue
14872     89/<- %esp 5/r32/ebp
14873     5d/pop-to-ebp
14874     c3/return
14875 
14876 array-element-type-id:  # v: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: type-id
14877     # precondition: n is positive
14878     # . prologue
14879     55/push-ebp
14880     89/<- %ebp 4/r32/esp
14881     #
14882     8b/-> *(ebp+8) 0/r32/eax
14883     # var t/eax: (addr type-tree)
14884     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
14885     # if t == 0 abort
14886     3d/compare-eax-with 0/imm32
14887     0f 84/jump-if-== $array-element-type-id:error0/disp32
14888     # if t->is-atom? abort
14889     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14890     0f 85/jump-if-!= $array-element-type-id:error1/disp32
14891     # if (t->left == addr) t = t->right
14892     {
14893       50/push-eax
14894       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14895       (is-simple-mu-type? %eax 2)  # addr => eax
14896       3d/compare-eax-with 0/imm32/false
14897       58/pop-to-eax
14898       74/jump-if-= break/disp8
14899 $array-element-type-id:skip-addr:
14900       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
14901     }
14902     # if t == 0 abort
14903     3d/compare-eax-with 0/imm32
14904     0f 84/jump-if-= $array-element-type-id:error2/disp32
14905     # if t->is-atom? abort
14906     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14907     0f 85/jump-if-!= $array-element-type-id:error2/disp32
14908     # if t->left != array abort
14909     {
14910       50/push-eax
14911       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14912       (is-simple-mu-type? %eax 3)  # array => eax
14913       3d/compare-eax-with 0/imm32/false
14914       58/pop-to-eax
14915 $array-element-type-id:no-array:
14916       0f 84/jump-if-= $array-element-type-id:error2/disp32
14917     }
14918 $array-element-type-id:skip-array:
14919     # t = t->right
14920     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
14921     # if t == 0 abort
14922     3d/compare-eax-with 0/imm32
14923     0f 84/jump-if-= $array-element-type-id:error2/disp32
14924     # if t->is-atom? abort
14925     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14926     0f 85/jump-if-!= $array-element-type-id:error2/disp32
14927     # return t->left->value
14928     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14929     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
14930 $array-element-type-id:end:
14931     # . epilogue
14932     89/<- %esp 5/r32/ebp
14933     5d/pop-to-ebp
14934     c3/return
14935 
14936 $array-element-type-id:error0:
14937     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
14938     50/push-eax
14939     8b/-> *(ebp+8) 0/r32/eax
14940     (lookup *eax *(eax+4))  # Var-name Var-name => eax
14941     (write-buffered *(ebp+0xc) %eax)
14942     58/pop-to-eax
14943     (write-buffered *(ebp+0xc) "' has no type\n")
14944     (flush *(ebp+0xc))
14945     (stop *(ebp+0x10) 1)
14946     # never gets here
14947 
14948 $array-element-type-id:error1:
14949     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
14950     50/push-eax
14951     8b/-> *(ebp+8) 0/r32/eax
14952     (lookup *eax *(eax+4))  # Var-name Var-name => eax
14953     (write-buffered *(ebp+0xc) %eax)
14954     58/pop-to-eax
14955     (write-buffered *(ebp+0xc) "' has atomic type ")
14956     (write-int32-hex-buffered *(ebp+0xc) *(eax+4))  # Type-tree-value
14957     (write-buffered *(ebp+0xc) Newline)
14958     (flush *(ebp+0xc))
14959     (stop *(ebp+0x10) 1)
14960     # never gets here
14961 
14962 $array-element-type-id:error2:
14963     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
14964     50/push-eax
14965     8b/-> *(ebp+8) 0/r32/eax
14966     (lookup *eax *(eax+4))  # Var-name Var-name => eax
14967     (write-buffered *(ebp+0xc) %eax)
14968     58/pop-to-eax
14969     (write-buffered *(ebp+0xc) "' has non-array type\n")
14970     (flush *(ebp+0xc))
14971     (stop *(ebp+0x10) 1)
14972     # never gets here
14973 
14974 size-of-type-id-as-array-element:  # t: type-id -> result/eax: int
14975     # . prologue
14976     55/push-ebp
14977     89/<- %ebp 4/r32/esp
14978     # eax = t
14979     8b/-> *(ebp+8) 0/r32/eax
14980     # if t is 'byte', size is 1
14981     3d/compare-eax-and 8/imm32/byte
14982     {
14983       75/jump-if-!= break/disp8
14984       b8/copy-to-eax 1/imm32
14985       eb/jump $size-of-type-id-as-array-element:end/disp8
14986     }
14987     # otherwise proceed as usual
14988     (size-of-type-id %eax)  # => eax
14989 $size-of-type-id-as-array-element:end:
14990     # . epilogue
14991     89/<- %esp 5/r32/ebp
14992     5d/pop-to-ebp
14993     c3/return
14994 
14995 emit-save-size-to:  # out: (addr buffered-file), base: (addr var), outreg: (addr array byte)
14996     # . prologue
14997     55/push-ebp
14998     89/<- %ebp 4/r32/esp
14999     # . save registers
15000     50/push-eax
15001     53/push-ebx
15002     # ebx = base
15003     8b/-> *(ebp+0xc) 3/r32/ebx
15004     (emit-indent *(ebp+8) *Curr-block-depth)
15005     (write-buffered *(ebp+8) "8b/-> *")
15006     # if base is an (addr array ...) in a register
15007     {
15008       81 7/subop/compare *(ebx+0x18)) 0/imm32  # Var-register
15009       74/jump-if-= break/disp8
15010 $emit-save-size-to:emit-base-from-register:
15011       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
15012       (write-buffered *(ebp+8) %eax)
15013       eb/jump $emit-save-size-to:emit-output/disp8
15014     }
15015     # otherwise if base is an (array ...) on the stack
15016     {
15017       81 7/subop/compare *(ebx+0x14)) 0/imm32  # Var-offset
15018       74/jump-if-= break/disp8
15019 $emit-save-size-to:emit-base-from-stack:
15020       (write-buffered *(ebp+8) "(ebp+")
15021       (write-int32-hex-buffered *(ebp+8) *(ebx+0x14))  # Var-offset
15022       (write-buffered *(ebp+8) ")")
15023     }
15024 $emit-save-size-to:emit-output:
15025     (write-buffered *(ebp+8) " ")
15026     (get Mu-registers *(ebp+0x10) 0xc "Mu-registers")  # => eax
15027     (write-int32-hex-buffered *(ebp+8) *eax)
15028     (write-buffered *(ebp+8) "/r32\n")
15029 $emit-save-size-to:end:
15030     # . restore registers
15031     5b/pop-to-ebx
15032     58/pop-to-eax
15033     # . epilogue
15034     89/<- %esp 5/r32/ebp
15035     5d/pop-to-ebp
15036     c3/return
15037 
15038 emit-divide-by-shift-right:  # out: (addr buffered-file), reg: (addr array byte), size: int
15039     # . prologue
15040     55/push-ebp
15041     89/<- %ebp 4/r32/esp
15042     # . save registers
15043     50/push-eax
15044     #
15045     (emit-indent *(ebp+8) *Curr-block-depth)
15046     (write-buffered *(ebp+8) "c1/shift 5/subop/>> %")
15047     (write-buffered *(ebp+8) *(ebp+0xc))
15048     (write-buffered *(ebp+8) Space)
15049     (num-shift-rights *(ebp+0x10))  # => eax
15050     (write-int32-hex-buffered *(ebp+8) %eax)
15051     (write-buffered *(ebp+8) "/imm8\n")
15052 $emit-divide-by-shift-right:end:
15053     # . restore registers
15054     58/pop-to-eax
15055     # . epilogue
15056     89/<- %esp 5/r32/ebp
15057     5d/pop-to-ebp
15058     c3/return
15059 
15060 translate-mu-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15061     # . prologue
15062     55/push-ebp
15063     89/<- %ebp 4/r32/esp
15064     # . save registers
15065     51/push-ecx
15066     # ecx = stmt
15067     8b/-> *(ebp+0xc) 1/r32/ecx
15068     # var base/ecx: (addr var) = stmt->inouts[0]
15069     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15070     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15071     89/<- %ecx 0/r32/eax
15072     # if (var->register) do one thing
15073     {
15074       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
15075       74/jump-if-= break/disp8
15076       # TODO: ensure there's no dereference
15077       (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
15078       eb/jump $translate-mu-index-stmt:end/disp8
15079     }
15080     # if (var->offset) do a different thing
15081     {
15082       81 7/subop/compare *(ecx+0x14) 0/imm32  # Var-offset
15083       74/jump-if-= break/disp8
15084       # TODO: ensure there's no dereference
15085       (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
15086       eb/jump $translate-mu-index-stmt:end/disp8
15087     }
15088 $translate-mu-index-stmt:end:
15089     # . restore registers
15090     59/pop-to-ecx
15091     # . epilogue
15092     89/<- %esp 5/r32/ebp
15093     5d/pop-to-ebp
15094     c3/return
15095 
15096 $translate-mu-index-stmt-with-array:error1:
15097     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
15098     (flush *(ebp+0x10))
15099     (stop *(ebp+0x14) 1)
15100     # never gets here
15101 
15102 $translate-mu-index-stmt-with-array:error2:
15103     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
15104     (flush *(ebp+0x10))
15105     (stop *(ebp+0x14) 1)
15106     # never gets here
15107 
15108 translate-mu-index-stmt-with-array-in-register:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15109     # . prologue
15110     55/push-ebp
15111     89/<- %ebp 4/r32/esp
15112     # . save registers
15113     50/push-eax
15114     51/push-ecx
15115     52/push-edx
15116     53/push-ebx
15117     #
15118     (emit-indent *(ebp+8) *Curr-block-depth)
15119     (write-buffered *(ebp+8) "8d/copy-address *(")
15120     # TODO: ensure inouts[0] is in a register and not dereferenced
15121 $translate-mu-index-stmt-with-array-in-register:emit-base:
15122     # ecx = stmt
15123     8b/-> *(ebp+0xc) 1/r32/ecx
15124     # var base/ebx: (addr var) = inouts[0]
15125     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15126     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15127     89/<- %ebx 0/r32/eax
15128     # print base->register " + "
15129     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
15130     (write-buffered *(ebp+8) %eax)
15131     (write-buffered *(ebp+8) " + ")
15132     # var index/edx: (addr var) = inouts[1]
15133     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15134     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
15135     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15136     89/<- %edx 0/r32/eax
15137     # if index->register
15138     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
15139     {
15140       0f 84/jump-if-= break/disp32
15141 $translate-mu-index-stmt-with-array-in-register:emit-register-index:
15142       # if index is an int
15143       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
15144       (is-simple-mu-type? %eax 1)  # int => eax
15145       3d/compare-eax-and 0/imm32/false
15146       {
15147         0f 84/jump-if-= break/disp32
15148 $translate-mu-index-stmt-with-array-in-register:emit-int-register-index:
15149         # print index->register "<<" log2(array-element-size(base)) " + 4) "
15150         # . index->register "<<"
15151         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
15152         (write-buffered *(ebp+8) %eax)
15153         (write-buffered *(ebp+8) "<<")
15154         # . log2(array-element-size(base->type))
15155         # TODO: ensure size is a power of 2
15156         (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
15157         (num-shift-rights %eax)  # => eax
15158         (write-int32-hex-buffered *(ebp+8) %eax)
15159         e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32
15160       }
15161       # if index->type is any other atom, abort
15162       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
15163       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
15164       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
15165       # if index has type (offset ...)
15166       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
15167       (is-simple-mu-type? %eax 7)  # => eax
15168       3d/compare-eax-and 0/imm32/false
15169       {
15170         0f 84/jump-if-= break/disp32
15171         # print index->register
15172 $translate-mu-index-stmt-with-array-in-register:emit-offset-register-index:
15173         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
15174         (write-buffered *(ebp+8) %eax)
15175       }
15176 $translate-mu-index-stmt-with-array-in-register:emit-register-index-done:
15177       (write-buffered *(ebp+8) " + 4) ")
15178       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
15179     }
15180     # otherwise if index is a literal
15181     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
15182     (is-simple-mu-type? %eax 0)  # => eax
15183     3d/compare-eax-and 0/imm32/false
15184     {
15185       0f 84/jump-if-= break/disp32
15186 $translate-mu-index-stmt-with-array-in-register:emit-literal-index:
15187       # var index-value/edx: int = parse-hex-int(index->name)
15188       (lookup *edx *(edx+4))  # Var-name Var-name => eax
15189       (parse-hex-int %eax)  # => eax
15190       89/<- %edx 0/r32/eax
15191       # offset = idx-value * array-element-size(base->type)
15192       (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
15193       f7 4/subop/multiply-into-eax %edx  # clobbers edx
15194       # offset += 4 for array size
15195       05/add-to-eax 4/imm32
15196       # TODO: check edx for overflow
15197       # print offset
15198       (write-int32-hex-buffered *(ebp+8) %eax)
15199       (write-buffered *(ebp+8) ") ")
15200       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
15201     }
15202     # otherwise abort
15203     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
15204 $translate-mu-index-stmt-with-array-in-register:emit-output:
15205     # outputs[0] "/r32"
15206     8b/-> *(ebp+0xc) 1/r32/ecx
15207     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
15208     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15209     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15210     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
15211     (write-int32-hex-buffered *(ebp+8) *eax)
15212     (write-buffered *(ebp+8) "/r32\n")
15213 $translate-mu-index-stmt-with-array-in-register:end:
15214     # . restore registers
15215     5b/pop-to-ebx
15216     5a/pop-to-edx
15217     59/pop-to-ecx
15218     58/pop-to-eax
15219     # . epilogue
15220     89/<- %esp 5/r32/ebp
15221     5d/pop-to-ebp
15222     c3/return
15223 
15224 translate-mu-index-stmt-with-array-on-stack:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15225     # . prologue
15226     55/push-ebp
15227     89/<- %ebp 4/r32/esp
15228     # . save registers
15229     50/push-eax
15230     51/push-ecx
15231     52/push-edx
15232     53/push-ebx
15233     #
15234     (emit-indent *(ebp+8) *Curr-block-depth)
15235     (write-buffered *(ebp+8) "8d/copy-address *(ebp + ")
15236     # var curr/edx: (addr stmt-var) = lookup(stmt->inouts)
15237     8b/-> *(ebp+0xc) 0/r32/eax
15238     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15239     89/<- %edx 0/r32/eax
15240     # var base/ecx: (addr var) = lookup(curr->value)
15241     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15242     89/<- %ecx 0/r32/eax
15243     # var curr2/eax: (addr stmt-var) = lookup(curr->next)
15244     (lookup *(edx+8) *(edx+0xc))  # Stmt-var-next Stmt-var-next => eax
15245     # var index/edx: (handle var) = curr2->value
15246     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15247     89/<- %edx 0/r32/eax
15248     # if index->register
15249     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
15250     {
15251       0f 84/jump-if-= break/disp32
15252 $translate-mu-index-stmt-with-array-on-stack:emit-register-index:
15253       # if index is an int
15254       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
15255       (is-simple-mu-type? %eax 1)  # int => eax
15256       3d/compare-eax-and 0/imm32/false
15257       {
15258         0f 84/jump-if-= break/disp32
15259 $translate-mu-index-stmt-with-array-on-stack:emit-int-register-index:
15260         # print index->register "<<" log2(array-element-size(base)) " + " base->offset+4
15261         # . inouts[1]->register "<<"
15262         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
15263         (write-buffered *(ebp+8) %eax)
15264         (write-buffered *(ebp+8) "<<")
15265         # . log2(array-element-size(base))
15266         # TODO: ensure size is a power of 2
15267         (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
15268         (num-shift-rights %eax)  # => eax
15269         (write-int32-hex-buffered *(ebp+8) %eax)
15270         #
15271         (write-buffered *(ebp+8) " + ")
15272         #
15273         8b/-> *(ecx+0x14) 0/r32/eax  # Var-offset
15274         05/add-to-eax 4/imm32  # for array length
15275         (write-int32-hex-buffered *(ebp+8) %eax)
15276         e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32
15277       }
15278       # if index->type is any other atom, abort
15279       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
15280       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
15281       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
15282       # if index has type (offset ...)
15283       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
15284       (is-simple-mu-type? %eax 7)  # => eax
15285       3d/compare-eax-and 0/imm32/false
15286       {
15287         0f 84/jump-if-= break/disp32
15288         # print index->register
15289 $translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index:
15290         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
15291         (write-buffered *(ebp+8) %eax)
15292       }
15293 $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done:
15294       (write-buffered *(ebp+8) ") ")
15295       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
15296     }
15297     # otherwise if index is a literal
15298     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
15299     (is-simple-mu-type? %eax 0)  # => eax
15300     3d/compare-eax-and 0/imm32/false
15301     {
15302       0f 84/jump-if-= break/disp32
15303 $translate-mu-index-stmt-with-array-on-stack:emit-literal-index:
15304       # var idx-value/edx: int = parse-hex-int(index->name)
15305       (lookup *edx *(edx+4))  # Var-name Var-name => eax
15306       (parse-hex-int %eax)  # Var-name => eax
15307       89/<- %edx 0/r32/eax
15308       # offset = idx-value * array-element-size(base)
15309       (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
15310       f7 4/subop/multiply-into-eax %edx  # clobbers edx
15311       # offset += base->offset
15312       03/add *(ecx+0x14) 0/r32/eax  # Var-offset
15313       # offset += 4 for array size
15314       05/add-to-eax 4/imm32
15315       # TODO: check edx for overflow
15316       # print offset
15317       (write-int32-hex-buffered *(ebp+8) %eax)
15318       (write-buffered *(ebp+8) ") ")
15319       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
15320     }
15321     # otherwise abort
15322     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
15323 $translate-mu-index-stmt-with-array-on-stack:emit-output:
15324     # outputs[0] "/r32"
15325     8b/-> *(ebp+0xc) 0/r32/eax
15326     (lookup *(eax+0x14) *(eax+0x18))  # Stmt1-outputs Stmt1-outputs => eax
15327     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15328     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15329     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
15330     (write-int32-hex-buffered *(ebp+8) *eax)
15331     (write-buffered *(ebp+8) "/r32\n")
15332 $translate-mu-index-stmt-with-array-on-stack:end:
15333     # . restore registers
15334     5b/pop-to-ebx
15335     5a/pop-to-edx
15336     59/pop-to-ecx
15337     58/pop-to-eax
15338     # . epilogue
15339     89/<- %esp 5/r32/ebp
15340     5d/pop-to-ebp
15341     c3/return
15342 
15343 translate-mu-compute-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15344     # . prologue
15345     55/push-ebp
15346     89/<- %ebp 4/r32/esp
15347     # . save registers
15348     50/push-eax
15349     51/push-ecx
15350     52/push-edx
15351     53/push-ebx
15352     #
15353     (emit-indent *(ebp+8) *Curr-block-depth)
15354     (write-buffered *(ebp+8) "69/multiply")
15355     # ecx = stmt
15356     8b/-> *(ebp+0xc) 1/r32/ecx
15357     # var first-inout/ebx: (addr stmt-var) = stmt->inouts[0]
15358     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15359     89/<- %ebx 0/r32/eax
15360 $translate-mu-compute-index-stmt:emit-index:
15361     (lookup *(ebx+8) *(ebx+0xc))  # Stmt-var-next Stmt-var-next => eax
15362     (emit-subx-var-as-rm32 *(ebp+8) %eax)
15363     (write-buffered *(ebp+8) Space)
15364 $translate-mu-compute-index-stmt:emit-elem-size:
15365     # var base/ebx: (addr var)
15366     (lookup *ebx *(ebx+4))  # Stmt-var-value Stmt-var-value => eax
15367     89/<- %ebx 0/r32/eax
15368     # print array-element-size(base)
15369     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
15370     (write-int32-hex-buffered *(ebp+8) %eax)
15371     (write-buffered *(ebp+8) "/imm32 ")
15372 $translate-mu-compute-index-stmt:emit-output:
15373     # outputs[0] "/r32"
15374     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
15375     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15376     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15377     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
15378     (write-int32-hex-buffered *(ebp+8) *eax)
15379     (write-buffered *(ebp+8) "/r32\n")
15380 $translate-mu-compute-index-stmt:end:
15381     # . restore registers
15382     5b/pop-to-ebx
15383     5a/pop-to-edx
15384     59/pop-to-ecx
15385     58/pop-to-eax
15386     # . epilogue
15387     89/<- %esp 5/r32/ebp
15388     5d/pop-to-ebp
15389     c3/return
15390 
15391 translate-mu-get-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
15392     # . prologue
15393     55/push-ebp
15394     89/<- %ebp 4/r32/esp
15395     # . save registers
15396     50/push-eax
15397     51/push-ecx
15398     52/push-edx
15399     #
15400     (emit-indent *(ebp+8) *Curr-block-depth)
15401     (write-buffered *(ebp+8) "8d/copy-address ")
15402     # ecx = stmt
15403     8b/-> *(ebp+0xc) 1/r32/ecx
15404     # var offset/edx: int = get offset of stmt
15405     (mu-get-offset %ecx)  # => eax
15406     89/<- %edx 0/r32/eax
15407     # var base/eax: (addr var) = stmt->inouts->value
15408     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15409     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15410     # if base is in a register
15411     81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
15412     {
15413       0f 84/jump-if-= break/disp32
15414 $translate-mu-get-stmt:emit-register-input:
15415       # emit "*(" base->register " + " offset ") "
15416       (write-buffered *(ebp+8) "*(")
15417       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15418       (write-buffered *(ebp+8) %eax)
15419       (write-buffered *(ebp+8) " + ")
15420       (write-int32-hex-buffered *(ebp+8) %edx)
15421       (write-buffered *(ebp+8) ") ")
15422       e9/jump $translate-mu-get-stmt:emit-output/disp32
15423     }
15424     # otherwise base is on the stack
15425     {
15426 $translate-mu-get-stmt:emit-stack-input:
15427       # emit "*(ebp + " inouts[0]->stack-offset + offset ") "
15428       (write-buffered *(ebp+8) "*(ebp+")
15429       03/add *(eax+0x14) 2/r32/edx  # Var-offset
15430       (write-int32-hex-buffered *(ebp+8) %edx)
15431       (write-buffered *(ebp+8) ") ")
15432       eb/jump $translate-mu-get-stmt:emit-output/disp8
15433     }
15434 $translate-mu-get-stmt:emit-output:
15435     # var output/eax: (addr var) = stmt->outputs->value
15436     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
15437     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15438     # emit offset->register "/r32"
15439     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15440     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
15441     (write-int32-hex-buffered *(ebp+8) *eax)
15442     (write-buffered *(ebp+8) "/r32\n")
15443 $translate-mu-get-stmt:end:
15444     # . restore registers
15445     5a/pop-to-edx
15446     59/pop-to-ecx
15447     58/pop-to-eax
15448     # . epilogue
15449     89/<- %esp 5/r32/ebp
15450     5d/pop-to-ebp
15451     c3/return
15452 
15453 translate-mu-allocate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15454     # . prologue
15455     55/push-ebp
15456     89/<- %ebp 4/r32/esp
15457     # . save registers
15458     50/push-eax
15459     56/push-esi
15460     57/push-edi
15461     # esi = stmt
15462     8b/-> *(ebp+0xc) 6/r32/esi
15463     # var target/edi: (addr stmt-var) = stmt->inouts[0]
15464     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15465     89/<- %edi 0/r32/eax
15466     #
15467     (emit-indent *(ebp+8) *Curr-block-depth)
15468     (write-buffered *(ebp+8) "(allocate Heap ")
15469     (addr-handle-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
15470     (write-int32-hex-buffered *(ebp+8) %eax)
15471     (emit-subx-call-operand *(ebp+8) %edi)
15472     (write-buffered *(ebp+8) ")\n")
15473 $translate-mu-allocate-stmt:end:
15474     # . restore registers
15475     5f/pop-to-edi
15476     5e/pop-to-esi
15477     58/pop-to-eax
15478     # . epilogue
15479     89/<- %esp 5/r32/ebp
15480     5d/pop-to-ebp
15481     c3/return
15482 
15483 addr-handle-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
15484     # . prologue
15485     55/push-ebp
15486     89/<- %ebp 4/r32/esp
15487     # var t/eax: (addr type-tree) = s->value->type
15488     8b/-> *(ebp+8) 0/r32/eax
15489     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15490     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
15491     # TODO: check eax != 0
15492     # TODO: check !t->is-atom?
15493     # TODO: check t->left == addr
15494     # t = t->right
15495 $addr-handle-payload-size:skip-addr:
15496     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15497     # TODO: check eax != 0
15498     # TODO: check !t->is-atom?
15499     # TODO: check t->left == handle
15500     # t = t->right
15501 $addr-handle-payload-size:skip-handle:
15502     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15503     # TODO: check eax != 0
15504     # if !t->is-atom? t = t->left
15505     81 7/subop/compare *eax 0/imm32/false
15506     {
15507       75/jump-if-!= break/disp8
15508       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
15509     }
15510     # TODO: check t->is-atom?
15511     # return size(t->value)
15512     (size-of-type-id *(eax+4))  # Type-tree-value => eax
15513 $addr-handle-payload-size:end:
15514     # . epilogue
15515     89/<- %esp 5/r32/ebp
15516     5d/pop-to-ebp
15517     c3/return
15518 
15519 addr-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
15520     # . prologue
15521     55/push-ebp
15522     89/<- %ebp 4/r32/esp
15523     # var t/eax: (addr type-tree) = s->value->type
15524     8b/-> *(ebp+8) 0/r32/eax
15525     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15526     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
15527     # TODO: check eax != 0
15528     # TODO: check !t->is-atom?
15529     # TODO: check t->left == addr
15530     # t = t->right
15531 $addr-payload-size:skip-addr:
15532     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15533     # TODO: check eax != 0
15534     # if !t->is-atom? t = t->left
15535     81 7/subop/compare *eax 0/imm32/false
15536     {
15537       75/jump-if-!= break/disp8
15538       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
15539     }
15540     # TODO: check t->is-atom?
15541     # return size(t->value)
15542     (size-of-type-id *(eax+4))  # Type-tree-value => eax
15543 $addr-payload-size:end:
15544     # . epilogue
15545     89/<- %esp 5/r32/ebp
15546     5d/pop-to-ebp
15547     c3/return
15548 
15549 translate-mu-populate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15550     # . prologue
15551     55/push-ebp
15552     89/<- %ebp 4/r32/esp
15553     # . save registers
15554     50/push-eax
15555     51/push-ecx
15556     56/push-esi
15557     57/push-edi
15558     # esi = stmt
15559     8b/-> *(ebp+0xc) 6/r32/esi
15560     # var target/edi: (addr stmt-var) = stmt->inouts[0]
15561     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15562     89/<- %edi 0/r32/eax
15563     # var len/ecx: (addr stmt-var) = stmt->inouts[1]
15564     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
15565     89/<- %ecx 0/r32/eax
15566     #
15567     (emit-indent *(ebp+8) *Curr-block-depth)
15568     (write-buffered *(ebp+8) "(allocate-array2 Heap ")
15569     (addr-handle-array-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
15570     (write-int32-hex-buffered *(ebp+8) %eax)
15571     (emit-subx-call-operand *(ebp+8) %ecx)
15572     (emit-subx-call-operand *(ebp+8) %edi)
15573     (write-buffered *(ebp+8) ")\n")
15574 $translate-mu-populate-stmt:end:
15575     # . restore registers
15576     5f/pop-to-edi
15577     5e/pop-to-esi
15578     59/pop-to-ecx
15579     58/pop-to-eax
15580     # . epilogue
15581     89/<- %esp 5/r32/ebp
15582     5d/pop-to-ebp
15583     c3/return
15584 
15585 translate-mu-populate-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15586     # . prologue
15587     55/push-ebp
15588     89/<- %ebp 4/r32/esp
15589     # . save registers
15590     50/push-eax
15591     51/push-ecx
15592     56/push-esi
15593     57/push-edi
15594     # esi = stmt
15595     8b/-> *(ebp+0xc) 6/r32/esi
15596     # var target/edi: (addr stmt-var) = stmt->inouts[0]
15597     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15598     89/<- %edi 0/r32/eax
15599     # var len/ecx: (addr stmt-var) = stmt->inouts[1]
15600     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
15601     89/<- %ecx 0/r32/eax
15602     #
15603     (emit-indent *(ebp+8) *Curr-block-depth)
15604     (write-buffered *(ebp+8) "(new-stream Heap ")
15605     (addr-handle-stream-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
15606     (write-int32-hex-buffered *(ebp+8) %eax)
15607     (emit-subx-call-operand *(ebp+8) %ecx)
15608     (emit-subx-call-operand *(ebp+8) %edi)
15609     (write-buffered *(ebp+8) ")\n")
15610 $translate-mu-populate-stream-stmt:end:
15611     # . restore registers
15612     5f/pop-to-edi
15613     5e/pop-to-esi
15614     59/pop-to-ecx
15615     58/pop-to-eax
15616     # . epilogue
15617     89/<- %esp 5/r32/ebp
15618     5d/pop-to-ebp
15619     c3/return
15620 
15621 translate-mu-read-from-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15622     # . prologue
15623     55/push-ebp
15624     89/<- %ebp 4/r32/esp
15625     # . save registers
15626     50/push-eax
15627     51/push-ecx
15628     56/push-esi
15629     57/push-edi
15630     # esi = stmt
15631     8b/-> *(ebp+0xc) 6/r32/esi
15632     # var stream/ecx: (addr stmt-var) = stmt->inouts[0]
15633     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15634     89/<- %ecx 0/r32/eax
15635     # var target/edi: (addr stmt-var) = stmt->inouts[1]
15636     (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
15637     89/<- %edi 0/r32/eax
15638     #
15639     (emit-indent *(ebp+8) *Curr-block-depth)
15640     (write-buffered *(ebp+8) "(read-from-stream")
15641     (emit-subx-call-operand *(ebp+8) %ecx)
15642     (emit-subx-call-operand *(ebp+8) %edi)
15643     (write-buffered *(ebp+8) Space)
15644     (addr-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
15645     (write-int32-hex-buffered *(ebp+8) %eax)
15646     (write-buffered *(ebp+8) ")\n")
15647 $translate-mu-read-from-stream-stmt:end:
15648     # . restore registers
15649     5f/pop-to-edi
15650     5e/pop-to-esi
15651     59/pop-to-ecx
15652     58/pop-to-eax
15653     # . epilogue
15654     89/<- %esp 5/r32/ebp
15655     5d/pop-to-ebp
15656     c3/return
15657 
15658 translate-mu-write-to-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15659     # . prologue
15660     55/push-ebp
15661     89/<- %ebp 4/r32/esp
15662     # . save registers
15663     50/push-eax
15664     51/push-ecx
15665     56/push-esi
15666     57/push-edi
15667     # esi = stmt
15668     8b/-> *(ebp+0xc) 6/r32/esi
15669     # var stream/ecx: (addr stmt-var) = stmt->inouts[0]
15670     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15671     89/<- %ecx 0/r32/eax
15672     # var target/edi: (addr stmt-var) = stmt->inouts[1]
15673     (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
15674     89/<- %edi 0/r32/eax
15675     #
15676     (emit-indent *(ebp+8) *Curr-block-depth)
15677     (write-buffered *(ebp+8) "(write-to-stream")
15678     (emit-subx-call-operand *(ebp+8) %ecx)
15679     (flush *(ebp+8))
15680     (emit-subx-call-operand *(ebp+8) %edi)
15681     (flush *(ebp+8))
15682     (write-buffered *(ebp+8) Space)
15683     (flush *(ebp+8))
15684     (addr-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
15685     (write-int32-hex-buffered *(ebp+8) %eax)
15686     (write-buffered *(ebp+8) ")\n")
15687 $translate-mu-write-to-stream-stmt:end:
15688     # . restore registers
15689     5f/pop-to-edi
15690     5e/pop-to-esi
15691     59/pop-to-ecx
15692     58/pop-to-eax
15693     # . epilogue
15694     89/<- %esp 5/r32/ebp
15695     5d/pop-to-ebp
15696     c3/return
15697 
15698 addr-handle-array-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
15699     # . prologue
15700     55/push-ebp
15701     89/<- %ebp 4/r32/esp
15702     # var t/eax: (addr type-tree) = s->value->type
15703     8b/-> *(ebp+8) 0/r32/eax
15704     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15705     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
15706     # TODO: check eax != 0
15707     # TODO: check !t->is-atom?
15708     # TODO: check t->left == addr
15709     # t = t->right
15710 $addr-handle-array-payload-size:skip-addr:
15711     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15712     # TODO: check eax != 0
15713     # TODO: check !t->is-atom?
15714     # TODO: check t->left == handle
15715     # t = t->right
15716 $addr-handle-array-payload-size:skip-handle:
15717     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15718     # TODO: check eax != 0
15719     # TODO: check !t->is-atom?
15720     # TODO: check t->left == array
15721     # t = t->right
15722 $addr-handle-array-payload-size:skip-array:
15723     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15724     # TODO: check eax != 0
15725     # if !t->is-atom? t = t->left
15726     81 7/subop/compare *eax 0/imm32/false
15727     {
15728       75/jump-if-!= break/disp8
15729       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
15730     }
15731 $addr-handle-array-payload-size:compute-size:
15732     # TODO: check t->is-atom?
15733     # return size(t->value)
15734     (size-of-type-id-as-array-element *(eax+4))  # Type-tree-value => eax
15735 $addr-handle-array-payload-size:end:
15736     # . epilogue
15737     89/<- %esp 5/r32/ebp
15738     5d/pop-to-ebp
15739     c3/return
15740 
15741 addr-handle-stream-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
15742     # . prologue
15743     55/push-ebp
15744     89/<- %ebp 4/r32/esp
15745     # var t/eax: (addr type-tree) = s->value->type
15746     8b/-> *(ebp+8) 0/r32/eax
15747     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15748     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
15749     # TODO: check eax != 0
15750     # TODO: check !t->is-atom?
15751     # TODO: check t->left == addr
15752     # t = t->right
15753 $addr-handle-stream-payload-size:skip-addr:
15754     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15755     # TODO: check eax != 0
15756     # TODO: check !t->is-atom?
15757     # TODO: check t->left == handle
15758     # t = t->right
15759 $addr-handle-stream-payload-size:skip-handle:
15760     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15761     # TODO: check eax != 0
15762     # TODO: check !t->is-atom?
15763     # TODO: check t->left == stream
15764     # t = t->right
15765 $addr-handle-stream-payload-size:skip-stream:
15766     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15767     # TODO: check eax != 0
15768     # if !t->is-atom? t = t->left
15769     81 7/subop/compare *eax 0/imm32/false
15770     {
15771       75/jump-if-!= break/disp8
15772       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
15773     }
15774 $addr-handle-stream-payload-size:compute-size:
15775     # TODO: check t->is-atom?
15776     # return size(t->value)
15777     (size-of-type-id-as-array-element *(eax+4))  # Type-tree-value => eax
15778 $addr-handle-stream-payload-size:end:
15779     # . epilogue
15780     89/<- %esp 5/r32/ebp
15781     5d/pop-to-ebp
15782     c3/return
15783 
15784 power-of-2?:  # n: int, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: boolean
15785     # precondition: n is positive
15786     # . prologue
15787     55/push-ebp
15788     89/<- %ebp 4/r32/esp
15789     # eax = n
15790     8b/-> *(ebp+8) 0/r32/eax
15791     # if (n < 0) abort
15792     3d/compare-eax-with 0/imm32
15793     0f 8c/jump-if-< $power-of-2?:abort/disp32
15794     # var tmp/eax: int = n-1
15795     48/decrement-eax
15796     # var tmp2/eax: int = n & tmp
15797     23/and-> *(ebp+8) 0/r32/eax
15798     # return (tmp2 == 0)
15799     3d/compare-eax-and 0/imm32
15800     0f 94/set-byte-if-= %al
15801     81 4/subop/and %eax 0xff/imm32
15802 $power-of-2?:end:
15803     # . epilogue
15804     89/<- %esp 5/r32/ebp
15805     5d/pop-to-ebp
15806     c3/return
15807 
15808 $power-of-2?:abort:
15809     (write-buffered *(ebp+0xc) "power-of-2?: negative number\n")
15810     (flush *(ebp+0xc))
15811     (stop *(ebp+0x10) 1)
15812     # never gets here
15813 
15814 num-shift-rights:  # n: int -> result/eax: int
15815     # precondition: n is a positive power of 2
15816     # . prologue
15817     55/push-ebp
15818     89/<- %ebp 4/r32/esp
15819     # . save registers
15820     51/push-ecx
15821     # var curr/ecx: int = n
15822     8b/-> *(ebp+8) 1/r32/ecx
15823     # result = 0
15824     b8/copy-to-eax 0/imm32
15825     {
15826       # if (curr <= 1) break
15827       81 7/subop/compare %ecx 1/imm32
15828       7e/jump-if-<= break/disp8
15829       40/increment-eax
15830       c1/shift 5/subop/arithmetic-right %ecx 1/imm8
15831       eb/jump loop/disp8
15832     }
15833 $num-shift-rights:end:
15834     # . restore registers
15835     59/pop-to-ecx
15836     # . epilogue
15837     89/<- %esp 5/r32/ebp
15838     5d/pop-to-ebp
15839     c3/return
15840 
15841 mu-get-offset:  # stmt: (addr stmt) -> result/eax: int
15842     # . prologue
15843     55/push-ebp
15844     89/<- %ebp 4/r32/esp
15845     # var second-inout/eax: (addr stmt-var) = stmt->inouts->next
15846     8b/-> *(ebp+8) 0/r32/eax
15847     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15848     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
15849     # var output-var/eax: (addr var) = second-inout->value
15850     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15851 #?     (write-buffered Stderr "mu-get-offset: ")
15852 #?     (write-int32-hex-buffered Stderr %eax)
15853 #?     (write-buffered Stderr " name: ")
15854 #?     50/push-eax
15855 #?     (lookup *eax *(eax+4))  # Var-name
15856 #?     (write-buffered Stderr %eax)
15857 #?     58/pop-to-eax
15858 #?     (write-buffered Stderr Newline)
15859 #?     (flush Stderr)
15860     # return output-var->stack-offset
15861     8b/-> *(eax+0x14) 0/r32/eax  # Var-offset
15862 #?     (write-buffered Stderr "=> ")
15863 #?     (write-int32-hex-buffered Stderr %eax)
15864 #?     (write-buffered Stderr Newline)
15865 #?     (flush Stderr)
15866 $emit-get-offset:end:
15867     # . epilogue
15868     89/<- %esp 5/r32/ebp
15869     5d/pop-to-ebp
15870     c3/return
15871 
15872 emit-subx-block:  # out: (addr buffered-file), block: (addr block), vars: (addr stack live-var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
15873     # . prologue
15874     55/push-ebp
15875     89/<- %ebp 4/r32/esp
15876     # . save registers
15877     50/push-eax
15878     51/push-ecx
15879     56/push-esi
15880     # esi = block
15881     8b/-> *(ebp+0xc) 6/r32/esi
15882     # block->var->block-depth = *Curr-block-depth
15883     (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
15884     8b/-> *Curr-block-depth 1/r32/ecx
15885     89/<- *(eax+0x10) 1/r32/ecx  # Var-block-depth
15886     # var stmts/eax: (addr list stmt) = lookup(block->statements)
15887     (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
15888     #
15889     {
15890 $emit-subx-block:check-empty:
15891       3d/compare-eax-and 0/imm32
15892       0f 84/jump-if-= break/disp32
15893       (emit-indent *(ebp+8) *Curr-block-depth)
15894       (write-buffered *(ebp+8) "{\n")
15895       # var v/ecx: (addr var) = lookup(block->var)
15896       (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
15897       89/<- %ecx 0/r32/eax
15898       #
15899       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
15900       (write-buffered *(ebp+8) %eax)
15901       (write-buffered *(ebp+8) ":loop:\n")
15902       ff 0/subop/increment *Curr-block-depth
15903       (push *(ebp+0x10) *(esi+0xc))  # Block-var
15904       (push *(ebp+0x10) *(esi+0x10))  # Block-var
15905       (push *(ebp+0x10) 0)  # false
15906       # emit block->statements
15907       (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
15908       (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
15909       (pop *(ebp+0x10))  # => eax
15910       (pop *(ebp+0x10))  # => eax
15911       (pop *(ebp+0x10))  # => eax
15912       ff 1/subop/decrement *Curr-block-depth
15913       (emit-indent *(ebp+8) *Curr-block-depth)
15914       (write-buffered *(ebp+8) "}\n")
15915       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
15916       (write-buffered *(ebp+8) %eax)
15917       (write-buffered *(ebp+8) ":break:\n")
15918     }
15919 $emit-subx-block:end:
15920     # . restore registers
15921     5e/pop-to-esi
15922     59/pop-to-ecx
15923     58/pop-to-eax
15924     # . epilogue
15925     89/<- %esp 5/r32/ebp
15926     5d/pop-to-ebp
15927     c3/return
15928 
15929 # Primitives supported
15930 # See mu_instructions for a summary of this linked-list data structure.
15931 #
15932 # For each operation, put variants with hard-coded registers before flexible ones.
15933 #
15934 # Unfortunately, our restrictions on addresses require that various fields in
15935 # primitives be handles, which complicates these definitions.
15936 #   - we need to insert dummy fields all over the place for fake alloc-ids
15937 #   - we can't use our syntax sugar of quoted literals for string fields
15938 #
15939 # Fake alloc-ids are needed because our type definitions up top require
15940 # handles but it's clearer to statically allocate these long-lived objects.
15941 # Fake alloc-ids are perfectly safe, but they can't be reclaimed.
15942 #
15943 # Every 'object' below starts with a fake alloc-id. It may also contain other
15944 # fake alloc-ids for various handle fields.
15945 #
15946 # I think of objects starting with a fake alloc-id as having type 'payload'.
15947 # It's not really intended to be created dynamically; for that use `allocate`
15948 # as usual.
15949 #
15950 # Idea for a notation to simplify such definitions:
15951 #   _Primitive-increment-eax:  # (payload primitive)
15952 #     0x11/alloc-id:fake:payload
15953 #     0x11 @(0x11 "increment")  # name
15954 #     0 0                       # inouts
15955 #     0x11 @(0x11/payload
15956 #            0x11 @(0x11/payload  # List-value
15957 #                   0 0             # Var-name
15958 #                   0x11 @(0x11     # Var-type
15959 #                          1/is-atom
15960 #                          1/value 0/unused   # Type-tree-left
15961 #                          0 0                # Type-tree-right
15962 #                         )
15963 #                   1               # block-depth
15964 #                   0               # stack-offset
15965 #                   0x11 @(0x11 "eax")  # Var-register
15966 #                  )
15967 #            0 0)                 # List-next
15968 #     ...
15969 #     _Primitive-increment-ecx/imm32/next
15970 #   ...
15971 # Awfully complex and non-obvious. But also clearly signals there's something
15972 # to learn here, so may be worth trying.
15973 #
15974 # '@' is just an initial thought. Punctuation used so far in Mu: () * % # / "
15975 #
15976 # For now we'll continue to just use comments and manually ensure they stay up
15977 # to date.
15978 == data
15979 Primitives:  # (addr primitive)
15980 # - increment/decrement
15981 _Primitive-increment-eax:  # (addr primitive)
15982     # var/eax <- increment => 40/increment-eax
15983     0x11/imm32/alloc-id:fake
15984     _string-increment/imm32/name
15985     0/imm32/no-inouts
15986     0/imm32/no-inouts
15987     0x11/imm32/alloc-id:fake
15988     Single-int-var-in-eax/imm32/outputs
15989     0x11/imm32/alloc-id:fake
15990     _string_40_increment_eax/imm32/subx-name
15991     0/imm32/no-rm32
15992     0/imm32/no-r32
15993     0/imm32/no-imm32
15994     0/imm32/no-imm8
15995     0/imm32/no-disp32
15996     0/imm32/output-is-write-only
15997     0x11/imm32/alloc-id:fake
15998     _Primitive-increment-ecx/imm32/next
15999 _Primitive-increment-ecx:  # (payload primitive)
16000     0x11/imm32/alloc-id:fake:payload
16001     # var/ecx <- increment => 41/increment-ecx
16002     0x11/imm32/alloc-id:fake
16003     _string-increment/imm32/name
16004     0/imm32/no-inouts
16005     0/imm32/no-inouts
16006     0x11/imm32/alloc-id:fake
16007     Single-int-var-in-ecx/imm32/outputs
16008     0x11/imm32/alloc-id:fake
16009     _string_41_increment_ecx/imm32/subx-name
16010     0/imm32/no-rm32
16011     0/imm32/no-r32
16012     0/imm32/no-imm32
16013     0/imm32/no-imm8
16014     0/imm32/no-disp32
16015     0/imm32/output-is-write-only
16016     0x11/imm32/alloc-id:fake
16017     _Primitive-increment-edx/imm32/next
16018 _Primitive-increment-edx:  # (payload primitive)
16019     0x11/imm32/alloc-id:fake:payload
16020     # var/edx <- increment => 42/increment-edx
16021     0x11/imm32/alloc-id:fake
16022     _string-increment/imm32/name
16023     0/imm32/no-inouts
16024     0/imm32/no-inouts
16025     0x11/imm32/alloc-id:fake
16026     Single-int-var-in-edx/imm32/outputs
16027     0x11/imm32/alloc-id:fake
16028     _string_42_increment_edx/imm32/subx-name
16029     0/imm32/no-rm32
16030     0/imm32/no-r32
16031     0/imm32/no-imm32
16032     0/imm32/no-imm8
16033     0/imm32/no-disp32
16034     0/imm32/output-is-write-only
16035     0x11/imm32/alloc-id:fake
16036     _Primitive-increment-ebx/imm32/next
16037 _Primitive-increment-ebx:  # (payload primitive)
16038     0x11/imm32/alloc-id:fake:payload
16039     # var/ebx <- increment => 43/increment-ebx
16040     0x11/imm32/alloc-id:fake
16041     _string-increment/imm32/name
16042     0/imm32/no-inouts
16043     0/imm32/no-inouts
16044     0x11/imm32/alloc-id:fake
16045     Single-int-var-in-ebx/imm32/outputs
16046     0x11/imm32/alloc-id:fake
16047     _string_43_increment_ebx/imm32/subx-name
16048     0/imm32/no-rm32
16049     0/imm32/no-r32
16050     0/imm32/no-imm32
16051     0/imm32/no-imm8
16052     0/imm32/no-disp32
16053     0/imm32/output-is-write-only
16054     0x11/imm32/alloc-id:fake
16055     _Primitive-increment-esi/imm32/next
16056 _Primitive-increment-esi:  # (payload primitive)
16057     0x11/imm32/alloc-id:fake:payload
16058     # var/esi <- increment => 46/increment-esi
16059     0x11/imm32/alloc-id:fake
16060     _string-increment/imm32/name
16061     0/imm32/no-inouts
16062     0/imm32/no-inouts
16063     0x11/imm32/alloc-id:fake
16064     Single-int-var-in-esi/imm32/outputs
16065     0x11/imm32/alloc-id:fake
16066     _string_46_increment_esi/imm32/subx-name
16067     0/imm32/no-rm32
16068     0/imm32/no-r32
16069     0/imm32/no-imm32
16070     0/imm32/no-imm8
16071     0/imm32/no-disp32
16072     0/imm32/output-is-write-only
16073     0x11/imm32/alloc-id:fake
16074     _Primitive-increment-edi/imm32/next
16075 _Primitive-increment-edi:  # (payload primitive)
16076     0x11/imm32/alloc-id:fake:payload
16077     # var/edi <- increment => 47/increment-edi
16078     0x11/imm32/alloc-id:fake
16079     _string-increment/imm32/name
16080     0/imm32/no-inouts
16081     0/imm32/no-inouts
16082     0x11/imm32/alloc-id:fake
16083     Single-int-var-in-edi/imm32/outputs
16084     0x11/imm32/alloc-id:fake
16085     _string_47_increment_edi/imm32/subx-name
16086     0/imm32/no-rm32
16087     0/imm32/no-r32
16088     0/imm32/no-imm32
16089     0/imm32/no-imm8
16090     0/imm32/no-disp32
16091     0/imm32/output-is-write-only
16092     0x11/imm32/alloc-id:fake
16093     _Primitive-decrement-eax/imm32/next
16094 _Primitive-decrement-eax:  # (payload primitive)
16095     0x11/imm32/alloc-id:fake:payload
16096     # var/eax <- decrement => 48/decrement-eax
16097     0x11/imm32/alloc-id:fake
16098     _string-decrement/imm32/name
16099     0/imm32/no-inouts
16100     0/imm32/no-inouts
16101     0x11/imm32/alloc-id:fake
16102     Single-int-var-in-eax/imm32/outputs
16103     0x11/imm32/alloc-id:fake
16104     _string_48_decrement_eax/imm32/subx-name
16105     0/imm32/no-rm32
16106     0/imm32/no-r32
16107     0/imm32/no-imm32
16108     0/imm32/no-imm8
16109     0/imm32/no-disp32
16110     0/imm32/output-is-write-only
16111     0x11/imm32/alloc-id:fake
16112     _Primitive-decrement-ecx/imm32/next
16113 _Primitive-decrement-ecx:  # (payload primitive)
16114     0x11/imm32/alloc-id:fake:payload
16115     # var/ecx <- decrement => 49/decrement-ecx
16116     0x11/imm32/alloc-id:fake
16117     _string-decrement/imm32/name
16118     0/imm32/no-inouts
16119     0/imm32/no-inouts
16120     0x11/imm32/alloc-id:fake
16121     Single-int-var-in-ecx/imm32/outputs
16122     0x11/imm32/alloc-id:fake
16123     _string_49_decrement_ecx/imm32/subx-name
16124     0/imm32/no-rm32
16125     0/imm32/no-r32
16126     0/imm32/no-imm32
16127     0/imm32/no-imm8
16128     0/imm32/no-disp32
16129     0/imm32/output-is-write-only
16130     0x11/imm32/alloc-id:fake
16131     _Primitive-decrement-edx/imm32/next
16132 _Primitive-decrement-edx:  # (payload primitive)
16133     0x11/imm32/alloc-id:fake:payload
16134     # var/edx <- decrement => 4a/decrement-edx
16135     0x11/imm32/alloc-id:fake
16136     _string-decrement/imm32/name
16137     0/imm32/no-inouts
16138     0/imm32/no-inouts
16139     0x11/imm32/alloc-id:fake
16140     Single-int-var-in-edx/imm32/outputs
16141     0x11/imm32/alloc-id:fake
16142     _string_4a_decrement_edx/imm32/subx-name
16143     0/imm32/no-rm32
16144     0/imm32/no-r32
16145     0/imm32/no-imm32
16146     0/imm32/no-imm8
16147     0/imm32/no-disp32
16148     0/imm32/output-is-write-only
16149     0x11/imm32/alloc-id:fake
16150     _Primitive-decrement-ebx/imm32/next
16151 _Primitive-decrement-ebx:  # (payload primitive)
16152     0x11/imm32/alloc-id:fake:payload
16153     # var/ebx <- decrement => 4b/decrement-ebx
16154     0x11/imm32/alloc-id:fake
16155     _string-decrement/imm32/name
16156     0/imm32/no-inouts
16157     0/imm32/no-inouts
16158     0x11/imm32/alloc-id:fake
16159     Single-int-var-in-ebx/imm32/outputs
16160     0x11/imm32/alloc-id:fake
16161     _string_4b_decrement_ebx/imm32/subx-name
16162     0/imm32/no-rm32
16163     0/imm32/no-r32
16164     0/imm32/no-imm32
16165     0/imm32/no-imm8
16166     0/imm32/no-disp32
16167     0/imm32/output-is-write-only
16168     0x11/imm32/alloc-id:fake
16169     _Primitive-decrement-esi/imm32/next
16170 _Primitive-decrement-esi:  # (payload primitive)
16171     0x11/imm32/alloc-id:fake:payload
16172     # var/esi <- decrement => 4e/decrement-esi
16173     0x11/imm32/alloc-id:fake
16174     _string-decrement/imm32/name
16175     0/imm32/no-inouts
16176     0/imm32/no-inouts
16177     0x11/imm32/alloc-id:fake
16178     Single-int-var-in-esi/imm32/outputs
16179     0x11/imm32/alloc-id:fake
16180     _string_4e_decrement_esi/imm32/subx-name
16181     0/imm32/no-rm32
16182     0/imm32/no-r32
16183     0/imm32/no-imm32
16184     0/imm32/no-imm8
16185     0/imm32/no-disp32
16186     0/imm32/output-is-write-only
16187     0x11/imm32/alloc-id:fake
16188     _Primitive-decrement-edi/imm32/next
16189 _Primitive-decrement-edi:  # (payload primitive)
16190     0x11/imm32/alloc-id:fake:payload
16191     # var/edi <- decrement => 4f/decrement-edi
16192     0x11/imm32/alloc-id:fake
16193     _string-decrement/imm32/name
16194     0/imm32/no-inouts
16195     0/imm32/no-inouts
16196     0x11/imm32/alloc-id:fake
16197     Single-int-var-in-edi/imm32/outputs
16198     0x11/imm32/alloc-id:fake
16199     _string_4f_decrement_edi/imm32/subx-name
16200     0/imm32/no-rm32
16201     0/imm32/no-r32
16202     0/imm32/no-imm32
16203     0/imm32/no-imm8
16204     0/imm32/no-disp32
16205     0/imm32/output-is-write-only
16206     0x11/imm32/alloc-id:fake
16207     _Primitive-increment-mem/imm32/next
16208 _Primitive-increment-mem:  # (payload primitive)
16209     0x11/imm32/alloc-id:fake:payload
16210     # increment var => ff 0/subop/increment *(ebp+__)
16211     0x11/imm32/alloc-id:fake
16212     _string-increment/imm32/name
16213     0x11/imm32/alloc-id:fake
16214     Single-int-var-in-mem/imm32/inouts
16215     0/imm32/no-outputs
16216     0/imm32/no-outputs
16217     0x11/imm32/alloc-id:fake
16218     _string_ff_subop_increment/imm32/subx-name
16219     1/imm32/rm32-is-first-inout
16220     0/imm32/no-r32
16221     0/imm32/no-imm32
16222     0/imm32/no-imm8
16223     0/imm32/no-disp32
16224     0/imm32/output-is-write-only
16225     0x11/imm32/alloc-id:fake
16226     _Primitive-increment-reg/imm32/next
16227 _Primitive-increment-reg:  # (payload primitive)
16228     0x11/imm32/alloc-id:fake:payload
16229     # var/reg <- increment => ff 0/subop/increment %__
16230     0x11/imm32/alloc-id:fake
16231     _string-increment/imm32/name
16232     0/imm32/no-inouts
16233     0/imm32/no-inouts
16234     0x11/imm32/alloc-id:fake
16235     Single-int-var-in-some-register/imm32/outputs
16236     0x11/imm32/alloc-id:fake
16237     _string_ff_subop_increment/imm32/subx-name
16238     3/imm32/rm32-is-first-output
16239     0/imm32/no-r32
16240     0/imm32/no-imm32
16241     0/imm32/no-imm8
16242     0/imm32/no-disp32
16243     0/imm32/output-is-write-only
16244     0x11/imm32/alloc-id:fake
16245     _Primitive-decrement-mem/imm32/next
16246 _Primitive-decrement-mem:  # (payload primitive)
16247     0x11/imm32/alloc-id:fake:payload
16248     # decrement var => ff 1/subop/decrement *(ebp+__)
16249     0x11/imm32/alloc-id:fake
16250     _string-decrement/imm32/name
16251     0x11/imm32/alloc-id:fake
16252     Single-int-var-in-mem/imm32/inouts
16253     0/imm32/no-outputs
16254     0/imm32/no-outputs
16255     0x11/imm32/alloc-id:fake
16256     _string_ff_subop_decrement/imm32/subx-name
16257     1/imm32/rm32-is-first-inout
16258     0/imm32/no-r32
16259     0/imm32/no-imm32
16260     0/imm32/no-imm8
16261     0/imm32/no-disp32
16262     0/imm32/output-is-write-only
16263     0x11/imm32/alloc-id:fake
16264     _Primitive-decrement-reg/imm32/next
16265 _Primitive-decrement-reg:  # (payload primitive)
16266     0x11/imm32/alloc-id:fake:payload
16267     # var/reg <- decrement => ff 1/subop/decrement %__
16268     0x11/imm32/alloc-id:fake
16269     _string-decrement/imm32/name
16270     0/imm32/no-inouts
16271     0/imm32/no-inouts
16272     0x11/imm32/alloc-id:fake
16273     Single-int-var-in-some-register/imm32/outputs
16274     0x11/imm32/alloc-id:fake
16275     _string_ff_subop_decrement/imm32/subx-name
16276     3/imm32/rm32-is-first-output
16277     0/imm32/no-r32
16278     0/imm32/no-imm32
16279     0/imm32/no-imm8
16280     0/imm32/no-disp32
16281     0/imm32/output-is-write-only
16282     0x11/imm32/alloc-id:fake
16283     _Primitive-add-to-eax/imm32/next
16284 # - add
16285 _Primitive-add-to-eax:  # (payload primitive)
16286     0x11/imm32/alloc-id:fake:payload
16287     # var/eax <- add lit => 05/add-to-eax lit/imm32
16288     0x11/imm32/alloc-id:fake
16289     _string-add/imm32/name
16290     0x11/imm32/alloc-id:fake
16291     Single-lit-var/imm32/inouts
16292     0x11/imm32/alloc-id:fake
16293     Single-int-var-in-eax/imm32/outputs
16294     0x11/imm32/alloc-id:fake
16295     _string_05_add_to_eax/imm32/subx-name
16296     0/imm32/no-rm32
16297     0/imm32/no-r32
16298     1/imm32/imm32-is-first-inout
16299     0/imm32/no-imm8
16300     0/imm32/no-disp32
16301     0/imm32/output-is-write-only
16302     0x11/imm32/alloc-id:fake
16303     _Primitive-add-reg-to-reg/imm32/next
16304 _Primitive-add-reg-to-reg:  # (payload primitive)
16305     0x11/imm32/alloc-id:fake:payload
16306     # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32
16307     0x11/imm32/alloc-id:fake
16308     _string-add/imm32/name
16309     0x11/imm32/alloc-id:fake
16310     Single-int-var-in-some-register/imm32/inouts
16311     0x11/imm32/alloc-id:fake
16312     Single-int-var-in-some-register/imm32/outputs
16313     0x11/imm32/alloc-id:fake
16314     _string_01_add_to/imm32/subx-name
16315     3/imm32/rm32-is-first-output
16316     1/imm32/r32-is-first-inout
16317     0/imm32/no-imm32
16318     0/imm32/no-imm8
16319     0/imm32/no-disp32
16320     0/imm32/output-is-write-only
16321     0x11/imm32/alloc-id:fake
16322     _Primitive-add-reg-to-mem/imm32/next
16323 _Primitive-add-reg-to-mem:  # (payload primitive)
16324     0x11/imm32/alloc-id:fake:payload
16325     # add-to var1 var2/reg => 01/add-to var1 var2/r32
16326     0x11/imm32/alloc-id:fake
16327     _string-add-to/imm32/name
16328     0x11/imm32/alloc-id:fake
16329     Two-args-int-stack-int-reg/imm32/inouts
16330     0/imm32/no-outputs
16331     0/imm32/no-outputs
16332     0x11/imm32/alloc-id:fake
16333     _string_01_add_to/imm32/subx-name
16334     1/imm32/rm32-is-first-inout
16335     2/imm32/r32-is-second-inout
16336     0/imm32/no-imm32
16337     0/imm32/no-imm8
16338     0/imm32/no-disp32
16339     0/imm32/output-is-write-only
16340     0x11/imm32/alloc-id:fake
16341     _Primitive-add-mem-to-reg/imm32/next
16342 _Primitive-add-mem-to-reg:  # (payload primitive)
16343     0x11/imm32/alloc-id:fake:payload
16344     # var1/reg <- add var2 => 03/add var2/rm32 var1/r32
16345     0x11/imm32/alloc-id:fake
16346     _string-add/imm32/name
16347     0x11/imm32/alloc-id:fake
16348     Single-int-var-in-mem/imm32/inouts
16349     0x11/imm32/alloc-id:fake
16350     Single-int-var-in-some-register/imm32/outputs
16351     0x11/imm32/alloc-id:fake
16352     _string_03_add/imm32/subx-name
16353     1/imm32/rm32-is-first-inout
16354     3/imm32/r32-is-first-output
16355     0/imm32/no-imm32
16356     0/imm32/no-imm8
16357     0/imm32/no-disp32
16358     0/imm32/output-is-write-only
16359     0x11/imm32/alloc-id:fake
16360     _Primitive-add-lit-to-reg/imm32/next
16361 _Primitive-add-lit-to-reg:  # (payload primitive)
16362     0x11/imm32/alloc-id:fake:payload
16363     # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32
16364     0x11/imm32/alloc-id:fake
16365     _string-add/imm32/name
16366     0x11/imm32/alloc-id:fake
16367     Single-lit-var/imm32/inouts
16368     0x11/imm32/alloc-id:fake
16369     Single-int-var-in-some-register/imm32/outputs
16370     0x11/imm32/alloc-id:fake
16371     _string_81_subop_add/imm32/subx-name
16372     3/imm32/rm32-is-first-output
16373     0/imm32/no-r32
16374     1/imm32/imm32-is-first-inout
16375     0/imm32/no-imm8
16376     0/imm32/no-disp32
16377     0/imm32/output-is-write-only
16378     0x11/imm32/alloc-id:fake
16379     _Primitive-add-lit-to-mem/imm32/next
16380 _Primitive-add-lit-to-mem:  # (payload primitive)
16381     0x11/imm32/alloc-id:fake:payload
16382     # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32
16383     0x11/imm32/alloc-id:fake
16384     _string-add-to/imm32/name
16385     0x11/imm32/alloc-id:fake
16386     Int-var-and-literal/imm32/inouts
16387     0/imm32/no-outputs
16388     0/imm32/no-outputs
16389     0x11/imm32/alloc-id:fake
16390     _string_81_subop_add/imm32/subx-name
16391     1/imm32/rm32-is-first-inout
16392     0/imm32/no-r32
16393     2/imm32/imm32-is-second-inout
16394     0/imm32/no-imm8
16395     0/imm32/no-disp32
16396     0/imm32/output-is-write-only
16397     0x11/imm32/alloc-id:fake
16398     _Primitive-subtract-from-eax/imm32/next
16399 # - subtract
16400 _Primitive-subtract-from-eax:  # (payload primitive)
16401     0x11/imm32/alloc-id:fake:payload
16402     # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32
16403     0x11/imm32/alloc-id:fake
16404     _string-subtract/imm32/name
16405     0x11/imm32/alloc-id:fake
16406     Single-lit-var/imm32/inouts
16407     0x11/imm32/alloc-id:fake
16408     Single-int-var-in-eax/imm32/outputs
16409     0x11/imm32/alloc-id:fake
16410     _string_2d_subtract_from_eax/imm32/subx-name
16411     0/imm32/no-rm32
16412     0/imm32/no-r32
16413     1/imm32/imm32-is-first-inout
16414     0/imm32/no-imm8
16415     0/imm32/no-disp32
16416     0/imm32/output-is-write-only
16417     0x11/imm32/alloc-id:fake
16418     _Primitive-subtract-reg-from-reg/imm32/next
16419 _Primitive-subtract-reg-from-reg:  # (payload primitive)
16420     0x11/imm32/alloc-id:fake:payload
16421     # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32
16422     0x11/imm32/alloc-id:fake
16423     _string-subtract/imm32/name
16424     0x11/imm32/alloc-id:fake
16425     Single-int-var-in-some-register/imm32/inouts
16426     0x11/imm32/alloc-id:fake
16427     Single-int-var-in-some-register/imm32/outputs
16428     0x11/imm32/alloc-id:fake
16429     _string_29_subtract_from/imm32/subx-name
16430     3/imm32/rm32-is-first-output
16431     1/imm32/r32-is-first-inout
16432     0/imm32/no-imm32
16433     0/imm32/no-imm8
16434     0/imm32/no-disp32
16435     0/imm32/output-is-write-only
16436     0x11/imm32/alloc-id:fake
16437     _Primitive-subtract-reg-from-mem/imm32/next
16438 _Primitive-subtract-reg-from-mem:  # (payload primitive)
16439     0x11/imm32/alloc-id:fake:payload
16440     # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32
16441     0x11/imm32/alloc-id:fake
16442     _string-subtract-from/imm32/name
16443     0x11/imm32/alloc-id:fake
16444     Two-args-int-stack-int-reg/imm32/inouts
16445     0/imm32/no-outputs
16446     0/imm32/no-outputs
16447     0x11/imm32/alloc-id:fake
16448     _string_29_subtract_from/imm32/subx-name
16449     1/imm32/rm32-is-first-inout
16450     2/imm32/r32-is-second-inout
16451     0/imm32/no-imm32
16452     0/imm32/no-imm8
16453     0/imm32/no-disp32
16454     0/imm32/output-is-write-only
16455     0x11/imm32/alloc-id:fake
16456     _Primitive-subtract-mem-from-reg/imm32/next
16457 _Primitive-subtract-mem-from-reg:  # (payload primitive)
16458     0x11/imm32/alloc-id:fake:payload
16459     # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32
16460     0x11/imm32/alloc-id:fake
16461     _string-subtract/imm32/name
16462     0x11/imm32/alloc-id:fake
16463     Single-int-var-in-mem/imm32/inouts
16464     0x11/imm32/alloc-id:fake
16465     Single-int-var-in-some-register/imm32/outputs
16466     0x11/imm32/alloc-id:fake
16467     _string_2b_subtract/imm32/subx-name
16468     1/imm32/rm32-is-first-inout
16469     3/imm32/r32-is-first-output
16470     0/imm32/no-imm32
16471     0/imm32/no-imm8
16472     0/imm32/no-disp32
16473     0/imm32/output-is-write-only
16474     0x11/imm32/alloc-id:fake
16475     _Primitive-subtract-lit-from-reg/imm32/next
16476 _Primitive-subtract-lit-from-reg:  # (payload primitive)
16477     0x11/imm32/alloc-id:fake:payload
16478     # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32
16479     0x11/imm32/alloc-id:fake
16480     _string-subtract/imm32/name
16481     0x11/imm32/alloc-id:fake
16482     Single-lit-var/imm32/inouts
16483     0x11/imm32/alloc-id:fake
16484     Single-int-var-in-some-register/imm32/outputs
16485     0x11/imm32/alloc-id:fake
16486     _string_81_subop_subtract/imm32/subx-name
16487     3/imm32/rm32-is-first-output
16488     0/imm32/no-r32
16489     1/imm32/imm32-is-first-inout
16490     0/imm32/no-imm8
16491     0/imm32/no-disp32
16492     0/imm32/output-is-write-only
16493     0x11/imm32/alloc-id:fake
16494     _Primitive-subtract-lit-from-mem/imm32/next
16495 _Primitive-subtract-lit-from-mem:  # (payload primitive)
16496     0x11/imm32/alloc-id:fake:payload
16497     # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32
16498     0x11/imm32/alloc-id:fake
16499     _string-subtract-from/imm32/name
16500     0x11/imm32/alloc-id:fake
16501     Int-var-and-literal/imm32/inouts
16502     0/imm32/no-outputs
16503     0/imm32/no-outputs
16504     0x11/imm32/alloc-id:fake
16505     _string_81_subop_subtract/imm32/subx-name
16506     1/imm32/rm32-is-first-inout
16507     0/imm32/no-r32
16508     2/imm32/imm32-is-second-inout
16509     0/imm32/no-imm8
16510     0/imm32/no-disp32
16511     0/imm32/output-is-write-only
16512     0x11/imm32/alloc-id:fake
16513     _Primitive-and-with-eax/imm32/next
16514 # - and
16515 _Primitive-and-with-eax:  # (payload primitive)
16516     0x11/imm32/alloc-id:fake:payload
16517     # var/eax <- and lit => 25/and-with-eax lit/imm32
16518     0x11/imm32/alloc-id:fake
16519     _string-and/imm32/name
16520     0x11/imm32/alloc-id:fake
16521     Single-lit-var/imm32/inouts
16522     0x11/imm32/alloc-id:fake
16523     Single-int-var-in-eax/imm32/outputs
16524     0x11/imm32/alloc-id:fake
16525     _string_25_and_with_eax/imm32/subx-name
16526     0/imm32/no-rm32
16527     0/imm32/no-r32
16528     1/imm32/imm32-is-first-inout
16529     0/imm32/no-imm8
16530     0/imm32/no-disp32
16531     0/imm32/output-is-write-only
16532     0x11/imm32/alloc-id:fake
16533     _Primitive-and-reg-with-reg/imm32/next
16534 _Primitive-and-reg-with-reg:  # (payload primitive)
16535     0x11/imm32/alloc-id:fake:payload
16536     # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32
16537     0x11/imm32/alloc-id:fake
16538     _string-and/imm32/name
16539     0x11/imm32/alloc-id:fake
16540     Single-int-var-in-some-register/imm32/inouts
16541     0x11/imm32/alloc-id:fake
16542     Single-int-var-in-some-register/imm32/outputs
16543     0x11/imm32/alloc-id:fake
16544     _string_21_and_with/imm32/subx-name
16545     3/imm32/rm32-is-first-output
16546     1/imm32/r32-is-first-inout
16547     0/imm32/no-imm32
16548     0/imm32/no-imm8
16549     0/imm32/no-disp32
16550     0/imm32/output-is-write-only
16551     0x11/imm32/alloc-id:fake
16552     _Primitive-and-reg-with-mem/imm32/next
16553 _Primitive-and-reg-with-mem:  # (payload primitive)
16554     0x11/imm32/alloc-id:fake:payload
16555     # and-with var1 var2/reg => 21/and-with var1 var2/r32
16556     0x11/imm32/alloc-id:fake
16557     _string-and-with/imm32/name
16558     0x11/imm32/alloc-id:fake
16559     Two-args-int-stack-int-reg/imm32/inouts
16560     0/imm32/no-outputs
16561     0/imm32/no-outputs
16562     0x11/imm32/alloc-id:fake
16563     _string_21_and_with/imm32/subx-name
16564     1/imm32/rm32-is-first-inout
16565     2/imm32/r32-is-second-inout
16566     0/imm32/no-imm32
16567     0/imm32/no-imm8
16568     0/imm32/no-disp32
16569     0/imm32/output-is-write-only
16570     0x11/imm32/alloc-id:fake
16571     _Primitive-and-mem-with-reg/imm32/next
16572 _Primitive-and-mem-with-reg:  # (payload primitive)
16573     0x11/imm32/alloc-id:fake:payload
16574     # var1/reg <- and var2 => 23/and var2/rm32 var1/r32
16575     0x11/imm32/alloc-id:fake
16576     _string-and/imm32/name
16577     0x11/imm32/alloc-id:fake
16578     Single-int-var-in-mem/imm32/inouts
16579     0x11/imm32/alloc-id:fake
16580     Single-int-var-in-some-register/imm32/outputs
16581     0x11/imm32/alloc-id:fake
16582     _string_23_and/imm32/subx-name
16583     1/imm32/rm32-is-first-inout
16584     3/imm32/r32-is-first-output
16585     0/imm32/no-imm32
16586     0/imm32/no-imm8
16587     0/imm32/no-disp32
16588     0/imm32/output-is-write-only
16589     0x11/imm32/alloc-id:fake
16590     _Primitive-and-lit-with-reg/imm32/next
16591 _Primitive-and-lit-with-reg:  # (payload primitive)
16592     0x11/imm32/alloc-id:fake:payload
16593     # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32
16594     0x11/imm32/alloc-id:fake
16595     _string-and/imm32/name
16596     0x11/imm32/alloc-id:fake
16597     Single-lit-var/imm32/inouts
16598     0x11/imm32/alloc-id:fake
16599     Single-int-var-in-some-register/imm32/outputs
16600     0x11/imm32/alloc-id:fake
16601     _string_81_subop_and/imm32/subx-name
16602     3/imm32/rm32-is-first-output
16603     0/imm32/no-r32
16604     1/imm32/imm32-is-first-inout
16605     0/imm32/no-imm8
16606     0/imm32/no-disp32
16607     0/imm32/output-is-write-only
16608     0x11/imm32/alloc-id:fake
16609     _Primitive-and-lit-with-mem/imm32/next
16610 _Primitive-and-lit-with-mem:  # (payload primitive)
16611     0x11/imm32/alloc-id:fake:payload
16612     # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32
16613     0x11/imm32/alloc-id:fake
16614     _string-and-with/imm32/name
16615     0x11/imm32/alloc-id:fake
16616     Int-var-and-literal/imm32/inouts
16617     0/imm32/no-outputs
16618     0/imm32/no-outputs
16619     0x11/imm32/alloc-id:fake
16620     _string_81_subop_and/imm32/subx-name
16621     1/imm32/rm32-is-first-inout
16622     0/imm32/no-r32
16623     2/imm32/imm32-is-second-inout
16624     0/imm32/no-imm8
16625     0/imm32/no-disp32
16626     0/imm32/output-is-write-only
16627     0x11/imm32/alloc-id:fake
16628     _Primitive-or-with-eax/imm32/next
16629 # - or
16630 _Primitive-or-with-eax:  # (payload primitive)
16631     0x11/imm32/alloc-id:fake:payload
16632     # var/eax <- or lit => 0d/or-with-eax lit/imm32
16633     0x11/imm32/alloc-id:fake
16634     _string-or/imm32/name
16635     0x11/imm32/alloc-id:fake
16636     Single-lit-var/imm32/inouts
16637     0x11/imm32/alloc-id:fake
16638     Single-int-var-in-eax/imm32/outputs
16639     0x11/imm32/alloc-id:fake
16640     _string_0d_or_with_eax/imm32/subx-name
16641     0/imm32/no-rm32
16642     0/imm32/no-r32
16643     1/imm32/imm32-is-first-inout
16644     0/imm32/no-imm8
16645     0/imm32/no-disp32
16646     0/imm32/output-is-write-only
16647     0x11/imm32/alloc-id:fake
16648     _Primitive-or-reg-with-reg/imm32/next
16649 _Primitive-or-reg-with-reg:  # (payload primitive)
16650     0x11/imm32/alloc-id:fake:payload
16651     # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32
16652     0x11/imm32/alloc-id:fake
16653     _string-or/imm32/name
16654     0x11/imm32/alloc-id:fake
16655     Single-int-var-in-some-register/imm32/inouts
16656     0x11/imm32/alloc-id:fake
16657     Single-int-var-in-some-register/imm32/outputs
16658     0x11/imm32/alloc-id:fake
16659     _string_09_or_with/imm32/subx-name
16660     3/imm32/rm32-is-first-output
16661     1/imm32/r32-is-first-inout
16662     0/imm32/no-imm32
16663     0/imm32/no-imm8
16664     0/imm32/no-disp32
16665     0/imm32/output-is-write-only
16666     0x11/imm32/alloc-id:fake
16667     _Primitive-or-reg-with-mem/imm32/next
16668 _Primitive-or-reg-with-mem:  # (payload primitive)
16669     0x11/imm32/alloc-id:fake:payload
16670     # or-with var1 var2/reg => 09/or-with var1 var2/r32
16671     0x11/imm32/alloc-id:fake
16672     _string-or-with/imm32/name
16673     0x11/imm32/alloc-id:fake
16674     Two-args-int-stack-int-reg/imm32/inouts
16675     0/imm32/no-outputs
16676     0/imm32/no-outputs
16677     0x11/imm32/alloc-id:fake
16678     _string_09_or_with/imm32/subx-name
16679     1/imm32/rm32-is-first-inout
16680     2/imm32/r32-is-second-inout
16681     0/imm32/no-imm32
16682     0/imm32/no-imm8
16683     0/imm32/no-disp32
16684     0/imm32/output-is-write-only
16685     0x11/imm32/alloc-id:fake
16686     _Primitive-or-mem-with-reg/imm32/next
16687 _Primitive-or-mem-with-reg:  # (payload primitive)
16688     0x11/imm32/alloc-id:fake:payload
16689     # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32
16690     0x11/imm32/alloc-id:fake
16691     _string-or/imm32/name
16692     0x11/imm32/alloc-id:fake
16693     Single-int-var-in-mem/imm32/inouts
16694     0x11/imm32/alloc-id:fake
16695     Single-int-var-in-some-register/imm32/outputs
16696     0x11/imm32/alloc-id:fake
16697     _string_0b_or/imm32/subx-name
16698     1/imm32/rm32-is-first-inout
16699     3/imm32/r32-is-first-output
16700     0/imm32/no-imm32
16701     0/imm32/no-imm8
16702     0/imm32/no-disp32
16703     0/imm32/output-is-write-only
16704     0x11/imm32/alloc-id:fake
16705     _Primitive-or-lit-with-reg/imm32/next
16706 _Primitive-or-lit-with-reg:  # (payload primitive)
16707     0x11/imm32/alloc-id:fake:payload
16708     # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32
16709     0x11/imm32/alloc-id:fake
16710     _string-or/imm32/name
16711     0x11/imm32/alloc-id:fake
16712     Single-lit-var/imm32/inouts
16713     0x11/imm32/alloc-id:fake
16714     Single-int-var-in-some-register/imm32/outputs
16715     0x11/imm32/alloc-id:fake
16716     _string_81_subop_or/imm32/subx-name
16717     3/imm32/rm32-is-first-output
16718     0/imm32/no-r32
16719     1/imm32/imm32-is-first-inout
16720     0/imm32/no-imm8
16721     0/imm32/no-disp32
16722     0/imm32/output-is-write-only
16723     0x11/imm32/alloc-id:fake
16724     _Primitive-or-lit-with-mem/imm32/next
16725 _Primitive-or-lit-with-mem:  # (payload primitive)
16726     0x11/imm32/alloc-id:fake:payload
16727     # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32
16728     0x11/imm32/alloc-id:fake
16729     _string-or-with/imm32/name
16730     0x11/imm32/alloc-id:fake
16731     Int-var-and-literal/imm32/inouts
16732     0/imm32/no-outputs
16733     0/imm32/no-outputs
16734     0x11/imm32/alloc-id:fake
16735     _string_81_subop_or/imm32/subx-name
16736     1/imm32/rm32-is-first-inout
16737     0/imm32/no-r32
16738     2/imm32/imm32-is-second-inout
16739     0/imm32/no-imm8
16740     0/imm32/no-disp32
16741     0/imm32/output-is-write-only
16742     0x11/imm32/alloc-id:fake
16743     _Primitive-xor-with-eax/imm32/next
16744 # - xor
16745 _Primitive-xor-with-eax:  # (payload primitive)
16746     0x11/imm32/alloc-id:fake:payload
16747     # var/eax <- xor lit => 35/xor-with-eax lit/imm32
16748     0x11/imm32/alloc-id:fake
16749     _string-xor/imm32/name
16750     0x11/imm32/alloc-id:fake
16751     Single-lit-var/imm32/inouts
16752     0x11/imm32/alloc-id:fake
16753     Single-int-var-in-eax/imm32/outputs
16754     0x11/imm32/alloc-id:fake
16755     _string_35_xor_with_eax/imm32/subx-name
16756     0/imm32/no-rm32
16757     0/imm32/no-r32
16758     1/imm32/imm32-is-first-inout
16759     0/imm32/no-imm8
16760     0/imm32/no-disp32
16761     0/imm32/output-is-write-only
16762     0x11/imm32/alloc-id:fake
16763     _Primitive-xor-reg-with-reg/imm32/next
16764 _Primitive-xor-reg-with-reg:  # (payload primitive)
16765     0x11/imm32/alloc-id:fake:payload
16766     # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32
16767     0x11/imm32/alloc-id:fake
16768     _string-xor/imm32/name
16769     0x11/imm32/alloc-id:fake
16770     Single-int-var-in-some-register/imm32/inouts
16771     0x11/imm32/alloc-id:fake
16772     Single-int-var-in-some-register/imm32/outputs
16773     0x11/imm32/alloc-id:fake
16774     _string_31_xor_with/imm32/subx-name
16775     3/imm32/rm32-is-first-output
16776     1/imm32/r32-is-first-inout
16777     0/imm32/no-imm32
16778     0/imm32/no-imm8
16779     0/imm32/no-disp32
16780     0/imm32/output-is-write-only
16781     0x11/imm32/alloc-id:fake
16782     _Primitive-xor-reg-with-mem/imm32/next
16783 _Primitive-xor-reg-with-mem:  # (payload primitive)
16784     0x11/imm32/alloc-id:fake:payload
16785     # xor-with var1 var2/reg => 31/xor-with var1 var2/r32
16786     0x11/imm32/alloc-id:fake
16787     _string-xor-with/imm32/name
16788     0x11/imm32/alloc-id:fake
16789     Two-args-int-stack-int-reg/imm32/inouts
16790     0/imm32/no-outputs
16791     0/imm32/no-outputs
16792     0x11/imm32/alloc-id:fake
16793     _string_31_xor_with/imm32/subx-name
16794     1/imm32/rm32-is-first-inout
16795     2/imm32/r32-is-second-inout
16796     0/imm32/no-imm32
16797     0/imm32/no-imm8
16798     0/imm32/no-disp32
16799     0/imm32/output-is-write-only
16800     0x11/imm32/alloc-id:fake
16801     _Primitive-xor-mem-with-reg/imm32/next
16802 _Primitive-xor-mem-with-reg:  # (payload primitive)
16803     0x11/imm32/alloc-id:fake:payload
16804     # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32
16805     0x11/imm32/alloc-id:fake
16806     _string-xor/imm32/name
16807     0x11/imm32/alloc-id:fake
16808     Single-int-var-in-mem/imm32/inouts
16809     0x11/imm32/alloc-id:fake
16810     Single-int-var-in-some-register/imm32/outputs
16811     0x11/imm32/alloc-id:fake
16812     _string_33_xor/imm32/subx-name
16813     1/imm32/rm32-is-first-inout
16814     3/imm32/r32-is-first-output
16815     0/imm32/no-imm32
16816     0/imm32/no-imm8
16817     0/imm32/no-disp32
16818     0/imm32/output-is-write-only
16819     0x11/imm32/alloc-id:fake
16820     _Primitive-xor-lit-with-reg/imm32/next
16821 _Primitive-xor-lit-with-reg:  # (payload primitive)
16822     0x11/imm32/alloc-id:fake:payload
16823     # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32
16824     0x11/imm32/alloc-id:fake
16825     _string-xor/imm32/name
16826     0x11/imm32/alloc-id:fake
16827     Single-lit-var/imm32/inouts
16828     0x11/imm32/alloc-id:fake
16829     Single-int-var-in-some-register/imm32/outputs
16830     0x11/imm32/alloc-id:fake
16831     _string_81_subop_xor/imm32/subx-name
16832     3/imm32/rm32-is-first-output
16833     0/imm32/no-r32
16834     1/imm32/imm32-is-first-inout
16835     0/imm32/no-imm8
16836     0/imm32/no-disp32
16837     0/imm32/output-is-write-only
16838     0x11/imm32/alloc-id:fake
16839     _Primitive-xor-lit-with-mem/imm32/next
16840 _Primitive-xor-lit-with-mem:  # (payload primitive)
16841     0x11/imm32/alloc-id:fake:payload
16842     # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32
16843     0x11/imm32/alloc-id:fake
16844     _string-xor-with/imm32/name
16845     0x11/imm32/alloc-id:fake
16846     Int-var-and-literal/imm32/inouts
16847     0/imm32/no-outputs
16848     0/imm32/no-outputs
16849     0x11/imm32/alloc-id:fake
16850     _string_81_subop_xor/imm32/subx-name
16851     1/imm32/rm32-is-first-inout
16852     0/imm32/no-r32
16853     2/imm32/imm32-is-second-inout
16854     0/imm32/no-imm8
16855     0/imm32/no-disp32
16856     0/imm32/output-is-write-only
16857     0x11/imm32/alloc-id:fake
16858     _Primitive-shift-reg-left-by-lit/imm32/next
16859 _Primitive-shift-reg-left-by-lit:  # (payload primitive)
16860     0x11/imm32/alloc-id:fake:payload
16861     # var1/reg <- shift-left lit => c1/shift 4/subop/left var1/rm32 lit/imm32
16862     0x11/imm32/alloc-id:fake
16863     _string-shift-left/imm32/name
16864     0x11/imm32/alloc-id:fake
16865     Single-lit-var/imm32/inouts
16866     0x11/imm32/alloc-id:fake
16867     Single-int-var-in-some-register/imm32/outputs
16868     0x11/imm32/alloc-id:fake
16869     _string_c1_subop_shift_left/imm32/subx-name
16870     3/imm32/rm32-is-first-output
16871     0/imm32/no-r32
16872     0/imm32/no-imm32
16873     1/imm32/imm8-is-first-inout
16874     0/imm32/no-disp32
16875     0/imm32/output-is-write-only
16876     0x11/imm32/alloc-id:fake
16877     _Primitive-shift-reg-right-by-lit/imm32/next
16878 _Primitive-shift-reg-right-by-lit:  # (payload primitive)
16879     0x11/imm32/alloc-id:fake:payload
16880     # var1/reg <- shift-right lit => c1/shift 5/subop/right var1/rm32 lit/imm32
16881     0x11/imm32/alloc-id:fake
16882     _string-shift-right/imm32/name
16883     0x11/imm32/alloc-id:fake
16884     Single-lit-var/imm32/inouts
16885     0x11/imm32/alloc-id:fake
16886     Single-int-var-in-some-register/imm32/outputs
16887     0x11/imm32/alloc-id:fake
16888     _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name
16889     3/imm32/rm32-is-first-output
16890     0/imm32/no-r32
16891     0/imm32/no-imm32
16892     1/imm32/imm8-is-first-inout
16893     0/imm32/no-disp32
16894     0/imm32/output-is-write-only
16895     0x11/imm32/alloc-id:fake
16896     _Primitive-shift-reg-right-signed-by-lit/imm32/next
16897 _Primitive-shift-reg-right-signed-by-lit:  # (payload primitive)
16898     0x11/imm32/alloc-id:fake:payload
16899     # var1/reg <- shift-right-signed lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32
16900     0x11/imm32/alloc-id:fake
16901     _string-shift-right-signed/imm32/name
16902     0x11/imm32/alloc-id:fake
16903     Single-lit-var/imm32/inouts
16904     0x11/imm32/alloc-id:fake
16905     Single-int-var-in-some-register/imm32/outputs
16906     0x11/imm32/alloc-id:fake
16907     _string_c1_subop_shift_right_preserving_sign/imm32/subx-name
16908     3/imm32/rm32-is-first-output
16909     0/imm32/no-r32
16910     0/imm32/no-imm32
16911     1/imm32/imm8-is-first-inout
16912     0/imm32/no-disp32
16913     0/imm32/output-is-write-only
16914     0x11/imm32/alloc-id:fake
16915     _Primitive-shift-mem-left-by-lit/imm32/next
16916 _Primitive-shift-mem-left-by-lit:  # (payload primitive)
16917     0x11/imm32/alloc-id:fake:payload
16918     # shift-left var1, lit => c1/shift 4/subop/left var1/rm32 lit/imm32
16919     0x11/imm32/alloc-id:fake
16920     _string-shift-left/imm32/name
16921     0x11/imm32/alloc-id:fake
16922     Int-var-and-literal/imm32/inouts
16923     0/imm32/no-outputs
16924     0/imm32/no-outputs
16925     0x11/imm32/alloc-id:fake
16926     _string_c1_subop_shift_left/imm32/subx-name
16927     1/imm32/rm32-is-first-inout
16928     0/imm32/no-r32
16929     0/imm32/no-imm32
16930     2/imm32/imm8-is-second-inout
16931     0/imm32/no-disp32
16932     0/imm32/output-is-write-only
16933     0x11/imm32/alloc-id:fake
16934     _Primitive-shift-mem-right-by-lit/imm32/next
16935 _Primitive-shift-mem-right-by-lit:  # (payload primitive)
16936     0x11/imm32/alloc-id:fake:payload
16937     # shift-right var1, lit => c1/shift 5/subop/right var1/rm32 lit/imm32
16938     0x11/imm32/alloc-id:fake
16939     _string-shift-right/imm32/name
16940     0x11/imm32/alloc-id:fake
16941     Int-var-and-literal/imm32/inouts
16942     0/imm32/no-outputs
16943     0/imm32/no-outputs
16944     0x11/imm32/alloc-id:fake
16945     _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name
16946     1/imm32/rm32-is-first-inout
16947     0/imm32/no-r32
16948     0/imm32/no-imm32
16949     2/imm32/imm8-is-second-inout
16950     0/imm32/no-disp32
16951     0/imm32/output-is-write-only
16952     0x11/imm32/alloc-id:fake
16953     _Primitive-shift-mem-right-signed-by-lit/imm32/next
16954 _Primitive-shift-mem-right-signed-by-lit:  # (payload primitive)
16955     0x11/imm32/alloc-id:fake:payload
16956     # shift-right-signed var1, lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32
16957     0x11/imm32/alloc-id:fake
16958     _string-shift-right-signed/imm32/name
16959     0x11/imm32/alloc-id:fake
16960     Int-var-and-literal/imm32/inouts
16961     0/imm32/no-outputs
16962     0/imm32/no-outputs
16963     0x11/imm32/alloc-id:fake
16964     _string_c1_subop_shift_right_preserving_sign/imm32/subx-name
16965     1/imm32/rm32-is-first-inout
16966     0/imm32/no-r32
16967     0/imm32/no-imm32
16968     2/imm32/imm8-is-second-inout
16969     0/imm32/no-disp32
16970     0/imm32/output-is-write-only
16971     0x11/imm32/alloc-id:fake
16972     _Primitive-copy-to-eax/imm32/next
16973 # - copy
16974 _Primitive-copy-to-eax:  # (payload primitive)
16975     0x11/imm32/alloc-id:fake:payload
16976     # var/eax <- copy lit => b8/copy-to-eax lit/imm32
16977     0x11/imm32/alloc-id:fake
16978     _string-copy/imm32/name
16979     0x11/imm32/alloc-id:fake
16980     Single-lit-var/imm32/inouts
16981     0x11/imm32/alloc-id:fake
16982     Single-int-var-in-eax/imm32/outputs
16983     0x11/imm32/alloc-id:fake
16984     _string_b8_copy_to_eax/imm32/subx-name
16985     0/imm32/no-rm32
16986     0/imm32/no-r32
16987     1/imm32/imm32-is-first-inout
16988     0/imm32/no-imm8
16989     0/imm32/no-disp32
16990     1/imm32/output-is-write-only
16991     0x11/imm32/alloc-id:fake
16992     _Primitive-copy-to-ecx/imm32/next
16993 _Primitive-copy-to-ecx:  # (payload primitive)
16994     0x11/imm32/alloc-id:fake:payload
16995     # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32
16996     0x11/imm32/alloc-id:fake
16997     _string-copy/imm32/name
16998     0x11/imm32/alloc-id:fake
16999     Single-lit-var/imm32/inouts
17000     0x11/imm32/alloc-id:fake
17001     Single-int-var-in-ecx/imm32/outputs
17002     0x11/imm32/alloc-id:fake
17003     _string_b9_copy_to_ecx/imm32/subx-name
17004     0/imm32/no-rm32
17005     0/imm32/no-r32
17006     1/imm32/imm32-is-first-inout
17007     0/imm32/no-imm8
17008     0/imm32/no-disp32
17009     1/imm32/output-is-write-only
17010     0x11/imm32/alloc-id:fake
17011     _Primitive-copy-to-edx/imm32/next
17012 _Primitive-copy-to-edx:  # (payload primitive)
17013     0x11/imm32/alloc-id:fake:payload
17014     # var/edx <- copy lit => ba/copy-to-edx lit/imm32
17015     0x11/imm32/alloc-id:fake
17016     _string-copy/imm32/name
17017     0x11/imm32/alloc-id:fake
17018     Single-lit-var/imm32/inouts
17019     0x11/imm32/alloc-id:fake
17020     Single-int-var-in-edx/imm32/outputs
17021     0x11/imm32/alloc-id:fake
17022     _string_ba_copy_to_edx/imm32/subx-name
17023     0/imm32/no-rm32
17024     0/imm32/no-r32
17025     1/imm32/imm32-is-first-inout
17026     0/imm32/no-imm8
17027     0/imm32/no-disp32
17028     1/imm32/output-is-write-only
17029     0x11/imm32/alloc-id:fake
17030     _Primitive-copy-to-ebx/imm32/next
17031 _Primitive-copy-to-ebx:  # (payload primitive)
17032     0x11/imm32/alloc-id:fake:payload
17033     # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32
17034     0x11/imm32/alloc-id:fake
17035     _string-copy/imm32/name
17036     0x11/imm32/alloc-id:fake
17037     Single-lit-var/imm32/inouts
17038     0x11/imm32/alloc-id:fake
17039     Single-int-var-in-ebx/imm32/outputs
17040     0x11/imm32/alloc-id:fake
17041     _string_bb_copy_to_ebx/imm32/subx-name
17042     0/imm32/no-rm32
17043     0/imm32/no-r32
17044     1/imm32/imm32-is-first-inout
17045     0/imm32/no-imm8
17046     0/imm32/no-disp32
17047     1/imm32/output-is-write-only
17048     0x11/imm32/alloc-id:fake
17049     _Primitive-copy-to-esi/imm32/next
17050 _Primitive-copy-to-esi:  # (payload primitive)
17051     0x11/imm32/alloc-id:fake:payload
17052     # var/esi <- copy lit => be/copy-to-esi lit/imm32
17053     0x11/imm32/alloc-id:fake
17054     _string-copy/imm32/name
17055     0x11/imm32/alloc-id:fake
17056     Single-lit-var/imm32/inouts
17057     0x11/imm32/alloc-id:fake
17058     Single-int-var-in-esi/imm32/outputs
17059     0x11/imm32/alloc-id:fake
17060     _string_be_copy_to_esi/imm32/subx-name
17061     0/imm32/no-rm32
17062     0/imm32/no-r32
17063     1/imm32/imm32-is-first-inout
17064     0/imm32/no-imm8
17065     0/imm32/no-disp32
17066     1/imm32/output-is-write-only
17067     0x11/imm32/alloc-id:fake
17068     _Primitive-copy-to-edi/imm32/next
17069 _Primitive-copy-to-edi:  # (payload primitive)
17070     0x11/imm32/alloc-id:fake:payload
17071     # var/edi <- copy lit => bf/copy-to-edi lit/imm32
17072     0x11/imm32/alloc-id:fake
17073     _string-copy/imm32/name
17074     0x11/imm32/alloc-id:fake
17075     Single-lit-var/imm32/inouts
17076     0x11/imm32/alloc-id:fake
17077     Single-int-var-in-edi/imm32/outputs
17078     0x11/imm32/alloc-id:fake
17079     _string_bf_copy_to_edi/imm32/subx-name
17080     0/imm32/no-rm32
17081     0/imm32/no-r32
17082     1/imm32/imm32-is-first-inout
17083     0/imm32/no-imm8
17084     0/imm32/no-disp32
17085     1/imm32/output-is-write-only
17086     0x11/imm32/alloc-id:fake
17087     _Primitive-copy-reg-to-reg/imm32/next
17088 _Primitive-copy-reg-to-reg:  # (payload primitive)
17089     0x11/imm32/alloc-id:fake:payload
17090     # var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32
17091     0x11/imm32/alloc-id:fake
17092     _string-copy/imm32/name
17093     0x11/imm32/alloc-id:fake
17094     Single-int-var-in-some-register/imm32/inouts
17095     0x11/imm32/alloc-id:fake
17096     Single-int-var-in-some-register/imm32/outputs
17097     0x11/imm32/alloc-id:fake
17098     _string_89_<-/imm32/subx-name
17099     3/imm32/rm32-is-first-output
17100     1/imm32/r32-is-first-inout
17101     0/imm32/no-imm32
17102     0/imm32/no-imm8
17103     0/imm32/no-disp32
17104     1/imm32/output-is-write-only
17105     0x11/imm32/alloc-id:fake
17106     _Primitive-copy-reg-to-mem/imm32/next
17107 _Primitive-copy-reg-to-mem:  # (payload primitive)
17108     0x11/imm32/alloc-id:fake:payload
17109     # copy-to var1 var2/reg => 89/<- var1 var2/r32
17110     0x11/imm32/alloc-id:fake
17111     _string-copy-to/imm32/name
17112     0x11/imm32/alloc-id:fake
17113     Two-args-int-stack-int-reg/imm32/inouts
17114     0/imm32/no-outputs
17115     0/imm32/no-outputs
17116     0x11/imm32/alloc-id:fake
17117     _string_89_<-/imm32/subx-name
17118     1/imm32/rm32-is-first-inout
17119     2/imm32/r32-is-second-inout
17120     0/imm32/no-imm32
17121     0/imm32/no-imm8
17122     0/imm32/no-disp32
17123     1/imm32/output-is-write-only
17124     0x11/imm32/alloc-id:fake
17125     _Primitive-copy-mem-to-reg/imm32/next
17126 _Primitive-copy-mem-to-reg:  # (payload primitive)
17127     0x11/imm32/alloc-id:fake:payload
17128     # var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32
17129     0x11/imm32/alloc-id:fake
17130     _string-copy/imm32/name
17131     0x11/imm32/alloc-id:fake
17132     Single-int-var-in-mem/imm32/inouts
17133     0x11/imm32/alloc-id:fake
17134     Single-int-var-in-some-register/imm32/outputs
17135     0x11/imm32/alloc-id:fake
17136     _string_8b_->/imm32/subx-name
17137     1/imm32/rm32-is-first-inout
17138     3/imm32/r32-is-first-output
17139     0/imm32/no-imm32
17140     0/imm32/no-imm8
17141     0/imm32/no-disp32
17142     1/imm32/output-is-write-only
17143     0x11/imm32/alloc-id:fake
17144     _Primitive-copy-lit-to-reg/imm32/next
17145 _Primitive-copy-lit-to-reg:  # (payload primitive)
17146     0x11/imm32/alloc-id:fake:payload
17147     # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32
17148     0x11/imm32/alloc-id:fake
17149     _string-copy/imm32/name
17150     0x11/imm32/alloc-id:fake
17151     Single-lit-var/imm32/inouts
17152     0x11/imm32/alloc-id:fake
17153     Single-int-var-in-some-register/imm32/outputs
17154     0x11/imm32/alloc-id:fake
17155     _string_c7_subop_copy/imm32/subx-name
17156     3/imm32/rm32-is-first-output
17157     0/imm32/no-r32
17158     1/imm32/imm32-is-first-inout
17159     0/imm32/no-imm8
17160     0/imm32/no-disp32
17161     1/imm32/output-is-write-only
17162     0x11/imm32/alloc-id:fake
17163     _Primitive-copy-lit-to-mem/imm32/next
17164 _Primitive-copy-lit-to-mem:  # (payload primitive)
17165     0x11/imm32/alloc-id:fake:payload
17166     # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32
17167     0x11/imm32/alloc-id:fake
17168     _string-copy-to/imm32/name
17169     0x11/imm32/alloc-id:fake
17170     Int-var-and-literal/imm32/inouts
17171     0/imm32/no-outputs
17172     0/imm32/no-outputs
17173     0x11/imm32/alloc-id:fake
17174     _string_c7_subop_copy/imm32/subx-name
17175     1/imm32/rm32-is-first-inout
17176     0/imm32/no-r32
17177     2/imm32/imm32-is-second-inout
17178     0/imm32/no-imm8
17179     0/imm32/no-disp32
17180     1/imm32/output-is-write-only
17181     0x11/imm32/alloc-id:fake
17182     _Primitive-copy-byte-from-reg/imm32/next
17183 # - copy byte
17184 _Primitive-copy-byte-from-reg:
17185     0x11/imm32/alloc-id:fake:payload
17186     # var/reg <- copy-byte var2/reg2 => 8a/byte-> %var2 var/r32
17187     0x11/imm32/alloc-id:fake
17188     _string-copy-byte/imm32/name
17189     0x11/imm32/alloc-id:fake
17190     Single-byte-var-in-some-register/imm32/inouts
17191     0x11/imm32/alloc-id:fake
17192     Single-byte-var-in-some-register/imm32/outputs
17193     0x11/imm32/alloc-id:fake
17194     _string_8a_copy_byte/imm32/subx-name
17195     1/imm32/rm32-is-first-inout
17196     3/imm32/r32-is-first-output
17197     0/imm32/no-imm32
17198     0/imm32/no-imm8
17199     0/imm32/no-disp32
17200     1/imm32/output-is-write-only
17201     0x11/imm32/alloc-id:fake
17202     _Primitive-copy-byte-from-mem/imm32/next
17203 _Primitive-copy-byte-from-mem:
17204     0x11/imm32/alloc-id:fake:payload
17205     # var/reg <- copy-byte *var2/reg2 => 8a/byte-> *var2 var/r32
17206     0x11/imm32/alloc-id:fake
17207     _string-copy-byte/imm32/name
17208     0x11/imm32/alloc-id:fake
17209     Single-byte-var-in-mem/imm32/inouts
17210     0x11/imm32/alloc-id:fake
17211     Single-byte-var-in-some-register/imm32/outputs
17212     0x11/imm32/alloc-id:fake
17213     _string_8a_copy_byte/imm32/subx-name
17214     1/imm32/rm32-is-first-inout
17215     3/imm32/r32-is-first-output
17216     0/imm32/no-imm32
17217     0/imm32/no-imm8
17218     0/imm32/no-disp32
17219     1/imm32/output-is-write-only
17220     0x11/imm32/alloc-id:fake
17221     _Primitive-copy-byte-to-mem/imm32/next
17222 _Primitive-copy-byte-to-mem:
17223     0x11/imm32/alloc-id:fake:payload
17224     # copy-byte-to *var1/reg1, var2/reg2 => 88/byte<- *reg1 reg2/r32
17225     0x11/imm32/alloc-id:fake
17226     _string-copy-byte-to/imm32/name
17227     0x11/imm32/alloc-id:fake
17228     Two-args-byte-stack-byte-reg/imm32/inouts
17229     0/imm32/no-outputs
17230     0/imm32/no-outputs
17231     0x11/imm32/alloc-id:fake
17232     _string_88_copy_byte/imm32/subx-name
17233     1/imm32/rm32-is-first-inout
17234     2/imm32/r32-is-second-inout
17235     0/imm32/no-imm32
17236     0/imm32/no-imm8
17237     0/imm32/no-disp32
17238     0/imm32/output-is-write-only
17239     0x11/imm32/alloc-id:fake
17240     _Primitive-address/imm32/next
17241 # - address
17242 _Primitive-address:  # (payload primitive)
17243     0x11/imm32/alloc-id:fake:payload
17244     # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32
17245     0x11/imm32/alloc-id:fake
17246     _string-address/imm32/name
17247     0x11/imm32/alloc-id:fake
17248     Single-int-var-in-mem/imm32/inouts
17249     0x11/imm32/alloc-id:fake
17250     Single-addr-var-in-some-register/imm32/outputs
17251     0x11/imm32/alloc-id:fake
17252     _string_8d_copy_address/imm32/subx-name
17253     1/imm32/rm32-is-first-inout
17254     3/imm32/r32-is-first-output
17255     0/imm32/no-imm32
17256     0/imm32/no-imm8
17257     0/imm32/no-disp32
17258     1/imm32/output-is-write-only
17259     0x11/imm32/alloc-id:fake
17260     _Primitive-compare-reg-with-reg/imm32/next
17261 # - compare
17262 _Primitive-compare-reg-with-reg:  # (payload primitive)
17263     0x11/imm32/alloc-id:fake:payload
17264     # compare var1/reg1 var2/reg2 => 39/compare var1/rm32 var2/r32
17265     0x11/imm32/alloc-id:fake
17266     _string-compare/imm32/name
17267     0x11/imm32/alloc-id:fake
17268     Two-int-args-in-regs/imm32/inouts
17269     0/imm32/no-outputs
17270     0/imm32/no-outputs
17271     0x11/imm32/alloc-id:fake
17272     _string_39_compare->/imm32/subx-name
17273     1/imm32/rm32-is-first-inout
17274     2/imm32/r32-is-second-inout
17275     0/imm32/no-imm32
17276     0/imm32/no-imm8
17277     0/imm32/no-disp32
17278     0/imm32/output-is-write-only
17279     0x11/imm32/alloc-id:fake
17280     _Primitive-compare-mem-with-reg/imm32/next
17281 _Primitive-compare-mem-with-reg:  # (payload primitive)
17282     0x11/imm32/alloc-id:fake:payload
17283     # compare var1 var2/reg => 39/compare var1/rm32 var2/r32
17284     0x11/imm32/alloc-id:fake
17285     _string-compare/imm32/name
17286     0x11/imm32/alloc-id:fake
17287     Two-args-int-stack-int-reg/imm32/inouts
17288     0/imm32/no-outputs
17289     0/imm32/no-outputs
17290     0x11/imm32/alloc-id:fake
17291     _string_39_compare->/imm32/subx-name
17292     1/imm32/rm32-is-first-inout
17293     2/imm32/r32-is-second-inout
17294     0/imm32/no-imm32
17295     0/imm32/no-imm8
17296     0/imm32/no-disp32
17297     0/imm32/output-is-write-only
17298     0x11/imm32/alloc-id:fake
17299     _Primitive-compare-reg-with-mem/imm32/next
17300 _Primitive-compare-reg-with-mem:  # (payload primitive)
17301     0x11/imm32/alloc-id:fake:payload
17302     # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32
17303     0x11/imm32/alloc-id:fake
17304     _string-compare/imm32/name
17305     0x11/imm32/alloc-id:fake
17306     Two-args-int-reg-int-stack/imm32/inouts
17307     0/imm32/no-outputs
17308     0/imm32/no-outputs
17309     0x11/imm32/alloc-id:fake
17310     _string_3b_compare<-/imm32/subx-name
17311     2/imm32/rm32-is-second-inout
17312     1/imm32/r32-is-first-inout
17313     0/imm32/no-imm32
17314     0/imm32/no-imm8
17315     0/imm32/no-disp32
17316     0/imm32/output-is-write-only
17317     0x11/imm32/alloc-id:fake
17318     _Primitive-compare-eax-with-literal/imm32/next
17319 _Primitive-compare-eax-with-literal:  # (payload primitive)
17320     0x11/imm32/alloc-id:fake:payload
17321     # compare var1/eax n => 3d/compare-eax-with n/imm32
17322     0x11/imm32/alloc-id:fake
17323     _string-compare/imm32/name
17324     0x11/imm32/alloc-id:fake
17325     Two-args-int-eax-int-literal/imm32/inouts
17326     0/imm32/no-outputs
17327     0/imm32/no-outputs
17328     0x11/imm32/alloc-id:fake
17329     _string_3d_compare_eax_with/imm32/subx-name
17330     0/imm32/no-rm32
17331     0/imm32/no-r32
17332     2/imm32/imm32-is-second-inout
17333     0/imm32/no-imm8
17334     0/imm32/no-disp32
17335     0/imm32/output-is-write-only
17336     0x11/imm32/alloc-id:fake
17337     _Primitive-compare-reg-with-literal/imm32/next
17338 _Primitive-compare-reg-with-literal:  # (payload primitive)
17339     0x11/imm32/alloc-id:fake:payload
17340     # compare var1/reg n => 81 7/subop/compare %reg n/imm32
17341     0x11/imm32/alloc-id:fake
17342     _string-compare/imm32/name
17343     0x11/imm32/alloc-id:fake
17344     Int-var-in-register-and-literal/imm32/inouts
17345     0/imm32/no-outputs
17346     0/imm32/no-outputs
17347     0x11/imm32/alloc-id:fake
17348     _string_81_subop_compare/imm32/subx-name
17349     1/imm32/rm32-is-first-inout
17350     0/imm32/no-r32
17351     2/imm32/imm32-is-second-inout
17352     0/imm32/no-imm8
17353     0/imm32/no-disp32
17354     0/imm32/output-is-write-only
17355     0x11/imm32/alloc-id:fake
17356     _Primitive-compare-mem-with-literal/imm32/next
17357 _Primitive-compare-mem-with-literal:  # (payload primitive)
17358     0x11/imm32/alloc-id:fake:payload
17359     # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32
17360     0x11/imm32/alloc-id:fake
17361     _string-compare/imm32/name
17362     0x11/imm32/alloc-id:fake
17363     Int-var-and-literal/imm32/inouts
17364     0/imm32/no-outputs
17365     0/imm32/no-outputs
17366     0x11/imm32/alloc-id:fake
17367     _string_81_subop_compare/imm32/subx-name
17368     1/imm32/rm32-is-first-inout
17369     0/imm32/no-r32
17370     2/imm32/imm32-is-second-inout
17371     0/imm32/no-imm8
17372     0/imm32/no-disp32
17373     0/imm32/output-is-write-only
17374     0x11/imm32/alloc-id:fake
17375     _Primitive-multiply-reg-by-reg/imm32/next
17376 # - multiply
17377 _Primitive-multiply-reg-by-reg:  # (payload primitive)
17378     0x11/imm32/alloc-id:fake:payload
17379     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
17380     0x11/imm32/alloc-id:fake
17381     _string-multiply/imm32/name
17382     0x11/imm32/alloc-id:fake
17383     Single-int-var-in-some-register/imm32/inouts
17384     0x11/imm32/alloc-id:fake
17385     Single-int-var-in-some-register/imm32/outputs
17386     0x11/imm32/alloc-id:fake
17387     _string_0f_af_multiply/imm32/subx-name
17388     1/imm32/rm32-is-first-inout
17389     3/imm32/r32-is-first-output
17390     0/imm32/no-imm32
17391     0/imm32/no-imm8
17392     0/imm32/no-disp32
17393     0/imm32/output-is-write-only
17394     0x11/imm32/alloc-id:fake
17395     _Primitive-multiply-reg-by-mem/imm32/next
17396 _Primitive-multiply-reg-by-mem:  # (payload primitive)
17397     0x11/imm32/alloc-id:fake:payload
17398     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
17399     0x11/imm32/alloc-id:fake
17400     _string-multiply/imm32/name
17401     0x11/imm32/alloc-id:fake
17402     Single-int-var-in-mem/imm32/inouts
17403     0x11/imm32/alloc-id:fake
17404     Single-int-var-in-some-register/imm32/outputs
17405     0x11/imm32/alloc-id:fake
17406     _string_0f_af_multiply/imm32/subx-name
17407     1/imm32/rm32-is-first-inout
17408     3/imm32/r32-is-first-output
17409     0/imm32/no-imm32
17410     0/imm32/no-imm8
17411     0/imm32/no-disp32
17412     0/imm32/output-is-write-only
17413     0x11/imm32/alloc-id:fake
17414     _Primitive-break-if-addr</imm32/next
17415 # - branches
17416 _Primitive-break-if-addr<:  # (payload primitive)
17417     0x11/imm32/alloc-id:fake:payload
17418     0x11/imm32/alloc-id:fake
17419     _string-break-if-addr</imm32/name
17420     0/imm32/no-inouts
17421     0/imm32/no-inouts
17422     0/imm32/no-outputs
17423     0/imm32/no-outputs
17424     0x11/imm32/alloc-id:fake
17425     _string_0f_82_jump_break/imm32/subx-name
17426     0/imm32/no-rm32
17427     0/imm32/no-r32
17428     0/imm32/no-imm32
17429     0/imm32/no-imm8
17430     0/imm32/no-disp32
17431     0/imm32/no-output
17432     0x11/imm32/alloc-id:fake
17433     _Primitive-break-if-addr>=/imm32/next
17434 _Primitive-break-if-addr>=:  # (payload primitive)
17435     0x11/imm32/alloc-id:fake:payload
17436     0x11/imm32/alloc-id:fake
17437     _string-break-if-addr>=/imm32/name
17438     0/imm32/no-inouts
17439     0/imm32/no-inouts
17440     0/imm32/no-outputs
17441     0/imm32/no-outputs
17442     0x11/imm32/alloc-id:fake
17443     _string_0f_83_jump_break/imm32/subx-name
17444     0/imm32/no-rm32
17445     0/imm32/no-r32
17446     0/imm32/no-imm32
17447     0/imm32/no-imm8
17448     0/imm32/no-disp32
17449     0/imm32/no-output
17450     0x11/imm32/alloc-id:fake
17451     _Primitive-break-if-=/imm32/next
17452 _Primitive-break-if-=:  # (payload primitive)
17453     0x11/imm32/alloc-id:fake:payload
17454     0x11/imm32/alloc-id:fake
17455     _string-break-if-=/imm32/name
17456     0/imm32/no-inouts
17457     0/imm32/no-inouts
17458     0/imm32/no-outputs
17459     0/imm32/no-outputs
17460     0x11/imm32/alloc-id:fake
17461     _string_0f_84_jump_break/imm32/subx-name
17462     0/imm32/no-rm32
17463     0/imm32/no-r32
17464     0/imm32/no-imm32
17465     0/imm32/no-imm8
17466     0/imm32/no-disp32
17467     0/imm32/no-output
17468     0x11/imm32/alloc-id:fake
17469     _Primitive-break-if-!=/imm32/next
17470 _Primitive-break-if-!=:  # (payload primitive)
17471     0x11/imm32/alloc-id:fake:payload
17472     0x11/imm32/alloc-id:fake
17473     _string-break-if-!=/imm32/name
17474     0/imm32/no-inouts
17475     0/imm32/no-inouts
17476     0/imm32/no-outputs
17477     0/imm32/no-outputs
17478     0x11/imm32/alloc-id:fake
17479     _string_0f_85_jump_break/imm32/subx-name
17480     0/imm32/no-rm32
17481     0/imm32/no-r32
17482     0/imm32/no-imm32
17483     0/imm32/no-imm8
17484     0/imm32/no-disp32
17485     0/imm32/no-output
17486     0x11/imm32/alloc-id:fake
17487     _Primitive-break-if-addr<=/imm32/next
17488 _Primitive-break-if-addr<=:  # (payload primitive)
17489     0x11/imm32/alloc-id:fake:payload
17490     0x11/imm32/alloc-id:fake
17491     _string-break-if-addr<=/imm32/name
17492     0/imm32/no-inouts
17493     0/imm32/no-inouts
17494     0/imm32/no-outputs
17495     0/imm32/no-outputs
17496     0x11/imm32/alloc-id:fake
17497     _string_0f_86_jump_break/imm32/subx-name
17498     0/imm32/no-rm32
17499     0/imm32/no-r32
17500     0/imm32/no-imm32
17501     0/imm32/no-imm8
17502     0/imm32/no-disp32
17503     0/imm32/no-output
17504     0x11/imm32/alloc-id:fake
17505     _Primitive-break-if-addr>/imm32/next
17506 _Primitive-break-if-addr>:  # (payload primitive)
17507     0x11/imm32/alloc-id:fake:payload
17508     0x11/imm32/alloc-id:fake
17509     _string-break-if-addr>/imm32/name
17510     0/imm32/no-inouts
17511     0/imm32/no-inouts
17512     0/imm32/no-outputs
17513     0/imm32/no-outputs
17514     0x11/imm32/alloc-id:fake
17515     _string_0f_87_jump_break/imm32/subx-name
17516     0/imm32/no-rm32
17517     0/imm32/no-r32
17518     0/imm32/no-imm32
17519     0/imm32/no-imm8
17520     0/imm32/no-disp32
17521     0/imm32/no-output
17522     0x11/imm32/alloc-id:fake
17523     _Primitive-break-if-</imm32/next
17524 _Primitive-break-if-<:  # (payload primitive)
17525     0x11/imm32/alloc-id:fake:payload
17526     0x11/imm32/alloc-id:fake
17527     _string-break-if-</imm32/name
17528     0/imm32/no-inouts
17529     0/imm32/no-inouts
17530     0/imm32/no-outputs
17531     0/imm32/no-outputs
17532     0x11/imm32/alloc-id:fake
17533     _string_0f_8c_jump_break/imm32/subx-name
17534     0/imm32/no-rm32
17535     0/imm32/no-r32
17536     0/imm32/no-imm32
17537     0/imm32/no-imm8
17538     0/imm32/no-disp32
17539     0/imm32/no-output
17540     0x11/imm32/alloc-id:fake
17541     _Primitive-break-if->=/imm32/next
17542 _Primitive-break-if->=:  # (payload primitive)
17543     0x11/imm32/alloc-id:fake:payload
17544     0x11/imm32/alloc-id:fake
17545     _string-break-if->=/imm32/name
17546     0/imm32/no-inouts
17547     0/imm32/no-inouts
17548     0/imm32/no-outputs
17549     0/imm32/no-outputs
17550     0x11/imm32/alloc-id:fake
17551     _string_0f_8d_jump_break/imm32/subx-name
17552     0/imm32/no-rm32
17553     0/imm32/no-r32
17554     0/imm32/no-imm32
17555     0/imm32/no-imm8
17556     0/imm32/no-disp32
17557     0/imm32/no-output
17558     0x11/imm32/alloc-id:fake
17559     _Primitive-break-if-<=/imm32/next
17560 _Primitive-break-if-<=:  # (payload primitive)
17561     0x11/imm32/alloc-id:fake:payload
17562     0x11/imm32/alloc-id:fake
17563     _string-break-if-<=/imm32/name
17564     0/imm32/no-inouts
17565     0/imm32/no-inouts
17566     0/imm32/no-outputs
17567     0/imm32/no-outputs
17568     0x11/imm32/alloc-id:fake
17569     _string_0f_8e_jump_break/imm32/subx-name
17570     0/imm32/no-rm32
17571     0/imm32/no-r32
17572     0/imm32/no-imm32
17573     0/imm32/no-imm8
17574     0/imm32/no-disp32
17575     0/imm32/no-output
17576     0x11/imm32/alloc-id:fake
17577     _Primitive-break-if->/imm32/next
17578 _Primitive-break-if->:  # (payload primitive)
17579     0x11/imm32/alloc-id:fake:payload
17580     0x11/imm32/alloc-id:fake
17581     _string-break-if->/imm32/name
17582     0/imm32/no-inouts
17583     0/imm32/no-inouts
17584     0/imm32/no-outputs
17585     0/imm32/no-outputs
17586     0x11/imm32/alloc-id:fake
17587     _string_0f_8f_jump_break/imm32/subx-name
17588     0/imm32/no-rm32
17589     0/imm32/no-r32
17590     0/imm32/no-imm32
17591     0/imm32/no-imm8
17592     0/imm32/no-disp32
17593     0/imm32/no-output
17594     0x11/imm32/alloc-id:fake
17595     _Primitive-break/imm32/next
17596 _Primitive-break:  # (payload primitive)
17597     0x11/imm32/alloc-id:fake:payload
17598     0x11/imm32/alloc-id:fake
17599     _string-break/imm32/name
17600     0/imm32/no-inouts
17601     0/imm32/no-inouts
17602     0/imm32/no-outputs
17603     0/imm32/no-outputs
17604     0x11/imm32/alloc-id:fake
17605     _string_e9_jump_break/imm32/subx-name
17606     0/imm32/no-rm32
17607     0/imm32/no-r32
17608     0/imm32/no-imm32
17609     0/imm32/no-imm8
17610     0/imm32/no-disp32
17611     0/imm32/no-output
17612     0x11/imm32/alloc-id:fake
17613     _Primitive-loop-if-addr</imm32/next
17614 _Primitive-loop-if-addr<:  # (payload primitive)
17615     0x11/imm32/alloc-id:fake:payload
17616     0x11/imm32/alloc-id:fake
17617     _string-loop-if-addr</imm32/name
17618     0/imm32/no-inouts
17619     0/imm32/no-inouts
17620     0/imm32/no-outputs
17621     0/imm32/no-outputs
17622     0x11/imm32/alloc-id:fake
17623     _string_0f_82_jump_loop/imm32/subx-name
17624     0/imm32/no-rm32
17625     0/imm32/no-r32
17626     0/imm32/no-imm32
17627     0/imm32/no-imm8
17628     0/imm32/no-disp32
17629     0/imm32/no-output
17630     0x11/imm32/alloc-id:fake
17631     _Primitive-loop-if-addr>=/imm32/next
17632 _Primitive-loop-if-addr>=:  # (payload primitive)
17633     0x11/imm32/alloc-id:fake:payload
17634     0x11/imm32/alloc-id:fake
17635     _string-loop-if-addr>=/imm32/name
17636     0/imm32/no-inouts
17637     0/imm32/no-inouts
17638     0/imm32/no-outputs
17639     0/imm32/no-outputs
17640     0x11/imm32/alloc-id:fake
17641     _string_0f_83_jump_loop/imm32/subx-name
17642     0/imm32/no-rm32
17643     0/imm32/no-r32
17644     0/imm32/no-imm32
17645     0/imm32/no-imm8
17646     0/imm32/no-disp32
17647     0/imm32/no-output
17648     0x11/imm32/alloc-id:fake
17649     _Primitive-loop-if-=/imm32/next
17650 _Primitive-loop-if-=:  # (payload primitive)
17651     0x11/imm32/alloc-id:fake:payload
17652     0x11/imm32/alloc-id:fake
17653     _string-loop-if-=/imm32/name
17654     0/imm32/no-inouts
17655     0/imm32/no-inouts
17656     0/imm32/no-outputs
17657     0/imm32/no-outputs
17658     0x11/imm32/alloc-id:fake
17659     _string_0f_84_jump_loop/imm32/subx-name
17660     0/imm32/no-rm32
17661     0/imm32/no-r32
17662     0/imm32/no-imm32
17663     0/imm32/no-imm8
17664     0/imm32/no-disp32
17665     0/imm32/no-output
17666     0x11/imm32/alloc-id:fake
17667     _Primitive-loop-if-!=/imm32/next
17668 _Primitive-loop-if-!=:  # (payload primitive)
17669     0x11/imm32/alloc-id:fake:payload
17670     0x11/imm32/alloc-id:fake
17671     _string-loop-if-!=/imm32/name
17672     0/imm32/no-inouts
17673     0/imm32/no-inouts
17674     0/imm32/no-outputs
17675     0/imm32/no-outputs
17676     0x11/imm32/alloc-id:fake
17677     _string_0f_85_jump_loop/imm32/subx-name
17678     0/imm32/no-rm32
17679     0/imm32/no-r32
17680     0/imm32/no-imm32
17681     0/imm32/no-imm8
17682     0/imm32/no-disp32
17683     0/imm32/no-output
17684     0x11/imm32/alloc-id:fake
17685     _Primitive-loop-if-addr<=/imm32/next
17686 _Primitive-loop-if-addr<=:  # (payload primitive)
17687     0x11/imm32/alloc-id:fake:payload
17688     0x11/imm32/alloc-id:fake
17689     _string-loop-if-addr<=/imm32/name
17690     0/imm32/no-inouts
17691     0/imm32/no-inouts
17692     0/imm32/no-outputs
17693     0/imm32/no-outputs
17694     0x11/imm32/alloc-id:fake
17695     _string_0f_86_jump_loop/imm32/subx-name
17696     0/imm32/no-rm32
17697     0/imm32/no-r32
17698     0/imm32/no-imm32
17699     0/imm32/no-imm8
17700     0/imm32/no-disp32
17701     0/imm32/no-output
17702     0x11/imm32/alloc-id:fake
17703     _Primitive-loop-if-addr>/imm32/next
17704 _Primitive-loop-if-addr>:  # (payload primitive)
17705     0x11/imm32/alloc-id:fake:payload
17706     0x11/imm32/alloc-id:fake
17707     _string-loop-if-addr>/imm32/name
17708     0/imm32/no-inouts
17709     0/imm32/no-inouts
17710     0/imm32/no-outputs
17711     0/imm32/no-outputs
17712     0x11/imm32/alloc-id:fake
17713     _string_0f_87_jump_loop/imm32/subx-name
17714     0/imm32/no-rm32
17715     0/imm32/no-r32
17716     0/imm32/no-imm32
17717     0/imm32/no-imm8
17718     0/imm32/no-disp32
17719     0/imm32/no-output
17720     0x11/imm32/alloc-id:fake
17721     _Primitive-loop-if-</imm32/next
17722 _Primitive-loop-if-<:  # (payload primitive)
17723     0x11/imm32/alloc-id:fake:payload
17724     0x11/imm32/alloc-id:fake
17725     _string-loop-if-</imm32/name
17726     0/imm32/no-inouts
17727     0/imm32/no-inouts
17728     0/imm32/no-outputs
17729     0/imm32/no-outputs
17730     0x11/imm32/alloc-id:fake
17731     _string_0f_8c_jump_loop/imm32/subx-name
17732     0/imm32/no-rm32
17733     0/imm32/no-r32
17734     0/imm32/no-imm32
17735     0/imm32/no-imm8
17736     0/imm32/no-disp32
17737     0/imm32/no-output
17738     0x11/imm32/alloc-id:fake
17739     _Primitive-loop-if->=/imm32/next
17740 _Primitive-loop-if->=:  # (payload primitive)
17741     0x11/imm32/alloc-id:fake:payload
17742     0x11/imm32/alloc-id:fake
17743     _string-loop-if->=/imm32/name
17744     0/imm32/no-inouts
17745     0/imm32/no-inouts
17746     0/imm32/no-outputs
17747     0/imm32/no-outputs
17748     0x11/imm32/alloc-id:fake
17749     _string_0f_8d_jump_loop/imm32/subx-name
17750     0/imm32/no-rm32
17751     0/imm32/no-r32
17752     0/imm32/no-imm32
17753     0/imm32/no-imm8
17754     0/imm32/no-disp32
17755     0/imm32/no-output
17756     0x11/imm32/alloc-id:fake
17757     _Primitive-loop-if-<=/imm32/next
17758 _Primitive-loop-if-<=:  # (payload primitive)
17759     0x11/imm32/alloc-id:fake:payload
17760     0x11/imm32/alloc-id:fake
17761     _string-loop-if-<=/imm32/name
17762     0/imm32/no-inouts
17763     0/imm32/no-inouts
17764     0/imm32/no-outputs
17765     0/imm32/no-outputs
17766     0x11/imm32/alloc-id:fake
17767     _string_0f_8e_jump_loop/imm32/subx-name
17768     0/imm32/no-rm32
17769     0/imm32/no-r32
17770     0/imm32/no-imm32
17771     0/imm32/no-imm8
17772     0/imm32/no-disp32
17773     0/imm32/no-output
17774     0x11/imm32/alloc-id:fake
17775     _Primitive-loop-if->/imm32/next
17776 _Primitive-loop-if->:  # (payload primitive)
17777     0x11/imm32/alloc-id:fake:payload
17778     0x11/imm32/alloc-id:fake
17779     _string-loop-if->/imm32/name
17780     0/imm32/no-inouts
17781     0/imm32/no-inouts
17782     0/imm32/no-outputs
17783     0/imm32/no-outputs
17784     0x11/imm32/alloc-id:fake
17785     _string_0f_8f_jump_loop/imm32/subx-name
17786     0/imm32/no-rm32
17787     0/imm32/no-r32
17788     0/imm32/no-imm32
17789     0/imm32/no-imm8
17790     0/imm32/no-disp32
17791     0/imm32/no-output
17792     0x11/imm32/alloc-id:fake
17793     _Primitive-loop/imm32/next  # we probably don't need an unconditional break
17794 _Primitive-loop:  # (payload primitive)
17795     0x11/imm32/alloc-id:fake:payload
17796     0x11/imm32/alloc-id:fake
17797     _string-loop/imm32/name
17798     0/imm32/no-inouts
17799     0/imm32/no-inouts
17800     0/imm32/no-outputs
17801     0/imm32/no-outputs
17802     0x11/imm32/alloc-id:fake
17803     _string_e9_jump_loop/imm32/subx-name
17804     0/imm32/no-rm32
17805     0/imm32/no-r32
17806     0/imm32/no-imm32
17807     0/imm32/no-imm8
17808     0/imm32/no-disp32
17809     0/imm32/no-output
17810     0x11/imm32/alloc-id:fake
17811     _Primitive-break-if-addr<-named/imm32/next
17812 # - branches to named blocks
17813 _Primitive-break-if-addr<-named:  # (payload primitive)
17814     0x11/imm32/alloc-id:fake:payload
17815     0x11/imm32/alloc-id:fake
17816     _string-break-if-addr</imm32/name
17817     0x11/imm32/alloc-id:fake
17818     Single-lit-var/imm32/inouts
17819     0/imm32/no-outputs
17820     0/imm32/no-outputs
17821     0x11/imm32/alloc-id:fake
17822     _string_0f_82_jump_label/imm32/subx-name
17823     0/imm32/no-rm32
17824     0/imm32/no-r32
17825     0/imm32/no-imm32
17826     0/imm32/no-imm8
17827     1/imm32/disp32-is-first-inout
17828     0/imm32/no-output
17829     0x11/imm32/alloc-id:fake
17830     _Primitive-break-if-addr>=-named/imm32/next
17831 _Primitive-break-if-addr>=-named:  # (payload primitive)
17832     0x11/imm32/alloc-id:fake:payload
17833     0x11/imm32/alloc-id:fake
17834     _string-break-if-addr>=/imm32/name
17835     0x11/imm32/alloc-id:fake
17836     Single-lit-var/imm32/inouts
17837     0/imm32/no-outputs
17838     0/imm32/no-outputs
17839     0x11/imm32/alloc-id:fake
17840     _string_0f_83_jump_label/imm32/subx-name
17841     0/imm32/no-rm32
17842     0/imm32/no-r32
17843     0/imm32/no-imm32
17844     0/imm32/no-imm8
17845     1/imm32/disp32-is-first-inout
17846     0/imm32/no-output
17847     0x11/imm32/alloc-id:fake
17848     _Primitive-break-if-=-named/imm32/next
17849 _Primitive-break-if-=-named:  # (payload primitive)
17850     0x11/imm32/alloc-id:fake:payload
17851     0x11/imm32/alloc-id:fake
17852     _string-break-if-=/imm32/name
17853     0x11/imm32/alloc-id:fake
17854     Single-lit-var/imm32/inouts
17855     0/imm32/no-outputs
17856     0/imm32/no-outputs
17857     0x11/imm32/alloc-id:fake
17858     _string_0f_84_jump_label/imm32/subx-name
17859     0/imm32/no-rm32
17860     0/imm32/no-r32
17861     0/imm32/no-imm32
17862     0/imm32/no-imm8
17863     1/imm32/disp32-is-first-inout
17864     0/imm32/no-output
17865     0x11/imm32/alloc-id:fake
17866     _Primitive-break-if-!=-named/imm32/next
17867 _Primitive-break-if-!=-named:  # (payload primitive)
17868     0x11/imm32/alloc-id:fake:payload
17869     0x11/imm32/alloc-id:fake
17870     _string-break-if-!=/imm32/name
17871     0x11/imm32/alloc-id:fake
17872     Single-lit-var/imm32/inouts
17873     0/imm32/no-outputs
17874     0/imm32/no-outputs
17875     0x11/imm32/alloc-id:fake
17876     _string_0f_85_jump_label/imm32/subx-name
17877     0/imm32/no-rm32
17878     0/imm32/no-r32
17879     0/imm32/no-imm32
17880     0/imm32/no-imm8
17881     1/imm32/disp32-is-first-inout
17882     0/imm32/no-output
17883     0x11/imm32/alloc-id:fake
17884     _Primitive-break-if-addr<=-named/imm32/next
17885 _Primitive-break-if-addr<=-named:  # (payload primitive)
17886     0x11/imm32/alloc-id:fake:payload
17887     0x11/imm32/alloc-id:fake
17888     _string-break-if-addr<=/imm32/name
17889     0x11/imm32/alloc-id:fake
17890     Single-lit-var/imm32/inouts
17891     0/imm32/no-outputs
17892     0/imm32/no-outputs
17893     0x11/imm32/alloc-id:fake
17894     _string_0f_86_jump_label/imm32/subx-name
17895     0/imm32/no-rm32
17896     0/imm32/no-r32
17897     0/imm32/no-imm32
17898     0/imm32/no-imm8
17899     1/imm32/disp32-is-first-inout
17900     0/imm32/no-output
17901     0x11/imm32/alloc-id:fake
17902     _Primitive-break-if-addr>-named/imm32/next
17903 _Primitive-break-if-addr>-named:  # (payload primitive)
17904     0x11/imm32/alloc-id:fake:payload
17905     0x11/imm32/alloc-id:fake
17906     _string-break-if-addr>/imm32/name
17907     0x11/imm32/alloc-id:fake
17908     Single-lit-var/imm32/inouts
17909     0/imm32/no-outputs
17910     0/imm32/no-outputs
17911     0x11/imm32/alloc-id:fake
17912     _string_0f_87_jump_label/imm32/subx-name
17913     0/imm32/no-rm32
17914     0/imm32/no-r32
17915     0/imm32/no-imm32
17916     0/imm32/no-imm8
17917     1/imm32/disp32-is-first-inout
17918     0/imm32/no-output
17919     0x11/imm32/alloc-id:fake
17920     _Primitive-break-if-<-named/imm32/next
17921 _Primitive-break-if-<-named:  # (payload primitive)
17922     0x11/imm32/alloc-id:fake:payload
17923     0x11/imm32/alloc-id:fake
17924     _string-break-if-</imm32/name
17925     0x11/imm32/alloc-id:fake
17926     Single-lit-var/imm32/inouts
17927     0/imm32/no-outputs
17928     0/imm32/no-outputs
17929     0x11/imm32/alloc-id:fake
17930     _string_0f_8c_jump_label/imm32/subx-name
17931     0/imm32/no-rm32
17932     0/imm32/no-r32
17933     0/imm32/no-imm32
17934     0/imm32/no-imm8
17935     1/imm32/disp32-is-first-inout
17936     0/imm32/no-output
17937     0x11/imm32/alloc-id:fake
17938     _Primitive-break-if->=-named/imm32/next
17939 _Primitive-break-if->=-named:  # (payload primitive)
17940     0x11/imm32/alloc-id:fake:payload
17941     0x11/imm32/alloc-id:fake
17942     _string-break-if->=/imm32/name
17943     0x11/imm32/alloc-id:fake
17944     Single-lit-var/imm32/inouts
17945     0/imm32/no-outputs
17946     0/imm32/no-outputs
17947     0x11/imm32/alloc-id:fake
17948     _string_0f_8d_jump_label/imm32/subx-name
17949     0/imm32/no-rm32
17950     0/imm32/no-r32
17951     0/imm32/no-imm32
17952     0/imm32/no-imm8
17953     1/imm32/disp32-is-first-inout
17954     0/imm32/no-output
17955     0x11/imm32/alloc-id:fake
17956     _Primitive-break-if-<=-named/imm32/next
17957 _Primitive-break-if-<=-named:  # (payload primitive)
17958     0x11/imm32/alloc-id:fake:payload
17959     0x11/imm32/alloc-id:fake
17960     _string-break-if-<=/imm32/name
17961     0x11/imm32/alloc-id:fake
17962     Single-lit-var/imm32/inouts
17963     0/imm32/no-outputs
17964     0/imm32/no-outputs
17965     0x11/imm32/alloc-id:fake
17966     _string_0f_8e_jump_label/imm32/subx-name
17967     0/imm32/no-rm32
17968     0/imm32/no-r32
17969     0/imm32/no-imm32
17970     0/imm32/no-imm8
17971     1/imm32/disp32-is-first-inout
17972     0/imm32/no-output
17973     0x11/imm32/alloc-id:fake
17974     _Primitive-break-if->-named/imm32/next
17975 _Primitive-break-if->-named:  # (payload primitive)
17976     0x11/imm32/alloc-id:fake:payload
17977     0x11/imm32/alloc-id:fake
17978     _string-break-if->/imm32/name
17979     0x11/imm32/alloc-id:fake
17980     Single-lit-var/imm32/inouts
17981     0/imm32/no-outputs
17982     0/imm32/no-outputs
17983     0x11/imm32/alloc-id:fake
17984     _string_0f_8f_jump_label/imm32/subx-name
17985     0/imm32/no-rm32
17986     0/imm32/no-r32
17987     0/imm32/no-imm32
17988     0/imm32/no-imm8
17989     1/imm32/disp32-is-first-inout
17990     0/imm32/no-output
17991     0x11/imm32/alloc-id:fake
17992     _Primitive-break-named/imm32/next
17993 _Primitive-break-named:  # (payload primitive)
17994     0x11/imm32/alloc-id:fake:payload
17995     0x11/imm32/alloc-id:fake
17996     _string-break/imm32/name
17997     0x11/imm32/alloc-id:fake
17998     Single-lit-var/imm32/inouts
17999     0/imm32/no-outputs
18000     0/imm32/no-outputs
18001     0x11/imm32/alloc-id:fake
18002     _string_e9_jump_label/imm32/subx-name
18003     0/imm32/no-rm32
18004     0/imm32/no-r32
18005     0/imm32/no-imm32
18006     0/imm32/no-imm8
18007     1/imm32/disp32-is-first-inout
18008     0/imm32/no-output
18009     0x11/imm32/alloc-id:fake
18010     _Primitive-loop-if-addr<-named/imm32/next
18011 _Primitive-loop-if-addr<-named:  # (payload primitive)
18012     0x11/imm32/alloc-id:fake:payload
18013     0x11/imm32/alloc-id:fake
18014     _string-loop-if-addr</imm32/name
18015     0x11/imm32/alloc-id:fake
18016     Single-lit-var/imm32/inouts
18017     0/imm32/no-outputs
18018     0/imm32/no-outputs
18019     0x11/imm32/alloc-id:fake
18020     _string_0f_82_jump_label/imm32/subx-name
18021     0/imm32/no-rm32
18022     0/imm32/no-r32
18023     0/imm32/no-imm32
18024     0/imm32/no-imm8
18025     1/imm32/disp32-is-first-inout
18026     0/imm32/no-output
18027     0x11/imm32/alloc-id:fake
18028     _Primitive-loop-if-addr>=-named/imm32/next
18029 _Primitive-loop-if-addr>=-named:  # (payload primitive)
18030     0x11/imm32/alloc-id:fake:payload
18031     0x11/imm32/alloc-id:fake
18032     _string-loop-if-addr>=/imm32/name
18033     0x11/imm32/alloc-id:fake
18034     Single-lit-var/imm32/inouts
18035     0/imm32/no-outputs
18036     0/imm32/no-outputs
18037     0x11/imm32/alloc-id:fake
18038     _string_0f_83_jump_label/imm32/subx-name
18039     0/imm32/no-rm32
18040     0/imm32/no-r32
18041     0/imm32/no-imm32
18042     0/imm32/no-imm8
18043     1/imm32/disp32-is-first-inout
18044     0/imm32/no-output
18045     0x11/imm32/alloc-id:fake
18046     _Primitive-loop-if-=-named/imm32/next
18047 _Primitive-loop-if-=-named:  # (payload primitive)
18048     0x11/imm32/alloc-id:fake:payload
18049     0x11/imm32/alloc-id:fake
18050     _string-loop-if-=/imm32/name
18051     0x11/imm32/alloc-id:fake
18052     Single-lit-var/imm32/inouts
18053     0/imm32/no-outputs
18054     0/imm32/no-outputs
18055     0x11/imm32/alloc-id:fake
18056     _string_0f_84_jump_label/imm32/subx-name
18057     0/imm32/no-rm32
18058     0/imm32/no-r32
18059     0/imm32/no-imm32
18060     0/imm32/no-imm8
18061     1/imm32/disp32-is-first-inout
18062     0/imm32/no-output
18063     0x11/imm32/alloc-id:fake
18064     _Primitive-loop-if-!=-named/imm32/next
18065 _Primitive-loop-if-!=-named:  # (payload primitive)
18066     0x11/imm32/alloc-id:fake:payload
18067     0x11/imm32/alloc-id:fake
18068     _string-loop-if-!=/imm32/name
18069     0x11/imm32/alloc-id:fake
18070     Single-lit-var/imm32/inouts
18071     0/imm32/no-outputs
18072     0/imm32/no-outputs
18073     0x11/imm32/alloc-id:fake
18074     _string_0f_85_jump_label/imm32/subx-name
18075     0/imm32/no-rm32
18076     0/imm32/no-r32
18077     0/imm32/no-imm32
18078     0/imm32/no-imm8
18079     1/imm32/disp32-is-first-inout
18080     0/imm32/no-output
18081     0x11/imm32/alloc-id:fake
18082     _Primitive-loop-if-addr<=-named/imm32/next
18083 _Primitive-loop-if-addr<=-named:  # (payload primitive)
18084     0x11/imm32/alloc-id:fake:payload
18085     0x11/imm32/alloc-id:fake
18086     _string-loop-if-addr<=/imm32/name
18087     0x11/imm32/alloc-id:fake
18088     Single-lit-var/imm32/inouts
18089     0/imm32/no-outputs
18090     0/imm32/no-outputs
18091     0x11/imm32/alloc-id:fake
18092     _string_0f_86_jump_label/imm32/subx-name
18093     0/imm32/no-rm32
18094     0/imm32/no-r32
18095     0/imm32/no-imm32
18096     0/imm32/no-imm8
18097     1/imm32/disp32-is-first-inout
18098     0/imm32/no-output
18099     0x11/imm32/alloc-id:fake
18100     _Primitive-loop-if-addr>-named/imm32/next
18101 _Primitive-loop-if-addr>-named:  # (payload primitive)
18102     0x11/imm32/alloc-id:fake:payload
18103     0x11/imm32/alloc-id:fake
18104     _string-loop-if-addr>/imm32/name
18105     0x11/imm32/alloc-id:fake
18106     Single-lit-var/imm32/inouts
18107     0/imm32/no-outputs
18108     0/imm32/no-outputs
18109     0x11/imm32/alloc-id:fake
18110     _string_0f_87_jump_label/imm32/subx-name
18111     0/imm32/no-rm32
18112     0/imm32/no-r32
18113     0/imm32/no-imm32
18114     0/imm32/no-imm8
18115     1/imm32/disp32-is-first-inout
18116     0/imm32/no-output
18117     0x11/imm32/alloc-id:fake
18118     _Primitive-loop-if-<-named/imm32/next
18119 _Primitive-loop-if-<-named:  # (payload primitive)
18120     0x11/imm32/alloc-id:fake:payload
18121     0x11/imm32/alloc-id:fake
18122     _string-loop-if-</imm32/name
18123     0x11/imm32/alloc-id:fake
18124     Single-lit-var/imm32/inouts
18125     0/imm32/no-outputs
18126     0/imm32/no-outputs
18127     0x11/imm32/alloc-id:fake
18128     _string_0f_8c_jump_label/imm32/subx-name
18129     0/imm32/no-rm32
18130     0/imm32/no-r32
18131     0/imm32/no-imm32
18132     0/imm32/no-imm8
18133     1/imm32/disp32-is-first-inout
18134     0/imm32/no-output
18135     0x11/imm32/alloc-id:fake
18136     _Primitive-loop-if->=-named/imm32/next
18137 _Primitive-loop-if->=-named:  # (payload primitive)
18138     0x11/imm32/alloc-id:fake:payload
18139     0x11/imm32/alloc-id:fake
18140     _string-loop-if->=/imm32/name
18141     0x11/imm32/alloc-id:fake
18142     Single-lit-var/imm32/inouts
18143     0/imm32/no-outputs
18144     0/imm32/no-outputs
18145     0x11/imm32/alloc-id:fake
18146     _string_0f_8d_jump_label/imm32/subx-name
18147     0/imm32/no-rm32
18148     0/imm32/no-r32
18149     0/imm32/no-imm32
18150     0/imm32/no-imm8
18151     1/imm32/disp32-is-first-inout
18152     0/imm32/no-output
18153     0x11/imm32/alloc-id:fake
18154     _Primitive-loop-if-<=-named/imm32/next
18155 _Primitive-loop-if-<=-named:  # (payload primitive)
18156     0x11/imm32/alloc-id:fake:payload
18157     0x11/imm32/alloc-id:fake
18158     _string-loop-if-<=/imm32/name
18159     0x11/imm32/alloc-id:fake
18160     Single-lit-var/imm32/inouts
18161     0/imm32/no-outputs
18162     0/imm32/no-outputs
18163     0x11/imm32/alloc-id:fake
18164     _string_0f_8e_jump_label/imm32/subx-name
18165     0/imm32/no-rm32
18166     0/imm32/no-r32
18167     0/imm32/no-imm32
18168     0/imm32/no-imm8
18169     1/imm32/disp32-is-first-inout
18170     0/imm32/no-output
18171     0x11/imm32/alloc-id:fake
18172     _Primitive-loop-if->-named/imm32/next
18173 _Primitive-loop-if->-named:  # (payload primitive)
18174     0x11/imm32/alloc-id:fake:payload
18175     0x11/imm32/alloc-id:fake
18176     _string-loop-if->/imm32/name
18177     0x11/imm32/alloc-id:fake
18178     Single-lit-var/imm32/inouts
18179     0/imm32/no-outputs
18180     0/imm32/no-outputs
18181     0x11/imm32/alloc-id:fake
18182     _string_0f_8f_jump_label/imm32/subx-name
18183     0/imm32/no-rm32
18184     0/imm32/no-r32
18185     0/imm32/no-imm32
18186     0/imm32/no-imm8
18187     1/imm32/disp32-is-first-inout
18188     0/imm32/no-output
18189     0x11/imm32/alloc-id:fake
18190     _Primitive-loop-named/imm32/next  # we probably don't need an unconditional break
18191 _Primitive-loop-named:  # (payload primitive)
18192     0x11/imm32/alloc-id:fake:payload
18193     0x11/imm32/alloc-id:fake
18194     _string-loop/imm32/name
18195     0x11/imm32/alloc-id:fake
18196     Single-lit-var/imm32/inouts
18197     0/imm32/no-outputs
18198     0/imm32/no-outputs
18199     0x11/imm32/alloc-id:fake
18200     _string_e9_jump_label/imm32/subx-name
18201     0/imm32/no-rm32
18202     0/imm32/no-r32
18203     0/imm32/no-imm32
18204     0/imm32/no-imm8
18205     1/imm32/disp32-is-first-inout
18206     0/imm32/no-output
18207     0/imm32/next
18208     0/imm32/next
18209 
18210 # string literals for Mu instructions
18211 _string-add:  # (payload array byte)
18212     0x11/imm32/alloc-id:fake:payload
18213     # "add"
18214     0x3/imm32/size
18215     0x61/a 0x64/d 0x64/d
18216 _string-address:  # (payload array byte)
18217     0x11/imm32/alloc-id:fake:payload
18218     # "address"
18219     0x7/imm32/size
18220     0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
18221 _string-add-to:  # (payload array byte)
18222     0x11/imm32/alloc-id:fake:payload
18223     # "add-to"
18224     0x6/imm32/size
18225     0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
18226 _string-and:  # (payload array byte)
18227     0x11/imm32/alloc-id:fake:payload
18228     # "and"
18229     0x3/imm32/size
18230     0x61/a 0x6e/n 0x64/d
18231 _string-and-with:  # (payload array byte)
18232     0x11/imm32/alloc-id:fake:payload
18233     # "and-with"
18234     0x8/imm32/size
18235     0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
18236 _string-break:  # (payload array byte)
18237     0x11/imm32/alloc-id:fake:payload
18238     # "break"
18239     0x5/imm32/size
18240     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k
18241 _string-break-if-<:  # (payload array byte)
18242     0x11/imm32/alloc-id:fake:payload
18243     # "break-if-<"
18244     0xa/imm32/size
18245     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
18246 _string-break-if-<=:  # (payload array byte)
18247     0x11/imm32/alloc-id:fake:payload
18248     # "break-if-<="
18249     0xb/imm32/size
18250     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
18251 _string-break-if-=:  # (payload array byte)
18252     0x11/imm32/alloc-id:fake:payload
18253     # "break-if-="
18254     0xa/imm32/size
18255     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
18256 _string-break-if->:  # (payload array byte)
18257     0x11/imm32/alloc-id:fake:payload
18258     # "break-if->"
18259     0xa/imm32/size
18260     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
18261 _string-break-if->=:  # (payload array byte)
18262     0x11/imm32/alloc-id:fake:payload
18263     # "break-if->="
18264     0xb/imm32/size
18265     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
18266 _string-break-if-!=:  # (payload array byte)
18267     0x11/imm32/alloc-id:fake:payload
18268     # "break-if-!="
18269     0xb/imm32/size
18270     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
18271 _string-break-if-addr<:  # (payload array byte)
18272     0x11/imm32/alloc-id:fake:payload
18273     # "break-if-addr<"
18274     0xe/imm32/size
18275     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/<
18276 _string-break-if-addr<=:  # (payload array byte)
18277     0x11/imm32/alloc-id:fake:payload
18278     # "break-if-addr<="
18279     0xf/imm32/size
18280     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/=
18281 _string-break-if-addr>:  # (payload array byte)
18282     0x11/imm32/alloc-id:fake:payload
18283     # "break-if-addr>"
18284     0xe/imm32/size
18285     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/>
18286 _string-break-if-addr>=:  # (payload array byte)
18287     0x11/imm32/alloc-id:fake:payload
18288     # "break-if-addr>="
18289     0xf/imm32/size
18290     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/=
18291 _string-compare:  # (payload array byte)
18292     0x11/imm32/alloc-id:fake:payload
18293     # "compare"
18294     0x7/imm32/size
18295     0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
18296 _string-copy:  # (payload array byte)
18297     0x11/imm32/alloc-id:fake:payload
18298     # "copy"
18299     0x4/imm32/size
18300     0x63/c 0x6f/o 0x70/p 0x79/y
18301 _string-copy-to:  # (payload array byte)
18302     0x11/imm32/alloc-id:fake:payload
18303     # "copy-to"
18304     0x7/imm32/size
18305     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o
18306 _string-copy-byte:
18307     0x11/imm32/alloc-id:fake:payload
18308     # "copy-byte"
18309     0x9/imm32/size
18310     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e
18311 _string-copy-byte-to:
18312     0x11/imm32/alloc-id:fake:payload
18313     # "copy-byte-to"
18314     0xc/imm32/size
18315     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x74/t 0x6f/o
18316 _string-decrement:  # (payload array byte)
18317     0x11/imm32/alloc-id:fake:payload
18318     # "decrement"
18319     0x9/imm32/size
18320     0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
18321 _string-increment:  # (payload array byte)
18322     0x11/imm32/alloc-id:fake:payload
18323     # "increment"
18324     0x9/imm32/size
18325     0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
18326 _string-loop:  # (payload array byte)
18327     0x11/imm32/alloc-id:fake:payload
18328     # "loop"
18329     0x4/imm32/size
18330     0x6c/l 0x6f/o 0x6f/o 0x70/p
18331 _string-loop-if-<:  # (payload array byte)
18332     0x11/imm32/alloc-id:fake:payload
18333     # "loop-if-<"
18334     0x9/imm32/size
18335     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
18336 _string-loop-if-<=:  # (payload array byte)
18337     0x11/imm32/alloc-id:fake:payload
18338     # "loop-if-<="
18339     0xa/imm32/size
18340     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
18341 _string-loop-if-=:  # (payload array byte)
18342     0x11/imm32/alloc-id:fake:payload
18343     # "loop-if-="
18344     0x9/imm32/size
18345     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
18346 _string-loop-if->:  # (payload array byte)
18347     0x11/imm32/alloc-id:fake:payload
18348     # "loop-if->"
18349     0x9/imm32/size
18350     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
18351 _string-loop-if->=:  # (payload array byte)
18352     0x11/imm32/alloc-id:fake:payload
18353     # "loop-if->="
18354     0xa/imm32/size
18355     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
18356 _string-loop-if-!=:  # (payload array byte)
18357     0x11/imm32/alloc-id:fake:payload
18358     # "loop-if-!="
18359     0xa/imm32/size
18360     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
18361 _string-loop-if-addr<:  # (payload array byte)
18362     0x11/imm32/alloc-id:fake:payload
18363     # "loop-if-addr<"
18364     0xd/imm32/size
18365     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/<
18366 _string-loop-if-addr<=:  # (payload array byte)
18367     0x11/imm32/alloc-id:fake:payload
18368     # "loop-if-addr<="
18369     0xe/imm32/size
18370     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/=
18371 _string-loop-if-addr>:  # (payload array byte)
18372     0x11/imm32/alloc-id:fake:payload
18373     # "loop-if-addr>"
18374     0xd/imm32/size
18375     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/>
18376 _string-loop-if-addr>=:  # (payload array byte)
18377     0x11/imm32/alloc-id:fake:payload
18378     # "loop-if-addr>="
18379     0xe/imm32/size
18380     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/=
18381 _string-multiply:  # (payload array byte)
18382     0x11/imm32/alloc-id:fake:payload
18383     # "multiply"
18384     0x8/imm32/size
18385     0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
18386 _string-or:  # (payload array byte)
18387     0x11/imm32/alloc-id:fake:payload
18388     # "or"
18389     0x2/imm32/size
18390     0x6f/o 0x72/r
18391 _string-or-with:  # (payload array byte)
18392     0x11/imm32/alloc-id:fake:payload
18393     # "or-with"
18394     0x7/imm32/size
18395     0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
18396 _string-subtract:  # (payload array byte)
18397     0x11/imm32/alloc-id:fake:payload
18398     # "subtract"
18399     0x8/imm32/size
18400     0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
18401 _string-subtract-from:  # (payload array byte)
18402     0x11/imm32/alloc-id:fake:payload
18403     # "subtract-from"
18404     0xd/imm32/size
18405     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
18406 _string-xor:  # (payload array byte)
18407     0x11/imm32/alloc-id:fake:payload
18408     # "xor"
18409     0x3/imm32/size
18410     0x78/x 0x6f/o 0x72/r
18411 _string-xor-with:  # (payload array byte)
18412     0x11/imm32/alloc-id:fake:payload
18413     # "xor-with"
18414     0x8/imm32/size
18415     0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
18416 _string-shift-left:  # (payload array byte)
18417     0x11/imm32/alloc-id:fake:payload
18418     # "shift-left"
18419     0xa/imm32/size
18420     0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x6c/l 0x65/e 0x66/f 0x74/t
18421 _string-shift-right:  # (payload array byte)
18422     0x11/imm32/alloc-id:fake:payload
18423     # "shift-right"
18424     0xb/imm32/size
18425     0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x72/r 0x69/i 0x67/g 0x68/h 0x74/t
18426 _string-shift-right-signed:  # (payload array byte)
18427     0x11/imm32/alloc-id:fake:payload
18428     # "shift-right-signed"
18429     0x12/imm32/size
18430     0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x72/r 0x69/i 0x67/g 0x68/h 0x74/t 0x2d/dash 0x73/s 0x69/i 0x67/g 0x6e/n 0x65/e 0x64/d
18431 
18432 # string literals for SubX instructions
18433 _string_01_add_to:  # (payload array byte)
18434     0x11/imm32/alloc-id:fake:payload
18435     # "01/add-to"
18436     0x9/imm32/size
18437     0x30/0 0x31/1 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
18438 _string_03_add:  # (payload array byte)
18439     0x11/imm32/alloc-id:fake:payload
18440     # "03/add"
18441     0x6/imm32/size
18442     0x30/0 0x33/3 0x2f/slash 0x61/a 0x64/d 0x64/d
18443 _string_05_add_to_eax:  # (payload array byte)
18444     0x11/imm32/alloc-id:fake:payload
18445     # "05/add-to-eax"
18446     0xd/imm32/size
18447     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
18448 _string_09_or_with:  # (payload array byte)
18449     0x11/imm32/alloc-id:fake:payload
18450     # "09/or-with"
18451     0xa/imm32/size
18452     0x30/0 0x39/9 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
18453 _string_0b_or:  # (payload array byte)
18454     0x11/imm32/alloc-id:fake:payload
18455     # "0b/or"
18456     0x5/imm32/size
18457     0x30/0 0x62/b 0x2f/slash 0x6f/o 0x72/r
18458 _string_0d_or_with_eax:  # (payload array byte)
18459     0x11/imm32/alloc-id:fake:payload
18460     # "0d/or-with-eax"
18461     0xe/imm32/size
18462     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
18463 _string_0f_82_jump_label:  # (payload array byte)
18464     0x11/imm32/alloc-id:fake:payload
18465     # "0f 82/jump-if-addr<"
18466     0x13/imm32/size
18467     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/<
18468 _string_0f_82_jump_break:  # (payload array byte)
18469     0x11/imm32/alloc-id:fake:payload
18470     # "0f 82/jump-if-addr< break/disp32"
18471     0x20/imm32/size
18472     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
18473 _string_0f_82_jump_loop:  # (payload array byte)
18474     0x11/imm32/alloc-id:fake:payload
18475     # "0f 82/jump-if-addr< loop/disp32"
18476     0x1f/imm32/size
18477     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
18478 _string_0f_83_jump_label:  # (payload array byte)
18479     0x11/imm32/alloc-id:fake:payload
18480     # "0f 83/jump-if-addr>="
18481     0x14/imm32/size
18482     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/=
18483 _string_0f_83_jump_break:  # (payload array byte)
18484     0x11/imm32/alloc-id:fake:payload
18485     # "0f 83/jump-if-addr>= break/disp32"
18486     0x21/imm32/size
18487     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
18488 _string_0f_83_jump_loop:  # (payload array byte)
18489     0x11/imm32/alloc-id:fake:payload
18490     # "0f 83/jump-if-addr>= loop/disp32"
18491     0x20/imm32/size
18492     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
18493 _string_0f_84_jump_label:  # (payload array byte)
18494     0x11/imm32/alloc-id:fake:payload
18495     # "0f 84/jump-if-="
18496     0xf/imm32/size
18497     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/=
18498 _string_0f_84_jump_break:  # (payload array byte)
18499     0x11/imm32/alloc-id:fake:payload
18500     # "0f 84/jump-if-= break/disp32"
18501     0x1c/imm32/size
18502     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
18503 _string_0f_84_jump_loop:  # (payload array byte)
18504     0x11/imm32/alloc-id:fake:payload
18505     # "0f 84/jump-if-= loop/disp32"
18506     0x1b/imm32/size
18507     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
18508 _string_0f_85_jump_label:  # (payload array byte)
18509     0x11/imm32/alloc-id:fake:payload
18510     # "0f 85/jump-if-!="
18511     0x10/imm32/size
18512     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/=
18513 _string_0f_85_jump_break:  # (payload array byte)
18514     0x11/imm32/alloc-id:fake:payload
18515     # "0f 85/jump-if-!= break/disp32"
18516     0x1d/imm32/size
18517     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
18518 _string_0f_85_jump_loop:  # (payload array byte)
18519     0x11/imm32/alloc-id:fake:payload
18520     # "0f 85/jump-if-!= loop/disp32"
18521     0x1c/imm32/size
18522     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
18523 _string_0f_86_jump_label:  # (payload array byte)
18524     0x11/imm32/alloc-id:fake:payload
18525     # "0f 86/jump-if-addr<="
18526     0x14/imm32/size
18527     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/=
18528 _string_0f_86_jump_break:  # (payload array byte)
18529     0x11/imm32/alloc-id:fake:payload
18530     # "0f 86/jump-if-addr<= break/disp32"
18531     0x21/imm32/size
18532     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
18533 _string_0f_86_jump_loop:  # (payload array byte)
18534     0x11/imm32/alloc-id:fake:payload
18535     # "0f 86/jump-if-addr<= loop/disp32"
18536     0x20/imm32/size
18537     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
18538 _string_0f_87_jump_label:  # (payload array byte)
18539     0x11/imm32/alloc-id:fake:payload
18540     # "0f 87/jump-if-addr>"
18541     0x13/imm32/size
18542     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/>
18543 _string_0f_87_jump_break:  # (payload array byte)
18544     0x11/imm32/alloc-id:fake:payload
18545     # "0f 87/jump-if-addr> break/disp32"
18546     0x20/imm32/size
18547     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
18548 _string_0f_87_jump_loop:  # (payload array byte)
18549     0x11/imm32/alloc-id:fake:payload
18550     # "0f 87/jump-if-addr> loop/disp32"
18551     0x1f/imm32/size
18552     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
18553 _string_0f_8c_jump_label:  # (payload array byte)
18554     0x11/imm32/alloc-id:fake:payload
18555     # "0f 8c/jump-if-<"
18556     0xf/imm32/size
18557     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/<
18558 _string_0f_8c_jump_break:  # (payload array byte)
18559     0x11/imm32/alloc-id:fake:payload
18560     # "0f 8c/jump-if-< break/disp32"
18561     0x1c/imm32/size
18562     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
18563 _string_0f_8c_jump_loop:  # (payload array byte)
18564     0x11/imm32/alloc-id:fake:payload
18565     # "0f 8c/jump-if-< loop/disp32"
18566     0x1b/imm32/size
18567     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
18568 _string_0f_8d_jump_label:  # (payload array byte)
18569     0x11/imm32/alloc-id:fake:payload
18570     # "0f 8d/jump-if->="
18571     0x10/imm32/size
18572     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/=
18573 _string_0f_8d_jump_break:  # (payload array byte)
18574     0x11/imm32/alloc-id:fake:payload
18575     # "0f 8d/jump-if->= break/disp32"
18576     0x1d/imm32/size
18577     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
18578 _string_0f_8d_jump_loop:  # (payload array byte)
18579     0x11/imm32/alloc-id:fake:payload
18580     # "0f 8d/jump-if->= loop/disp32"
18581     0x1c/imm32/size
18582     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
18583 _string_0f_8e_jump_label:  # (payload array byte)
18584     0x11/imm32/alloc-id:fake:payload
18585     # "0f 8e/jump-if-<="
18586     0x10/imm32/size
18587     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/=
18588 _string_0f_8e_jump_break:  # (payload array byte)
18589     0x11/imm32/alloc-id:fake:payload
18590     # "0f 8e/jump-if-<= break/disp32"
18591     0x1d/imm32/size
18592     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
18593 _string_0f_8e_jump_loop:  # (payload array byte)
18594     0x11/imm32/alloc-id:fake:payload
18595     # "0f 8e/jump-if-<= loop/disp32"
18596     0x1c/imm32/size
18597     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
18598 _string_0f_8f_jump_label:  # (payload array byte)
18599     0x11/imm32/alloc-id:fake:payload
18600     # "0f 8f/jump-if->"
18601     0xf/imm32/size
18602     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/>
18603 _string_0f_8f_jump_break:  # (payload array byte)
18604     0x11/imm32/alloc-id:fake:payload
18605     # "0f 8f/jump-if-> break/disp32"
18606     0x1c/imm32/size
18607     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
18608 _string_0f_8f_jump_loop:  # (payload array byte)
18609     0x11/imm32/alloc-id:fake:payload
18610     # "0f 8f/jump-if-> loop/disp32"
18611     0x1b/imm32/size
18612     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
18613 _string_0f_af_multiply:  # (payload array byte)
18614     0x11/imm32/alloc-id:fake:payload
18615     # "0f af/multiply"
18616     0xe/imm32/size
18617     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
18618 _string_21_and_with:  # (payload array byte)
18619     0x11/imm32/alloc-id:fake:payload
18620     # "21/and-with"
18621     0xb/imm32/size
18622     0x32/2 0x31/1 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
18623 _string_23_and:  # (payload array byte)
18624     0x11/imm32/alloc-id:fake:payload
18625     # "23/and"
18626     0x6/imm32/size
18627     0x32/2 0x33/3 0x2f/slash 0x61/a 0x6e/n 0x64/d
18628 _string_25_and_with_eax:  # (payload array byte)
18629     0x11/imm32/alloc-id:fake:payload
18630     # "25/and-with-eax"
18631     0xf/imm32/size
18632     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
18633 _string_29_subtract_from:  # (payload array byte)
18634     0x11/imm32/alloc-id:fake:payload
18635     # "29/subtract-from"
18636     0x10/imm32/size
18637     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
18638 _string_2b_subtract:  # (payload array byte)
18639     0x11/imm32/alloc-id:fake:payload
18640     # "2b/subtract"
18641     0xb/imm32/size
18642     0x32/2 0x62/b 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
18643 _string_2d_subtract_from_eax:  # (payload array byte)
18644     0x11/imm32/alloc-id:fake:payload
18645     # "2d/subtract-from-eax"
18646     0x14/imm32/size
18647     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
18648 _string_31_xor_with:  # (payload array byte)
18649     0x11/imm32/alloc-id:fake:payload
18650     # "31/xor-with"
18651     0xb/imm32/size
18652     0x33/3 0x31/1 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
18653 _string_33_xor:  # (payload array byte)
18654     0x11/imm32/alloc-id:fake:payload
18655     # "33/xor"
18656     0x6/imm32/size
18657     0x33/3 0x33/3 0x2f/slash 0x78/x 0x6f/o 0x72/r
18658 _string_35_xor_with_eax:  # (payload array byte)
18659     0x11/imm32/alloc-id:fake:payload
18660     # "35/xor-with-eax"
18661     0xf/imm32/size
18662     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
18663 _string_39_compare->:  # (payload array byte)
18664     0x11/imm32/alloc-id:fake:payload
18665     # "39/compare->"
18666     0xc/imm32/size
18667     0x33/3 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x3e/>
18668 _string_3b_compare<-:  # (payload array byte)
18669     0x11/imm32/alloc-id:fake:payload
18670     # "3b/compare<-"
18671     0xc/imm32/size
18672     0x33/3 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x3c/< 0x2d/dash
18673 _string_3d_compare_eax_with:  # (payload array byte)
18674     0x11/imm32/alloc-id:fake:payload
18675     # "3d/compare-eax-with"
18676     0x13/imm32/size
18677     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
18678 _string_40_increment_eax:  # (payload array byte)
18679     0x11/imm32/alloc-id:fake:payload
18680     # "40/increment-eax"
18681     0x10/imm32/size
18682     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
18683 _string_41_increment_ecx:  # (payload array byte)
18684     0x11/imm32/alloc-id:fake:payload
18685     # "41/increment-ecx"
18686     0x10/imm32/size
18687     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
18688 _string_42_increment_edx:  # (payload array byte)
18689     0x11/imm32/alloc-id:fake:payload
18690     # "42/increment-edx"
18691     0x10/imm32/size
18692     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
18693 _string_43_increment_ebx:  # (payload array byte)
18694     0x11/imm32/alloc-id:fake:payload
18695     # "43/increment-ebx"
18696     0x10/imm32/size
18697     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
18698 _string_46_increment_esi:  # (payload array byte)
18699     0x11/imm32/alloc-id:fake:payload
18700     # "46/increment-esi"
18701     0x10/imm32/size
18702     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
18703 _string_47_increment_edi:  # (payload array byte)
18704     0x11/imm32/alloc-id:fake:payload
18705     # "47/increment-edi"
18706     0x10/imm32/size
18707     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
18708 _string_48_decrement_eax:  # (payload array byte)
18709     0x11/imm32/alloc-id:fake:payload
18710     # "48/decrement-eax"
18711     0x10/imm32/size
18712     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
18713 _string_49_decrement_ecx:  # (payload array byte)
18714     0x11/imm32/alloc-id:fake:payload
18715     # "49/decrement-ecx"
18716     0x10/imm32/size
18717     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
18718 _string_4a_decrement_edx:  # (payload array byte)
18719     0x11/imm32/alloc-id:fake:payload
18720     # "4a/decrement-edx"
18721     0x10/imm32/size
18722     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
18723 _string_4b_decrement_ebx:  # (payload array byte)
18724     0x11/imm32/alloc-id:fake:payload
18725     # "4b/decrement-ebx"
18726     0x10/imm32/size
18727     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
18728 _string_4e_decrement_esi:  # (payload array byte)
18729     0x11/imm32/alloc-id:fake:payload
18730     # "4e/decrement-esi"
18731     0x10/imm32/size
18732     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
18733 _string_4f_decrement_edi:  # (payload array byte)
18734     0x11/imm32/alloc-id:fake:payload
18735     # "4f/decrement-edi"
18736     0x10/imm32/size
18737     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
18738 _string_81_subop_add:  # (payload array byte)
18739     0x11/imm32/alloc-id:fake:payload
18740     # "81 0/subop/add"
18741     0xe/imm32/size
18742     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
18743 _string_81_subop_or:  # (payload array byte)
18744     0x11/imm32/alloc-id:fake:payload
18745     # "81 1/subop/or"
18746     0xd/imm32/size
18747     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
18748 _string_81_subop_and:  # (payload array byte)
18749     0x11/imm32/alloc-id:fake:payload
18750     # "81 4/subop/and"
18751     0xe/imm32/size
18752     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
18753 _string_81_subop_subtract:  # (payload array byte)
18754     0x11/imm32/alloc-id:fake:payload
18755     # "81 5/subop/subtract"
18756     0x13/imm32/size
18757     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
18758 _string_81_subop_xor:  # (payload array byte)
18759     0x11/imm32/alloc-id:fake:payload
18760     # "81 6/subop/xor"
18761     0xe/imm32/size
18762     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
18763 _string_81_subop_compare:  # (payload array byte)
18764     0x11/imm32/alloc-id:fake:payload
18765     # "81 7/subop/compare"
18766     0x12/imm32/size
18767     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
18768 _string_89_<-:  # (payload array byte)
18769     0x11/imm32/alloc-id:fake:payload
18770     # "89/<-"
18771     0x5/imm32/size
18772     0x38/8 0x39/9 0x2f/slash 0x3c/< 0x2d/dash
18773 _string_8b_->:  # (payload array byte)
18774     0x11/imm32/alloc-id:fake:payload
18775     # "8b/->"
18776     0x5/imm32/size
18777     0x38/8 0x62/b 0x2f/slash 0x2d/dash 0x3e/>
18778 _string_8a_copy_byte:
18779     0x11/imm32/alloc-id:fake:payload
18780     # "8a/byte->"
18781     0x9/imm32/size
18782     0x38/8 0x61/a 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x3e/>
18783 _string_88_copy_byte:
18784     0x11/imm32/alloc-id:fake:payload
18785     # "88/byte<-"
18786     0x9/imm32/size
18787     0x38/8 0x38/8 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x3c/< 0x2d/-
18788 _string_8d_copy_address:  # (payload array byte)
18789     0x11/imm32/alloc-id:fake:payload
18790     # "8d/copy-address"
18791     0xf/imm32/size
18792     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
18793 _string_b8_copy_to_eax:  # (payload array byte)
18794     0x11/imm32/alloc-id:fake:payload
18795     # "b8/copy-to-eax"
18796     0xe/imm32/size
18797     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
18798 _string_b9_copy_to_ecx:  # (payload array byte)
18799     0x11/imm32/alloc-id:fake:payload
18800     # "b9/copy-to-ecx"
18801     0xe/imm32/size
18802     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
18803 _string_ba_copy_to_edx:  # (payload array byte)
18804     0x11/imm32/alloc-id:fake:payload
18805     # "ba/copy-to-edx"
18806     0xe/imm32/size
18807     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
18808 _string_bb_copy_to_ebx:  # (payload array byte)
18809     0x11/imm32/alloc-id:fake:payload
18810     # "bb/copy-to-ebx"
18811     0xe/imm32/size
18812     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
18813 _string_be_copy_to_esi:  # (payload array byte)
18814     0x11/imm32/alloc-id:fake:payload
18815     # "be/copy-to-esi"
18816     0xe/imm32/size
18817     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
18818 _string_bf_copy_to_edi:  # (payload array byte)
18819     0x11/imm32/alloc-id:fake:payload
18820     # "bf/copy-to-edi"
18821     0xe/imm32/size
18822     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
18823 _string_c7_subop_copy:  # (payload array byte)
18824     0x11/imm32/alloc-id:fake:payload
18825     # "c7 0/subop/copy"
18826     0xf/imm32/size
18827     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
18828 _string_e9_jump_label:  # (payload array byte)
18829     0x11/imm32/alloc-id:fake:payload
18830     # "e9/jump"
18831     0x7/imm32/size
18832     0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p
18833 _string_e9_jump_break:  # (payload array byte)
18834     0x11/imm32/alloc-id:fake:payload
18835     # "e9/jump break/disp32"
18836     0x14/imm32/size
18837     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
18838 _string_e9_jump_loop:  # (payload array byte)
18839     0x11/imm32/alloc-id:fake:payload
18840     # "e9/jump loop/disp32"
18841     0x13/imm32/size
18842     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
18843 _string_ff_subop_increment:  # (payload array byte)
18844     0x11/imm32/alloc-id:fake:payload
18845     # "ff 0/subop/increment"
18846     0x14/imm32/size
18847     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
18848 _string_ff_subop_decrement:  # (payload array byte)
18849     0x11/imm32/alloc-id:fake:payload
18850     # "ff 1/subop/decrement"
18851     0x14/imm32/size
18852     0x66/f 0x66/f 0x20/space 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
18853 _string_c1_subop_shift_left:  # (payload array byte)
18854     0x11/imm32/alloc-id:fake:payload
18855     # "c1/shift 4/subop/left"
18856     0x15/imm32/size
18857     0x63/c 0x31/1 0x2f/slash 0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x20/space 0x34/4 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x6c/l 0x65/e 0x66/f 0x74/t
18858 _string_c1_subop_shift_right_padding_zeroes:  # (payload array byte)
18859     0x11/imm32/alloc-id:fake:payload
18860     # "c1/shift 5/subop/right-padding-zeroes"
18861     0x25/imm32/size
18862     0x63/c 0x31/1 0x2f/slash 0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x20/space 0x35/5 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x72/r 0x69/i 0x67/g 0x68/h 0x74/t 0x2d/dash 0x70/p 0x61/a 0x64/d 0x64/d 0x69/i 0x6e/n 0x67/g 0x2d/dash 0x7a/z 0x65/e 0x72/r 0x6f/o 0x65/e 0x73/s
18863 _string_c1_subop_shift_right_preserving_sign:  # (payload array byte)
18864     0x11/imm32/alloc-id:fake:payload
18865     # "c1/shift 7/subop/right-preserving-sign"
18866     0x26/imm32/size
18867     0x63/c 0x31/1 0x2f/slash 0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x20/space 0x37/7 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x72/r 0x69/i 0x67/g 0x68/h 0x74/t 0x2d/dash 0x70/p 0x72/r 0x65/e 0x73/s 0x65/e 0x72/r 0x76/v 0x69/i 0x6e/n 0x67/g 0x2d/dash 0x73/s 0x69/i 0x67/g 0x6e/n
18868 
18869 Single-int-var-in-mem:  # (payload list var)
18870     0x11/imm32/alloc-id:fake:payload
18871     0x11/imm32/alloc-id:fake
18872     Int-var-in-mem/imm32
18873     0/imm32/next
18874     0/imm32/next
18875 
18876 Int-var-in-mem:  # (payload var)
18877     0x11/imm32/alloc-id:fake:payload
18878     0/imm32/name
18879     0/imm32/name
18880     0x11/imm32/alloc-id:fake
18881     Type-int/imm32
18882     1/imm32/some-block-depth
18883     1/imm32/some-stack-offset
18884     0/imm32/no-register
18885     0/imm32/no-register
18886 
18887 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
18888 Single-byte-var-in-mem:  # (payload list var)
18889     0x11/imm32/alloc-id:fake:payload
18890     0x11/imm32/alloc-id:fake
18891     Byte-var-in-mem/imm32
18892     0/imm32/next
18893     0/imm32/next
18894 
18895 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
18896 Byte-var-in-mem:  # (payload var)
18897     0x11/imm32/alloc-id:fake:payload
18898     0/imm32/name
18899     0/imm32/name
18900     0x11/imm32/alloc-id:fake
18901     Type-byte/imm32
18902     1/imm32/some-block-depth
18903     1/imm32/some-stack-offset
18904     0/imm32/no-register
18905     0/imm32/no-register
18906 
18907 Two-args-int-stack-int-reg:  # (payload list var)
18908     0x11/imm32/alloc-id:fake:payload
18909     0x11/imm32/alloc-id:fake
18910     Int-var-in-mem/imm32
18911     0x11/imm32/alloc-id:fake
18912     Single-int-var-in-some-register/imm32/next
18913 
18914 Two-int-args-in-regs:  # (payload list var)
18915     0x11/imm32/alloc-id:fake:payload
18916     0x11/imm32/alloc-id:fake
18917     Int-var-in-some-register/imm32
18918     0x11/imm32/alloc-id:fake
18919     Single-int-var-in-some-register/imm32/next
18920 
18921 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
18922 Two-args-byte-stack-byte-reg:  # (payload list var)
18923     0x11/imm32/alloc-id:fake:payload
18924     0x11/imm32/alloc-id:fake
18925     Byte-var-in-mem/imm32
18926     0x11/imm32/alloc-id:fake
18927     Single-byte-var-in-some-register/imm32/next
18928 
18929 Two-args-int-reg-int-stack:  # (payload list var)
18930     0x11/imm32/alloc-id:fake:payload
18931     0x11/imm32/alloc-id:fake
18932     Int-var-in-some-register/imm32
18933     0x11/imm32/alloc-id:fake
18934     Single-int-var-in-mem/imm32/next
18935 
18936 Two-args-int-eax-int-literal:  # (payload list var)
18937     0x11/imm32/alloc-id:fake:payload
18938     0x11/imm32/alloc-id:fake
18939     Int-var-in-eax/imm32
18940     0x11/imm32/alloc-id:fake
18941     Single-lit-var/imm32/next
18942 
18943 Int-var-and-literal:  # (payload list var)
18944     0x11/imm32/alloc-id:fake:payload
18945     0x11/imm32/alloc-id:fake
18946     Int-var-in-mem/imm32
18947     0x11/imm32/alloc-id:fake
18948     Single-lit-var/imm32/next
18949 
18950 Int-var-in-register-and-literal:  # (payload list var)
18951     0x11/imm32/alloc-id:fake:payload
18952     0x11/imm32/alloc-id:fake
18953     Int-var-in-some-register/imm32
18954     0x11/imm32/alloc-id:fake
18955     Single-lit-var/imm32/next
18956 
18957 Single-int-var-in-some-register:  # (payload list var)
18958     0x11/imm32/alloc-id:fake:payload
18959     0x11/imm32/alloc-id:fake
18960     Int-var-in-some-register/imm32
18961     0/imm32/next
18962     0/imm32/next
18963 
18964 Single-addr-var-in-some-register:  # (payload list var)
18965     0x11/imm32/alloc-id:fake:payload
18966     0x11/imm32/alloc-id:fake
18967     Addr-var-in-some-register/imm32
18968     0/imm32/next
18969     0/imm32/next
18970 
18971 Single-byte-var-in-some-register:  # (payload list var)
18972     0x11/imm32/alloc-id:fake:payload
18973     0x11/imm32/alloc-id:fake
18974     Byte-var-in-some-register/imm32
18975     0/imm32/next
18976     0/imm32/next
18977 
18978 Int-var-in-some-register:  # (payload var)
18979     0x11/imm32/alloc-id:fake:payload
18980     0/imm32/name
18981     0/imm32/name
18982     0x11/imm32/alloc-id:fake
18983     Type-int/imm32
18984     1/imm32/some-block-depth
18985     0/imm32/no-stack-offset
18986     0x11/imm32/alloc-id:fake
18987     Any-register/imm32
18988 
18989 Any-register:  # (payload array byte)
18990     0x11/imm32/alloc-id:fake:payload
18991     1/imm32/size
18992     # data
18993     2a/asterisk
18994 
18995 Addr-var-in-some-register:  # (payload var)
18996     0x11/imm32/alloc-id:fake:payload
18997     0/imm32/name
18998     0/imm32/name
18999     0x11/imm32/alloc-id:fake
19000     Type-addr/imm32
19001     1/imm32/some-block-depth
19002     0/imm32/no-stack-offset
19003     0x11/imm32/alloc-id:fake
19004     Any-register/imm32
19005 
19006 Byte-var-in-some-register:  # (payload var)
19007     0x11/imm32/alloc-id:fake:payload
19008     0/imm32/name
19009     0/imm32/name
19010     0x11/imm32/alloc-id:fake
19011     Type-byte/imm32
19012     1/imm32/some-block-depth
19013     0/imm32/no-stack-offset
19014     0x11/imm32/alloc-id:fake
19015     Any-register/imm32
19016 
19017 Single-int-var-in-eax:  # (payload list var)
19018     0x11/imm32/alloc-id:fake:payload
19019     0x11/imm32/alloc-id:fake
19020     Int-var-in-eax/imm32
19021     0/imm32/next
19022     0/imm32/next
19023 
19024 Int-var-in-eax:
19025     0x11/imm32/alloc-id:fake:payload
19026     0/imm32/name
19027     0/imm32/name
19028     0x11/imm32/alloc-id:fake
19029     Type-int/imm32
19030     1/imm32/some-block-depth
19031     0/imm32/no-stack-offset
19032     0x11/imm32/alloc-id:fake
19033     $Register-eax/imm32
19034 
19035 Single-int-var-in-ecx:  # (payload list var)
19036     0x11/imm32/alloc-id:fake:payload
19037     0x11/imm32/alloc-id:fake
19038     Int-var-in-ecx/imm32
19039     0/imm32/next
19040     0/imm32/next
19041 
19042 Int-var-in-ecx:
19043     0x11/imm32/alloc-id:fake:payload
19044     0/imm32/name
19045     0/imm32/name
19046     0x11/imm32/alloc-id:fake
19047     Type-int/imm32
19048     1/imm32/some-block-depth
19049     0/imm32/no-stack-offset
19050     0x11/imm32/alloc-id:fake
19051     $Register-ecx/imm32/register
19052 
19053 Single-int-var-in-edx:  # (payload list var)
19054     0x11/imm32/alloc-id:fake:payload
19055     0x11/imm32/alloc-id:fake
19056     Int-var-in-edx/imm32
19057     0/imm32/next
19058     0/imm32/next
19059 
19060 Int-var-in-edx:  # (payload list var)
19061     0x11/imm32/alloc-id:fake:payload
19062     0/imm32/name
19063     0/imm32/name
19064     0x11/imm32/alloc-id:fake
19065     Type-int/imm32
19066     1/imm32/some-block-depth
19067     0/imm32/no-stack-offset
19068     0x11/imm32/alloc-id:fake
19069     $Register-edx/imm32/register
19070 
19071 Single-int-var-in-ebx:  # (payload list var)
19072     0x11/imm32/alloc-id:fake:payload
19073     0x11/imm32/alloc-id:fake
19074     Int-var-in-ebx/imm32
19075     0/imm32/next
19076     0/imm32/next
19077 
19078 Int-var-in-ebx:  # (payload list var)
19079     0x11/imm32/alloc-id:fake:payload
19080     0/imm32/name
19081     0/imm32/name
19082     0x11/imm32/alloc-id:fake
19083     Type-int/imm32
19084     1/imm32/some-block-depth
19085     0/imm32/no-stack-offset
19086     0x11/imm32/alloc-id:fake
19087     $Register-ebx/imm32/register
19088 
19089 Single-int-var-in-esi:  # (payload list var)
19090     0x11/imm32/alloc-id:fake:payload
19091     0x11/imm32/alloc-id:fake
19092     Int-var-in-esi/imm32
19093     0/imm32/next
19094     0/imm32/next
19095 
19096 Int-var-in-esi:  # (payload list var)
19097     0x11/imm32/alloc-id:fake:payload
19098     0/imm32/name
19099     0/imm32/name
19100     0x11/imm32/alloc-id:fake
19101     Type-int/imm32
19102     1/imm32/some-block-depth
19103     0/imm32/no-stack-offset
19104     0x11/imm32/alloc-id:fake
19105     $Register-esi/imm32/register
19106 
19107 Single-int-var-in-edi:  # (payload list var)
19108     0x11/imm32/alloc-id:fake:payload
19109     0x11/imm32/alloc-id:fake
19110     Int-var-in-edi/imm32
19111     0/imm32/next
19112     0/imm32/next
19113 
19114 Int-var-in-edi:  # (payload list var)
19115     0x11/imm32/alloc-id:fake:payload
19116     0/imm32/name
19117     0/imm32/name
19118     0x11/imm32/alloc-id:fake
19119     Type-int/imm32
19120     1/imm32/some-block-depth
19121     0/imm32/no-stack-offset
19122     0x11/imm32/alloc-id:fake
19123     $Register-edi/imm32/register
19124 
19125 Single-lit-var:  # (payload list var)
19126     0x11/imm32/alloc-id:fake:payload
19127     0x11/imm32/alloc-id:fake
19128     Lit-var/imm32
19129     0/imm32/next
19130     0/imm32/next
19131 
19132 Lit-var:  # (payload var)
19133     0x11/imm32/alloc-id:fake:payload
19134     0/imm32/name
19135     0/imm32/name
19136     0x11/imm32/alloc-id:fake
19137     Type-literal/imm32
19138     1/imm32/some-block-depth
19139     0/imm32/no-stack-offset
19140     0/imm32/no-register
19141     0/imm32/no-register
19142 
19143 Type-int:  # (payload type-tree)
19144     0x11/imm32/alloc-id:fake:payload
19145     1/imm32/is-atom
19146     1/imm32/value:int
19147     0/imm32/left:unused
19148     0/imm32/right:null
19149     0/imm32/right:null
19150 
19151 Type-literal:  # (payload type-tree)
19152     0x11/imm32/alloc-id:fake:payload
19153     1/imm32/is-atom
19154     0/imm32/value:literal
19155     0/imm32/left:unused
19156     0/imm32/right:null
19157     0/imm32/right:null
19158 
19159 Type-addr:  # (payload type-tree)
19160     0x11/imm32/alloc-id:fake:payload
19161     1/imm32/is-atom
19162     2/imm32/value:addr
19163     0/imm32/left:unused
19164     0/imm32/right:null
19165     0/imm32/right:null
19166 
19167 Type-byte:  # (payload type-tree)
19168     0x11/imm32/alloc-id:fake:payload
19169     1/imm32/is-atom
19170     8/imm32/value:byte
19171     0/imm32/left:unused
19172     0/imm32/right:null
19173     0/imm32/right:null
19174 
19175 == code
19176 emit-subx-primitive:  # out: (addr buffered-file), stmt: (addr stmt), primitive: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
19177     # . prologue
19178     55/push-ebp
19179     89/<- %ebp 4/r32/esp
19180     # . save registers
19181     50/push-eax
19182     51/push-ecx
19183     # ecx = primitive
19184     8b/-> *(ebp+0x10) 1/r32/ecx
19185     # emit primitive name
19186     (emit-indent *(ebp+8) *Curr-block-depth)
19187     (lookup *(ecx+0x18) *(ecx+0x1c))  # Primitive-subx-name Primitive-subx-name => eax
19188     (write-buffered *(ebp+8) %eax)
19189     # emit rm32 if necessary
19190     (emit-subx-rm32 *(ebp+8) *(ecx+0x20) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-rm32
19191     # emit r32 if necessary
19192     (emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc))  # Primitive-subx-r32
19193     # emit imm32 if necessary
19194     (emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc))  # Primitive-subx-imm32
19195     # emit imm8 if necessary
19196     (emit-subx-imm8 *(ebp+8) *(ecx+0x2c) *(ebp+0xc))  # Primitive-subx-imm8
19197     # emit disp32 if necessary
19198     (emit-subx-disp32 *(ebp+8) *(ecx+0x30) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-disp32
19199     (write-buffered *(ebp+8) Newline)
19200 $emit-subx-primitive:end:
19201     # . restore registers
19202     59/pop-to-ecx
19203     58/pop-to-eax
19204     # . epilogue
19205     89/<- %esp 5/r32/ebp
19206     5d/pop-to-ebp
19207     c3/return
19208 
19209 emit-subx-rm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
19210     # . prologue
19211     55/push-ebp
19212     89/<- %ebp 4/r32/esp
19213     # . save registers
19214     50/push-eax
19215     # if (l == 0) return
19216     81 7/subop/compare *(ebp+0xc) 0/imm32
19217     74/jump-if-= $emit-subx-rm32:end/disp8
19218     # var v/eax: (addr stmt-var)
19219     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
19220     (emit-subx-var-as-rm32 *(ebp+8) %eax)
19221 $emit-subx-rm32:end:
19222     # . restore registers
19223     58/pop-to-eax
19224     # . epilogue
19225     89/<- %esp 5/r32/ebp
19226     5d/pop-to-ebp
19227     c3/return
19228 
19229 get-stmt-operand-from-arg-location:  # stmt: (addr stmt), l: arg-location, err: (addr buffered-file), ed: (addr exit-descriptor) -> var/eax: (addr stmt-var)
19230     # . prologue
19231     55/push-ebp
19232     89/<- %ebp 4/r32/esp
19233     # . save registers
19234     51/push-ecx
19235     # eax = l
19236     8b/-> *(ebp+0xc) 0/r32/eax
19237     # ecx = stmt
19238     8b/-> *(ebp+8) 1/r32/ecx
19239     # if (l == 1) return stmt->inouts
19240     {
19241       3d/compare-eax-and 1/imm32
19242       75/jump-if-!= break/disp8
19243 $get-stmt-operand-from-arg-location:1:
19244       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
19245       eb/jump $get-stmt-operand-from-arg-location:end/disp8
19246     }
19247     # if (l == 2) return stmt->inouts->next
19248     {
19249       3d/compare-eax-and 2/imm32
19250       75/jump-if-!= break/disp8
19251 $get-stmt-operand-from-arg-location:2:
19252       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
19253       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
19254       eb/jump $get-stmt-operand-from-arg-location:end/disp8
19255     }
19256     # if (l == 3) return stmt->outputs
19257     {
19258       3d/compare-eax-and 3/imm32
19259       75/jump-if-!= break/disp8
19260 $get-stmt-operand-from-arg-location:3:
19261       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
19262       eb/jump $get-stmt-operand-from-arg-location:end/disp8
19263     }
19264     # abort
19265     e9/jump $get-stmt-operand-from-arg-location:abort/disp32
19266 $get-stmt-operand-from-arg-location:end:
19267     # . restore registers
19268     59/pop-to-ecx
19269     # . epilogue
19270     89/<- %esp 5/r32/ebp
19271     5d/pop-to-ebp
19272     c3/return
19273 
19274 $get-stmt-operand-from-arg-location:abort:
19275     # error("invalid arg-location " eax)
19276     (write-buffered *(ebp+0x10) "invalid arg-location ")
19277     (write-int32-hex-buffered *(ebp+0x10) %eax)
19278     (write-buffered *(ebp+0x10) Newline)
19279     (flush *(ebp+0x10))
19280     (stop *(ebp+0x14) 1)
19281     # never gets here
19282 
19283 emit-subx-r32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
19284     # . prologue
19285     55/push-ebp
19286     89/<- %ebp 4/r32/esp
19287     # . save registers
19288     50/push-eax
19289     51/push-ecx
19290     # if (l == 0) return
19291     81 7/subop/compare *(ebp+0xc) 0/imm32
19292     0f 84/jump-if-= $emit-subx-r32:end/disp32
19293     # var v/eax: (addr stmt-var)
19294     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
19295     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
19296     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
19297     (maybe-get Mu-registers %eax 0xc)  # => eax: (addr register-index)
19298     (write-buffered *(ebp+8) Space)
19299     (write-int32-hex-buffered *(ebp+8) *eax)
19300     (write-buffered *(ebp+8) "/r32")
19301 $emit-subx-r32:end:
19302     # . restore registers
19303     59/pop-to-ecx
19304     58/pop-to-eax
19305     # . epilogue
19306     89/<- %esp 5/r32/ebp
19307     5d/pop-to-ebp
19308     c3/return
19309 
19310 emit-subx-imm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
19311     # . prologue
19312     55/push-ebp
19313     89/<- %ebp 4/r32/esp
19314     # . save registers
19315     50/push-eax
19316     51/push-ecx
19317     # if (l == 0) return
19318     81 7/subop/compare *(ebp+0xc) 0/imm32
19319     0f 84/jump-if-= $emit-subx-imm32:end/disp32
19320     # var v/eax: (handle var)
19321     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
19322     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
19323     (lookup *eax *(eax+4))  # Var-name Var-name => eax
19324     (write-buffered *(ebp+8) Space)
19325     (write-buffered *(ebp+8) %eax)
19326     (write-buffered *(ebp+8) "/imm32")
19327 $emit-subx-imm32:end:
19328     # . restore registers
19329     59/pop-to-ecx
19330     58/pop-to-eax
19331     # . epilogue
19332     89/<- %esp 5/r32/ebp
19333     5d/pop-to-ebp
19334     c3/return
19335 
19336 emit-subx-imm8:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
19337     # . prologue
19338     55/push-ebp
19339     89/<- %ebp 4/r32/esp
19340     # . save registers
19341     50/push-eax
19342     51/push-ecx
19343     # if (l == 0) return
19344     81 7/subop/compare *(ebp+0xc) 0/imm32
19345     0f 84/jump-if-= $emit-subx-imm32:end/disp32
19346     # var v/eax: (handle var)
19347     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
19348     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
19349     (lookup *eax *(eax+4))  # Var-name Var-name => eax
19350     (write-buffered *(ebp+8) Space)
19351     (write-buffered *(ebp+8) %eax)
19352     (write-buffered *(ebp+8) "/imm8")
19353 $emit-subx-imm8:end:
19354     # . restore registers
19355     59/pop-to-ecx
19356     58/pop-to-eax
19357     # . epilogue
19358     89/<- %esp 5/r32/ebp
19359     5d/pop-to-ebp
19360     c3/return
19361 
19362 emit-subx-disp32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
19363     # . prologue
19364     55/push-ebp
19365     89/<- %ebp 4/r32/esp
19366     # . save registers
19367     50/push-eax
19368     51/push-ecx
19369     # if (location == 0) return
19370     81 7/subop/compare *(ebp+0xc) 0/imm32
19371     0f 84/jump-if-= $emit-subx-disp32:end/disp32
19372     # var v/eax: (addr stmt-var)
19373     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
19374     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
19375     (lookup *eax *(eax+4))  # Var-name Var-name => eax
19376     (write-buffered *(ebp+8) Space)
19377     (write-buffered *(ebp+8) %eax)
19378     # hack: if instruction operation starts with "break", emit ":break"
19379     # var name/ecx: (addr array byte) = lookup(stmt->operation)
19380     8b/-> *(ebp+0x10) 0/r32/eax
19381     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
19382     89/<- %ecx 0/r32/eax
19383     {
19384       (string-starts-with? %ecx "break")  # => eax
19385       3d/compare-eax-and 0/imm32/false
19386       74/jump-if-= break/disp8
19387       (write-buffered *(ebp+8) ":break")
19388     }
19389     # hack: if instruction operation starts with "loop", emit ":loop"
19390     {
19391       (string-starts-with? %ecx "loop")  # => eax
19392       3d/compare-eax-and 0/imm32/false
19393       74/jump-if-= break/disp8
19394       (write-buffered *(ebp+8) ":loop")
19395     }
19396     (write-buffered *(ebp+8) "/disp32")
19397 $emit-subx-disp32:end:
19398     # . restore registers
19399     59/pop-to-ecx
19400     58/pop-to-eax
19401     # . epilogue
19402     89/<- %esp 5/r32/ebp
19403     5d/pop-to-ebp
19404     c3/return
19405 
19406 emit-call:  # out: (addr buffered-file), stmt: (addr stmt)
19407     # . prologue
19408     55/push-ebp
19409     89/<- %ebp 4/r32/esp
19410     # . save registers
19411     50/push-eax
19412     51/push-ecx
19413     #
19414     (emit-indent *(ebp+8) *Curr-block-depth)
19415     (write-buffered *(ebp+8) "(")
19416     # ecx = stmt
19417     8b/-> *(ebp+0xc) 1/r32/ecx
19418     # - emit function name
19419     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
19420     (write-buffered *(ebp+8) %eax)
19421     # - emit arguments
19422     # var curr/eax: (addr stmt-var) = lookup(stmt->inouts)
19423     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
19424     {
19425       # if (curr == null) break
19426       3d/compare-eax-and 0/imm32
19427       74/jump-if-= break/disp8
19428       #
19429       (emit-subx-call-operand *(ebp+8) %eax)
19430       # curr = lookup(curr->next)
19431       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
19432       eb/jump loop/disp8
19433     }
19434     #
19435     (write-buffered *(ebp+8) ")\n")
19436 $emit-call:end:
19437     # . restore registers
19438     59/pop-to-ecx
19439     58/pop-to-eax
19440     # . epilogue
19441     89/<- %esp 5/r32/ebp
19442     5d/pop-to-ebp
19443     c3/return
19444 
19445 emit-subx-call-operand:  # out: (addr buffered-file), s: (addr stmt-var)
19446     # shares code with emit-subx-var-as-rm32
19447     # . prologue
19448     55/push-ebp
19449     89/<- %ebp 4/r32/esp
19450     # . save registers
19451     50/push-eax
19452     51/push-ecx
19453     56/push-esi
19454     # ecx = s
19455     8b/-> *(ebp+0xc) 1/r32/ecx
19456     # var operand/esi: (addr var) = lookup(s->value)
19457     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
19458     89/<- %esi 0/r32/eax
19459     # if (operand->register && !s->is-deref?) emit "%__"
19460     {
19461 $emit-subx-call-operand:check-for-register-direct:
19462       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19463       74/jump-if-= break/disp8
19464       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19465       75/jump-if-!= break/disp8
19466 $emit-subx-call-operand:register-direct:
19467       (write-buffered *(ebp+8) " %")
19468       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
19469       (write-buffered *(ebp+8) %eax)
19470       e9/jump $emit-subx-call-operand:end/disp32
19471     }
19472     # else if (operand->register && s->is-deref?) emit "*__"
19473     {
19474 $emit-subx-call-operand:check-for-register-indirect:
19475       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19476       74/jump-if-= break/disp8
19477       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19478       74/jump-if-= break/disp8
19479 $emit-subx-call-operand:register-indirect:
19480       (emit-subx-call-operand-register-indirect *(ebp+8) %esi)
19481       e9/jump $emit-subx-call-operand:end/disp32
19482     }
19483     # else if (operand->stack-offset) emit "*(ebp+__)"
19484     {
19485       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
19486       74/jump-if-= break/disp8
19487 $emit-subx-call-operand:stack:
19488       (emit-subx-call-operand-stack *(ebp+8) %esi)
19489       e9/jump $emit-subx-call-operand:end/disp32
19490     }
19491     # else if (operand->type == literal) emit "__"
19492     {
19493       (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
19494       81 7/subop/compare *(eax+4) 0/imm32  # Type-tree-left
19495       75/jump-if-!= break/disp8
19496 $emit-subx-call-operand:literal:
19497       (write-buffered *(ebp+8) Space)
19498       (lookup *esi *(esi+4))  # Var-name Var-name => eax
19499       (write-buffered *(ebp+8) %eax)
19500     }
19501 $emit-subx-call-operand:end:
19502     # . restore registers
19503     5e/pop-to-esi
19504     59/pop-to-ecx
19505     58/pop-to-eax
19506     # . epilogue
19507     89/<- %esp 5/r32/ebp
19508     5d/pop-to-ebp
19509     c3/return
19510 
19511 emit-subx-call-operand-register-indirect:  # out: (addr buffered-file), v: (addr var)
19512     # . prologue
19513     55/push-ebp
19514     89/<- %ebp 4/r32/esp
19515     # . save registers
19516     50/push-eax
19517     51/push-ecx
19518     56/push-esi
19519     # esi = v
19520     8b/-> *(ebp+0xc) 6/r32/esi
19521     # var size/ecx: int = size-of-deref(v)
19522     (size-of-deref %esi)  # => eax
19523     89/<- %ecx 0/r32/eax
19524     # var reg-name/esi: (addr array byte) = lookup(v->register)
19525     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
19526     89/<- %esi 0/r32/eax
19527     # TODO: assert size is a multiple of 4
19528     # var i/eax: int = 0
19529     b8/copy-to-eax 0/imm32
19530     {
19531 $emit-subx-call-operand-register-indirect:loop:
19532       # if (i >= size) break
19533       39/compare %eax 1/r32/ecx
19534       7d/jump-if->= break/disp8
19535       # emit " *(" v->register "+" i ")"
19536       (write-buffered *(ebp+8) " *(")
19537       (write-buffered *(ebp+8) %esi)
19538       (write-buffered *(ebp+8) "+")
19539       (write-int32-hex-buffered *(ebp+8) %eax)
19540       (write-buffered *(ebp+8) ")")
19541       # i += 4
19542       05/add-to-eax 4/imm32
19543       #
19544       eb/jump loop/disp8
19545     }
19546 $emit-subx-call-operand-register-indirect:end:
19547     # . restore registers
19548     5e/pop-to-esi
19549     59/pop-to-ecx
19550     58/pop-to-eax
19551     # . epilogue
19552     89/<- %esp 5/r32/ebp
19553     5d/pop-to-ebp
19554     c3/return
19555 
19556 emit-subx-call-operand-stack:  # out: (addr buffered-file), v: (addr var)
19557     # . prologue
19558     55/push-ebp
19559     89/<- %ebp 4/r32/esp
19560     # . save registers
19561     50/push-eax
19562     51/push-ecx
19563     56/push-esi
19564     # esi = v
19565     8b/-> *(ebp+0xc) 6/r32/esi
19566     # var curr/ecx: int = v->offset
19567     8b/-> *(esi+0x14) 1/r32/ecx  # Var-offset
19568     # var max/eax: int = v->offset + size-of(v)
19569     (size-of %esi)  # => eax
19570     # TODO: assert size is a multiple of 4
19571     01/add-to %eax 1/r32/ecx
19572     {
19573 $emit-subx-call-operand-stack:loop:
19574       # if (curr >= max) break
19575       39/compare %ecx 0/r32/eax
19576       7d/jump-if->= break/disp8
19577       # emit " *(ebp+" curr ")"
19578       (write-buffered *(ebp+8) " *(ebp+")
19579       (write-int32-hex-buffered *(ebp+8) %ecx)
19580       (write-buffered *(ebp+8) ")")
19581       # i += 4
19582       81 0/subop/add %ecx 4/imm32
19583       #
19584       eb/jump loop/disp8
19585     }
19586 $emit-subx-call-operand-stack:end:
19587     # . restore registers
19588     5e/pop-to-esi
19589     59/pop-to-ecx
19590     58/pop-to-eax
19591     # . epilogue
19592     89/<- %esp 5/r32/ebp
19593     5d/pop-to-ebp
19594     c3/return
19595 
19596 emit-subx-var-as-rm32:  # out: (addr buffered-file), s: (addr stmt-var)
19597     # . prologue
19598     55/push-ebp
19599     89/<- %ebp 4/r32/esp
19600     # . save registers
19601     50/push-eax
19602     51/push-ecx
19603     56/push-esi
19604     # ecx = s
19605     8b/-> *(ebp+0xc) 1/r32/ecx
19606     # var operand/esi: (addr var) = lookup(s->value)
19607     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
19608     89/<- %esi 0/r32/eax
19609     # if (operand->register && s->is-deref?) emit "*__"
19610     {
19611 $emit-subx-var-as-rm32:check-for-register-indirect:
19612       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19613       74/jump-if-= break/disp8
19614       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19615       74/jump-if-= break/disp8
19616 $emit-subx-var-as-rm32:register-indirect:
19617       (write-buffered *(ebp+8) " *")
19618       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
19619       (write-buffered *(ebp+8) %eax)
19620       e9/jump $emit-subx-var-as-rm32:end/disp32
19621     }
19622     # if (operand->register && !s->is-deref?) emit "%__"
19623     {
19624 $emit-subx-var-as-rm32:check-for-register-direct:
19625       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19626       74/jump-if-= break/disp8
19627       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19628       75/jump-if-!= break/disp8
19629 $emit-subx-var-as-rm32:register-direct:
19630       (write-buffered *(ebp+8) " %")
19631       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
19632       (write-buffered *(ebp+8) %eax)
19633       e9/jump $emit-subx-var-as-rm32:end/disp32
19634     }
19635     # else if (operand->stack-offset) emit "*(ebp+__)"
19636     {
19637       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
19638       74/jump-if-= break/disp8
19639 $emit-subx-var-as-rm32:stack:
19640       (write-buffered *(ebp+8) Space)
19641       (write-buffered *(ebp+8) "*(ebp+")
19642       (write-int32-hex-buffered *(ebp+8) *(esi+0x14))  # Var-offset
19643       (write-buffered *(ebp+8) ")")
19644     }
19645 $emit-subx-var-as-rm32:end:
19646     # . restore registers
19647     5e/pop-to-esi
19648     59/pop-to-ecx
19649     58/pop-to-eax
19650     # . epilogue
19651     89/<- %esp 5/r32/ebp
19652     5d/pop-to-ebp
19653     c3/return
19654 
19655 find-matching-primitive:  # primitives: (addr primitive), stmt: (addr stmt) -> result/eax: (addr primitive)
19656     # . prologue
19657     55/push-ebp
19658     89/<- %ebp 4/r32/esp
19659     # . save registers
19660     51/push-ecx
19661     # var curr/ecx: (addr primitive) = primitives
19662     8b/-> *(ebp+8) 1/r32/ecx
19663     {
19664 $find-matching-primitive:loop:
19665       # if (curr == null) break
19666       81 7/subop/compare %ecx 0/imm32
19667       74/jump-if-= break/disp8
19668       # if match(curr, stmt) return curr
19669       {
19670         (mu-stmt-matches-primitive? *(ebp+0xc) %ecx)  # => eax
19671         3d/compare-eax-and 0/imm32/false
19672         74/jump-if-= break/disp8
19673         89/<- %eax 1/r32/ecx
19674         eb/jump $find-matching-primitive:end/disp8
19675       }
19676 $find-matching-primitive:next-primitive:
19677       # curr = curr->next
19678       (lookup *(ecx+0x38) *(ecx+0x3c))  # Primitive-next Primitive-next => eax
19679       89/<- %ecx 0/r32/eax
19680       #
19681       e9/jump loop/disp32
19682     }
19683     # return null
19684     b8/copy-to-eax 0/imm32
19685 $find-matching-primitive:end:
19686     # . restore registers
19687     59/pop-to-ecx
19688     # . epilogue
19689     89/<- %esp 5/r32/ebp
19690     5d/pop-to-ebp
19691     c3/return
19692 
19693 mu-stmt-matches-primitive?:  # stmt: (addr stmt), primitive: (addr primitive) -> result/eax: boolean
19694     # A mu stmt matches a primitive if the name matches, all the inout vars
19695     # match, and all the output vars match.
19696     # Vars match if types match and registers match.
19697     # In addition, a stmt output matches a primitive's output if types match
19698     # and the primitive has a wildcard register.
19699     # . prologue
19700     55/push-ebp
19701     89/<- %ebp 4/r32/esp
19702     # . save registers
19703     51/push-ecx
19704     52/push-edx
19705     53/push-ebx
19706     56/push-esi
19707     57/push-edi
19708     # ecx = stmt
19709     8b/-> *(ebp+8) 1/r32/ecx
19710     # edx = primitive
19711     8b/-> *(ebp+0xc) 2/r32/edx
19712     {
19713 $mu-stmt-matches-primitive?:check-name:
19714       # if (primitive->name != stmt->operation) return false
19715       # . var esi: (addr array byte) = lookup(stmt->operation)
19716       (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
19717       89/<- %esi 0/r32/eax
19718       # . var edi: (addr array byte) = lookup(primitive->name)
19719       (lookup *edx *(edx+4))  # Primitive-name Primitive-name => eax
19720       89/<- %edi 0/r32/eax
19721       (string-equal? %esi %edi)  # => eax
19722       3d/compare-eax-and 0/imm32/false
19723       75/jump-if-!= break/disp8
19724       b8/copy-to-eax 0/imm32
19725       e9/jump $mu-stmt-matches-primitive?:end/disp32
19726     }
19727     # var curr/esi: (addr stmt-var) = lookup(stmt->inouts)
19728     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
19729     89/<- %esi 0/r32/eax
19730     # var curr2/edi: (addr list var) = lookup(primitive->inouts)
19731     (lookup *(edx+8) *(edx+0xc))  # Primitive-inouts Primitive-inouts => eax
19732     89/<- %edi 0/r32/eax
19733     {
19734 $mu-stmt-matches-primitive?:inouts-loop:
19735       # if (curr == 0 && curr2 == 0) move on to check outputs
19736       {
19737 $mu-stmt-matches-primitive?:check-both-inouts-null:
19738         81 7/subop/compare %esi 0/imm32
19739         75/jump-if-!= break/disp8
19740 $mu-stmt-matches-primitive?:stmt-inout-null:
19741         81 7/subop/compare %edi 0/imm32
19742         0f 84/jump-if-= $mu-stmt-matches-primitive?:check-outputs/disp32
19743 $mu-stmt-matches-primitive?:stmt-inout-null-and-prim-inout-not-null:
19744         # return false
19745         b8/copy-to-eax 0/imm32/false
19746         e9/jump $mu-stmt-matches-primitive?:end/disp32
19747       }
19748       # if (curr2 == 0) return false
19749       {
19750 $mu-stmt-matches-primitive?:check-prim-inout-null:
19751         81 7/subop/compare %edi 0/imm32
19752         75/jump-if-!= break/disp8
19753 $mu-stmt-matches-primitive?:prim-inout-null:
19754         b8/copy-to-eax 0/imm32/false
19755         e9/jump $mu-stmt-matches-primitive?:end/disp32
19756       }
19757       # if (curr != curr2) return false
19758       {
19759 $mu-stmt-matches-primitive?:check-inouts-match:
19760         (lookup *edi *(edi+4))  # List-value List-value => eax
19761         (operand-matches-primitive? %esi %eax)  # => eax
19762         3d/compare-eax-and 0/imm32/false
19763         75/jump-if-!= break/disp8
19764 $mu-stmt-matches-primitive?:inouts-match:
19765         b8/copy-to-eax 0/imm32/false
19766         e9/jump $mu-stmt-matches-primitive?:end/disp32
19767       }
19768 $mu-stmt-matches-primitive?:next-inout:
19769       # curr = lookup(curr->next)
19770       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
19771       89/<- %esi 0/r32/eax
19772       # curr2 = lookup(curr2->next)
19773       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
19774       89/<- %edi 0/r32/eax
19775       #
19776       e9/jump loop/disp32
19777     }
19778 $mu-stmt-matches-primitive?:check-outputs:
19779     # var curr/esi: (addr stmt-var) = lookup(stmt->outputs)
19780     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
19781     89/<- %esi 0/r32/eax
19782     # var curr2/edi: (addr list var) = lookup(primitive->outputs)
19783     (lookup *(edx+0x10) *(edx+0x14))  # Primitive-outputs Primitive-outputs => eax
19784     89/<- %edi 0/r32/eax
19785     {
19786 $mu-stmt-matches-primitive?:outputs-loop:
19787       # if (curr == 0) return (curr2 == 0)
19788       {
19789 $mu-stmt-matches-primitive?:check-both-outputs-null:
19790         81 7/subop/compare %esi 0/imm32
19791         75/jump-if-!= break/disp8
19792         {
19793 $mu-stmt-matches-primitive?:stmt-output-null:
19794           81 7/subop/compare %edi 0/imm32
19795           75/jump-if-!= break/disp8
19796 $mu-stmt-matches-primitive?:both-outputs-null:
19797           # return true
19798           b8/copy-to-eax 1/imm32
19799           e9/jump $mu-stmt-matches-primitive?:end/disp32
19800         }
19801 $mu-stmt-matches-primitive?:stmt-output-null-and-prim-output-not-null:
19802         # return false
19803         b8/copy-to-eax 0/imm32
19804         e9/jump $mu-stmt-matches-primitive?:end/disp32
19805       }
19806       # if (curr2 == 0) return false
19807       {
19808 $mu-stmt-matches-primitive?:check-prim-output-null:
19809         81 7/subop/compare %edi 0/imm32
19810         75/jump-if-!= break/disp8
19811 $mu-stmt-matches-primitive?:prim-output-is-null:
19812         b8/copy-to-eax 0/imm32
19813         e9/jump $mu-stmt-matches-primitive?:end/disp32
19814       }
19815       # if (curr != curr2) return false
19816       {
19817 $mu-stmt-matches-primitive?:check-outputs-match:
19818         (lookup *edi *(edi+4))  # List-value List-value => eax
19819         (operand-matches-primitive? %esi %eax)  # => eax
19820         3d/compare-eax-and 0/imm32/false
19821         75/jump-if-!= break/disp8
19822 $mu-stmt-matches-primitive?:outputs-match:
19823         b8/copy-to-eax 0/imm32
19824         e9/jump $mu-stmt-matches-primitive?:end/disp32
19825       }
19826 $mu-stmt-matches-primitive?:next-output:
19827       # curr = lookup(curr->next)
19828       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
19829       89/<- %esi 0/r32/eax
19830       # curr2 = lookup(curr2->next)
19831       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
19832       89/<- %edi 0/r32/eax
19833       #
19834       e9/jump loop/disp32
19835     }
19836 $mu-stmt-matches-primitive?:return-true:
19837     b8/copy-to-eax 1/imm32
19838 $mu-stmt-matches-primitive?:end:
19839     # . restore registers
19840     5f/pop-to-edi
19841     5e/pop-to-esi
19842     5b/pop-to-ebx
19843     5a/pop-to-edx
19844     59/pop-to-ecx
19845     # . epilogue
19846     89/<- %esp 5/r32/ebp
19847     5d/pop-to-ebp
19848     c3/return
19849 
19850 operand-matches-primitive?:  # s: (addr stmt-var), prim-var: (addr var) -> result/eax: boolean
19851     # . prologue
19852     55/push-ebp
19853     89/<- %ebp 4/r32/esp
19854     # . save registers
19855     51/push-ecx
19856     52/push-edx
19857     53/push-ebx
19858     56/push-esi
19859     57/push-edi
19860     # ecx = s
19861     8b/-> *(ebp+8) 1/r32/ecx
19862     # var var/esi: (addr var) = lookup(s->value)
19863     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
19864     89/<- %esi 0/r32/eax
19865     # edi = prim-var
19866     8b/-> *(ebp+0xc) 7/r32/edi
19867 $operand-matches-primitive?:check-type:
19868     # if !category-match?(var->type, prim-var->type) return false
19869     # . var vtype/ebx: (addr type-tree) = lookup(var->type)
19870     (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
19871     89/<- %ebx 0/r32/eax
19872     # . var ptype/eax: (addr type-tree) = lookup(prim-var->type)
19873     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
19874     (subx-type-category-match? %ebx %eax)  # => eax
19875     3d/compare-eax-and 0/imm32/false
19876     0f 84/jump-if-= $operand-matches-primitive?:return-false/disp32
19877     {
19878 $operand-matches-primitive?:check-register:
19879       # if prim-var is in memory and var is in register but dereference, match
19880       {
19881         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
19882         0f 85/jump-if-!= break/disp32
19883         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19884         74/jump-if-= break/disp8
19885         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19886         74/jump-if-= break/disp8
19887 $operand-matches-primitive?:var-deref-match:
19888         e9/jump $operand-matches-primitive?:return-true/disp32
19889       }
19890       # if prim-var is in register and var is in register but dereference, no match
19891       {
19892         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
19893         0f 84/jump-if-= break/disp32
19894         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19895         0f 84/jump-if-= break/disp32
19896         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19897         74/jump-if-= break/disp8
19898 $operand-matches-primitive?:var-deref-no-match:
19899         e9/jump $operand-matches-primitive?:return-false/disp32
19900       }
19901       # return false if var->register doesn't match prim-var->register
19902       {
19903         # if register addresses are equal, it's a match
19904         # var vreg/ebx: (addr array byte) = lookup(var->register)
19905         (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
19906         89/<- %ebx 0/r32/eax
19907         # var preg/ecx: (addr array byte) = lookup(prim-var->register)
19908         (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
19909         89/<- %ecx 0/r32/eax
19910         # if (vreg == preg) break
19911         39/compare %ecx 3/r32/ebx
19912         74/jump-if-= break/disp8
19913 $operand-matches-primitive?:var-register-no-match:
19914         # if either address is 0, return false
19915         81 7/subop/compare %ebx 0/imm32
19916         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
19917         81 7/subop/compare %ecx 0/imm32
19918         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
19919         # if prim-var->register is wildcard, it's a match
19920         (string-equal? %ecx "*")  # Any-register => eax
19921         3d/compare-eax-and 0/imm32/false
19922         75/jump-if-!= break/disp8
19923 $operand-matches-primitive?:wildcard-no-match:
19924         # if string contents aren't equal, return false
19925         (string-equal? %ecx %ebx)  # => eax
19926         3d/compare-eax-and 0/imm32/false
19927         74/jump-if-= $operand-matches-primitive?:return-false/disp8
19928       }
19929     }
19930 $operand-matches-primitive?:return-true:
19931     b8/copy-to-eax 1/imm32/true
19932     eb/jump $operand-matches-primitive?:end/disp8
19933 $operand-matches-primitive?:return-false:
19934     b8/copy-to-eax 0/imm32/false
19935 $operand-matches-primitive?:end:
19936     # . restore registers
19937     5f/pop-to-edi
19938     5e/pop-to-esi
19939     5b/pop-to-ebx
19940     5a/pop-to-edx
19941     59/pop-to-ecx
19942     # . epilogue
19943     89/<- %esp 5/r32/ebp
19944     5d/pop-to-ebp
19945     c3/return
19946 
19947 find-matching-function:  # functions: (addr function), stmt: (addr stmt) -> result/eax: (addr function)
19948     # . prologue
19949     55/push-ebp
19950     89/<- %ebp 4/r32/esp
19951     # . save registers
19952     51/push-ecx
19953     # var curr/ecx: (handle function) = functions
19954     8b/-> *(ebp+8) 1/r32/ecx
19955     {
19956       # if (curr == null) break
19957       81 7/subop/compare %ecx 0/imm32
19958       74/jump-if-= break/disp8
19959 #?       (write-buffered Stderr "iter\n")
19960 #?       (flush Stderr)
19961       # if match(stmt, curr) return curr
19962       {
19963         (mu-stmt-matches-function? *(ebp+0xc) %ecx)  # => eax
19964         3d/compare-eax-and 0/imm32/false
19965         74/jump-if-= break/disp8
19966         89/<- %eax 1/r32/ecx
19967         eb/jump $find-matching-function:end/disp8
19968       }
19969       # curr = curr->next
19970       (lookup *(ecx+0x20) *(ecx+0x24))  # Function-next Function-next => eax
19971       89/<- %ecx 0/r32/eax
19972       #
19973       eb/jump loop/disp8
19974     }
19975     # return null
19976     b8/copy-to-eax 0/imm32
19977 $find-matching-function:end:
19978     # . restore registers
19979     59/pop-to-ecx
19980     # . epilogue
19981     89/<- %esp 5/r32/ebp
19982     5d/pop-to-ebp
19983     c3/return
19984 
19985 # Just compare names; user-defined functions don't support overloading yet.
19986 mu-stmt-matches-function?:  # stmt: (addr stmt1), function: (addr function) -> result/eax: boolean
19987     # . prologue
19988     55/push-ebp
19989     89/<- %ebp 4/r32/esp
19990     # . save registers
19991     51/push-ecx
19992     # return function->name == stmt->operation
19993     # ecx = lookup(stmt->operation)
19994     8b/-> *(ebp+8) 0/r32/eax
19995     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
19996     89/<- %ecx 0/r32/eax
19997     # eax = lookup(function->name)
19998     8b/-> *(ebp+0xc) 0/r32/eax
19999     (lookup *eax *(eax+4))  # Function-name Function-name => eax
20000     (string-equal? %eax %ecx)  # => eax
20001 $mu-stmt-matches-function?:end:
20002     # . restore registers
20003     59/pop-to-ecx
20004     # . epilogue
20005     89/<- %esp 5/r32/ebp
20006     5d/pop-to-ebp
20007     c3/return
20008 
20009 # Type-checking happens elsewhere. This method is for selecting between
20010 # primitives.
20011 subx-type-category-match?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
20012     # . prologue
20013     55/push-ebp
20014     89/<- %ebp 4/r32/esp
20015     # . save registers
20016     51/push-ecx
20017     # var alit/ecx: boolean = is-literal-type?(a)
20018     (is-simple-mu-type? *(ebp+8) 0)  # => eax
20019     89/<- %ecx 0/r32/eax
20020     # var blit/eax: boolean = is-literal-type?(b)
20021     (is-simple-mu-type? *(ebp+0xc) 0)  # => eax
20022     # return alit == blit
20023     39/compare %eax 1/r32/ecx
20024     0f 94/set-byte-if-= %al
20025     81 4/subop/and %eax 0xff/imm32
20026 $subx-type-category-match?:end:
20027     # . restore registers
20028     59/pop-to-ecx
20029     # . epilogue
20030     89/<- %esp 5/r32/ebp
20031     5d/pop-to-ebp
20032     c3/return
20033 
20034 is-simple-mu-type?:  # a: (addr type-tree), n: type-id -> result/eax: boolean
20035     # . prologue
20036     55/push-ebp
20037     89/<- %ebp 4/r32/esp
20038     # . save registers
20039     51/push-ecx
20040     # ecx = n
20041     8b/-> *(ebp+0xc) 1/r32/ecx
20042     # return (a->value == n)
20043     8b/-> *(ebp+8) 0/r32/eax
20044     39/compare *(eax+4) 1/r32/ecx  # Type-tree-value
20045     0f 94/set-byte-if-= %al
20046     81 4/subop/and %eax 0xff/imm32
20047 $is-simple-mu-type?:end:
20048     # . restore registers
20049     59/pop-to-ecx
20050     # . epilogue
20051     89/<- %esp 5/r32/ebp
20052     5d/pop-to-ebp
20053     c3/return
20054 
20055 is-mu-addr-type?:  # a: (addr type-tree) -> result/eax: boolean
20056     # . prologue
20057     55/push-ebp
20058     89/<- %ebp 4/r32/esp
20059     # eax = a
20060     8b/-> *(ebp+8) 0/r32/eax
20061     # if (!a->is-atom?) a = a->left
20062     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
20063     {
20064       75/jump-if-!= break/disp8
20065       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
20066     }
20067     # return (a->value == addr)
20068     81 7/subop/compare *(eax+4) 2/imm32/addr  # Type-tree-value
20069     0f 94/set-byte-if-= %al
20070     81 4/subop/and %eax 0xff/imm32
20071 $is-mu-addr-type?:end:
20072     # . epilogue
20073     89/<- %esp 5/r32/ebp
20074     5d/pop-to-ebp
20075     c3/return
20076 
20077 is-mu-array-type?:  # a: (addr type-tree) -> result/eax: boolean
20078     # . prologue
20079     55/push-ebp
20080     89/<- %ebp 4/r32/esp
20081     # eax = a
20082     8b/-> *(ebp+8) 0/r32/eax
20083     # if (!a->is-atom?) a = a->left
20084     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
20085     {
20086       75/jump-if-!= break/disp8
20087       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
20088     }
20089     # return (a->value == array)
20090     81 7/subop/compare *(eax+4) 3/imm32/array  # Type-tree-value
20091     0f 94/set-byte-if-= %al
20092     81 4/subop/and %eax 0xff/imm32
20093 $is-mu-array-type?:end:
20094     # . epilogue
20095     89/<- %esp 5/r32/ebp
20096     5d/pop-to-ebp
20097     c3/return
20098 
20099 is-mu-stream-type?:  # a: (addr type-tree) -> result/eax: boolean
20100     # . prologue
20101     55/push-ebp
20102     89/<- %ebp 4/r32/esp
20103     # eax = a
20104     8b/-> *(ebp+8) 0/r32/eax
20105     # if (!a->is-atom?) a = a->left
20106     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
20107     {
20108       75/jump-if-!= break/disp8
20109       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
20110     }
20111     # return (a->value == stream)
20112     81 7/subop/compare *(eax+4) 0xb/imm32/stream  # Type-tree-value
20113     0f 94/set-byte-if-= %al
20114     81 4/subop/and %eax 0xff/imm32
20115 $is-mu-stream-type?:end:
20116     # . epilogue
20117     89/<- %esp 5/r32/ebp
20118     5d/pop-to-ebp
20119     c3/return
20120 
20121 test-emit-subx-stmt-primitive:
20122     # Primitive operation on a variable on the stack.
20123     #   increment foo
20124     # =>
20125     #   ff 0/subop/increment *(ebp-8)
20126     #
20127     # There's a variable on the var stack as follows:
20128     #   name: 'foo'
20129     #   type: int
20130     #   stack-offset: -8
20131     #
20132     # There's a primitive with this info:
20133     #   name: 'increment'
20134     #   inouts: int/mem
20135     #   value: 'ff 0/subop/increment'
20136     #
20137     # . prologue
20138     55/push-ebp
20139     89/<- %ebp 4/r32/esp
20140     # setup
20141     (clear-stream _test-output-stream)
20142     (clear-stream $_test-output-buffered-file->buffer)
20143     # simulate allocated payloads starting with an initial fake alloc-id (0x11)
20144 $test-emit-subx-stmt-primitive:initialize-type:
20145     # var type/ecx: (payload type-tree) = int
20146     68/push 0/imm32/right:null
20147     68/push 0/imm32/right:null
20148     68/push 0/imm32/left:unused
20149     68/push 1/imm32/value:int
20150     68/push 1/imm32/is-atom?:true
20151     68/push 0x11/imm32/alloc-id:fake:payload
20152     89/<- %ecx 4/r32/esp
20153 $test-emit-subx-stmt-primitive:initialize-var:
20154     # var var-foo/ecx: (payload var) = var(type)
20155     68/push 0/imm32/no-register
20156     68/push 0/imm32/no-register
20157     68/push -8/imm32/stack-offset
20158     68/push 1/imm32/block-depth
20159     51/push-ecx/type
20160     68/push 0x11/imm32/alloc-id:fake
20161     68/push 0/imm32/name
20162     68/push 0/imm32/name
20163     68/push 0x11/imm32/alloc-id:fake:payload
20164     89/<- %ecx 4/r32/esp
20165 $test-emit-subx-stmt-primitive:initialize-var-name:
20166     # var-foo->name = "foo"
20167     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20168     (copy-array Heap "foo" %eax)
20169 $test-emit-subx-stmt-primitive:initialize-stmt-var:
20170     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
20171     68/push 0/imm32/is-deref:false
20172     68/push 0/imm32/next
20173     68/push 0/imm32/next
20174     51/push-ecx/var-foo
20175     68/push 0x11/imm32/alloc-id:fake
20176     68/push 0x11/imm32/alloc-id:fake:payload
20177     89/<- %ebx 4/r32/esp
20178 $test-emit-subx-stmt-primitive:initialize-stmt:
20179     # var stmt/esi: (addr statement)
20180     68/push 0/imm32/no-outputs
20181     68/push 0/imm32/no-outputs
20182     53/push-ebx/inouts
20183     68/push 0x11/imm32/alloc-id:fake
20184     68/push 0/imm32/operation
20185     68/push 0/imm32/operation
20186     68/push 1/imm32/tag
20187     89/<- %esi 4/r32/esp
20188 $test-emit-subx-stmt-primitive:initialize-stmt-operation:
20189     # stmt->operation = "increment"
20190     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20191     (copy-array Heap "increment" %eax)
20192 $test-emit-subx-stmt-primitive:initialize-primitive:
20193     # var primitives/ebx: (addr primitive)
20194     68/push 0/imm32/next
20195     68/push 0/imm32/next
20196     68/push 0/imm32/output-is-write-only
20197     68/push 0/imm32/no-disp32
20198     68/push 0/imm32/no-imm8
20199     68/push 0/imm32/no-imm32
20200     68/push 0/imm32/no-r32
20201     68/push 1/imm32/rm32-is-first-inout
20202     68/push 0/imm32/subx-name
20203     68/push 0/imm32/subx-name
20204     68/push 0/imm32/no-outputs
20205     68/push 0/imm32/no-outputs
20206     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
20207     68/push 0x11/imm32/alloc-id:fake
20208     68/push 0/imm32/name
20209     68/push 0/imm32/name
20210     89/<- %ebx 4/r32/esp
20211 $test-emit-subx-stmt-primitive:initialize-primitive-name:
20212     # primitives->name = "increment"
20213     (copy-array Heap "increment" %ebx)  # Primitive-name
20214 $test-emit-subx-stmt-primitive:initialize-primitive-subx-name:
20215     # primitives->subx-name = "ff 0/subop/increment"
20216     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
20217     (copy-array Heap "ff 0/subop/increment" %eax)
20218     # convert
20219     c7 0/subop/copy *Curr-block-depth 0/imm32
20220     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
20221     (flush _test-output-buffered-file)
20222 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20228     # check output
20229     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-stmt-primitive")
20230     # . epilogue
20231     89/<- %esp 5/r32/ebp
20232     5d/pop-to-ebp
20233     c3/return
20234 
20235 test-emit-subx-stmt-primitive-register:
20236     # Primitive operation on a variable in a register.
20237     #   foo <- increment
20238     # =>
20239     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
20240     #
20241     # There's a variable on the var stack as follows:
20242     #   name: 'foo'
20243     #   type: int
20244     #   register: 'eax'
20245     #
20246     # There's a primitive with this info:
20247     #   name: 'increment'
20248     #   out: int/reg
20249     #   value: 'ff 0/subop/increment'
20250     #
20251     # . prologue
20252     55/push-ebp
20253     89/<- %ebp 4/r32/esp
20254     # setup
20255     (clear-stream _test-output-stream)
20256     (clear-stream $_test-output-buffered-file->buffer)
20257 $test-emit-subx-stmt-primitive-register:initialize-type:
20258     # var type/ecx: (payload type-tree) = int
20259     68/push 0/imm32/right:null
20260     68/push 0/imm32/right:null
20261     68/push 0/imm32/left:unused
20262     68/push 1/imm32/value:int
20263     68/push 1/imm32/is-atom?:true
20264     68/push 0x11/imm32/alloc-id:fake:payload
20265     89/<- %ecx 4/r32/esp
20266 $test-emit-subx-stmt-primitive-register:initialize-var:
20267     # var var-foo/ecx: (payload var)
20268     68/push 0/imm32/register
20269     68/push 0/imm32/register
20270     68/push 0/imm32/no-stack-offset
20271     68/push 1/imm32/block-depth
20272     51/push-ecx
20273     68/push 0x11/imm32/alloc-id:fake
20274     68/push 0/imm32/name
20275     68/push 0/imm32/name
20276     68/push 0x11/imm32/alloc-id:fake:payload
20277     89/<- %ecx 4/r32/esp
20278 $test-emit-subx-stmt-primitive-register:initialize-var-name:
20279     # var-foo->name = "foo"
20280     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20281     (copy-array Heap "foo" %eax)
20282 $test-emit-subx-stmt-primitive-register:initialize-var-register:
20283     # var-foo->register = "eax"
20284     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20285     (copy-array Heap "eax" %eax)
20286 $test-emit-subx-stmt-primitive-register:initialize-stmt-var:
20287     # var operand/ebx: (payload stmt-var)
20288     68/push 0/imm32/is-deref:false
20289     68/push 0/imm32/next
20290     68/push 0/imm32/next
20291     51/push-ecx/var-foo
20292     68/push 0x11/imm32/alloc-id:fake
20293     68/push 0x11/imm32/alloc-id:fake:payload
20294     89/<- %ebx 4/r32/esp
20295 $test-emit-subx-stmt-primitive-register:initialize-stmt:
20296     # var stmt/esi: (addr statement)
20297     53/push-ebx/outputs
20298     68/push 0x11/imm32/alloc-id:fake
20299     68/push 0/imm32/no-inouts
20300     68/push 0/imm32/no-inouts
20301     68/push 0/imm32/operation
20302     68/push 0/imm32/operation
20303     68/push 1/imm32
20304     89/<- %esi 4/r32/esp
20305 $test-emit-subx-stmt-primitive-register:initialize-stmt-operation:
20306     # stmt->operation = "increment"
20307     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20308     (copy-array Heap "increment" %eax)
20309 $test-emit-subx-stmt-primitive-register:initialize-formal-var:
20310     # var formal-var/ebx: (payload var)
20311     68/push 0/imm32/register
20312     68/push 0/imm32/register
20313     68/push 0/imm32/no-stack-offset
20314     68/push 1/imm32/block-depth
20315     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
20316     68/push 0x11/imm32/alloc-id:fake
20317     68/push 0/imm32/name
20318     68/push 0/imm32/name
20319     68/push 0x11/imm32/alloc-id:fake:payload
20320     89/<- %ebx 4/r32/esp
20321 $test-emit-subx-stmt-primitive-register:initialize-formal-var-name:
20322     # formal-var->name = "dummy"
20323     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
20324     (copy-array Heap "dummy" %eax)
20325 $test-emit-subx-stmt-primitive-register:initialize-formal-register:
20326     # formal-var->register = "*"
20327     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
20328     (copy-array Heap "*" %eax)  # Any-register
20329 $test-emit-subx-stmt-primitive-register:initialize-var-list:
20330     # var formal-outputs/ebx: (payload list var)
20331     68/push 0/imm32/next
20332     68/push 0/imm32/next
20333     53/push-ebx/formal-var
20334     68/push 0x11/imm32/alloc-id:fake
20335     68/push 0x11/imm32/alloc-id:fake:payload
20336     89/<- %ebx 4/r32/esp
20337 $test-emit-subx-stmt-primitive-register:initialize-primitive:
20338     # var primitives/ebx: (addr primitive)
20339     68/push 0/imm32/next
20340     68/push 0/imm32/next
20341     68/push 0/imm32/output-is-write-only
20342     68/push 0/imm32/no-disp32
20343     68/push 0/imm32/no-imm8
20344     68/push 0/imm32/no-imm32
20345     68/push 0/imm32/no-r32
20346     68/push 3/imm32/rm32-is-first-output
20347     68/push 0/imm32/subx-name
20348     68/push 0/imm32/subx-name
20349     53/push-ebx/outputs
20350     68/push 0x11/imm32/alloc-id:fake
20351     68/push 0/imm32/no-inouts
20352     68/push 0/imm32/no-inouts
20353     68/push 0/imm32/name
20354     68/push 0/imm32/name
20355     89/<- %ebx 4/r32/esp
20356 $test-emit-subx-stmt-primitive-register:initialize-primitive-name:
20357     # primitives->name = "increment"
20358     (copy-array Heap "increment" %ebx)  # Primitive-name
20359 $test-emit-subx-stmt-primitive-register:initialize-primitive-subx-name:
20360     # primitives->subx-name = "ff 0/subop/increment"
20361     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
20362     (copy-array Heap "ff 0/subop/increment" %eax)
20363     # convert
20364     c7 0/subop/copy *Curr-block-depth 0/imm32
20365     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
20366     (flush _test-output-buffered-file)
20367 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20373     # check output
20374     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-primitive-register")
20375     # . epilogue
20376     89/<- %esp 5/r32/ebp
20377     5d/pop-to-ebp
20378     c3/return
20379 
20380 test-emit-subx-stmt-select-primitive:
20381     # Select the right primitive between overloads.
20382     #   foo <- increment
20383     # =>
20384     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
20385     #
20386     # There's a variable on the var stack as follows:
20387     #   name: 'foo'
20388     #   type: int
20389     #   register: 'eax'
20390     #
20391     # There's two primitives, as follows:
20392     #   - name: 'increment'
20393     #     out: int/reg
20394     #     value: 'ff 0/subop/increment'
20395     #   - name: 'increment'
20396     #     inout: int/mem
20397     #     value: 'ff 0/subop/increment'
20398     #
20399     # . prologue
20400     55/push-ebp
20401     89/<- %ebp 4/r32/esp
20402     # setup
20403     (clear-stream _test-output-stream)
20404     (clear-stream $_test-output-buffered-file->buffer)
20405 $test-emit-subx-stmt-select-primitive:initialize-type:
20406     # var type/ecx: (payload type-tree) = int
20407     68/push 0/imm32/right:null
20408     68/push 0/imm32/right:null
20409     68/push 0/imm32/left:unused
20410     68/push 1/imm32/value:int
20411     68/push 1/imm32/is-atom?:true
20412     68/push 0x11/imm32/alloc-id:fake:payload
20413     89/<- %ecx 4/r32/esp
20414 $test-emit-subx-stmt-select-primitive:initialize-var:
20415     # var var-foo/ecx: (payload var)
20416     68/push 0/imm32/register
20417     68/push 0/imm32/register
20418     68/push 0/imm32/no-stack-offset
20419     68/push 1/imm32/block-depth
20420     51/push-ecx
20421     68/push 0x11/imm32/alloc-id:fake
20422     68/push 0/imm32/name
20423     68/push 0/imm32/name
20424     68/push 0x11/imm32/alloc-id:fake:payload
20425     89/<- %ecx 4/r32/esp
20426 $test-emit-subx-stmt-select-primitive:initialize-var-name:
20427     # var-foo->name = "foo"
20428     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20429     (copy-array Heap "foo" %eax)
20430 $test-emit-subx-stmt-select-primitive:initialize-var-register:
20431     # var-foo->register = "eax"
20432     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20433     (copy-array Heap "eax" %eax)
20434 $test-emit-subx-stmt-select-primitive:initialize-stmt-var:
20435     # var operand/ebx: (payload stmt-var)
20436     68/push 0/imm32/is-deref:false
20437     68/push 0/imm32/next
20438     68/push 0/imm32/next
20439     51/push-ecx/var-foo
20440     68/push 0x11/imm32/alloc-id:fake
20441     68/push 0x11/imm32/alloc-id:fake:payload
20442     89/<- %ebx 4/r32/esp
20443 $test-emit-subx-stmt-select-primitive:initialize-stmt:
20444     # var stmt/esi: (addr statement)
20445     53/push-ebx/outputs
20446     68/push 0x11/imm32/alloc-id:fake
20447     68/push 0/imm32/no-inouts
20448     68/push 0/imm32/no-inouts
20449     68/push 0/imm32/operation
20450     68/push 0/imm32/operation
20451     68/push 1/imm32
20452     89/<- %esi 4/r32/esp
20453 $test-emit-subx-stmt-select-primitive:initialize-stmt-operation:
20454     # stmt->operation = "increment"
20455     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20456     (copy-array Heap "increment" %eax)
20457 $test-emit-subx-stmt-select-primitive:initialize-formal-var:
20458     # var formal-var/ebx: (payload var)
20459     68/push 0/imm32/register
20460     68/push 0/imm32/register
20461     68/push 0/imm32/no-stack-offset
20462     68/push 1/imm32/block-depth
20463     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
20464     68/push 0x11/imm32/alloc-id:fake
20465     68/push 0/imm32/name
20466     68/push 0/imm32/name
20467     68/push 0x11/imm32/alloc-id:fake:payload
20468     89/<- %ebx 4/r32/esp
20469 $test-emit-subx-stmt-select-primitive:initialize-formal-var-name:
20470     # formal-var->name = "dummy"
20471     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
20472     (copy-array Heap "dummy" %eax)
20473 $test-emit-subx-stmt-select-primitive:initialize-formal-register:
20474     # formal-var->register = "*"
20475     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
20476     (copy-array Heap "*" %eax)  # Any-register
20477 $test-emit-subx-stmt-select-primitive:initialize-var-list:
20478     # var formal-outputs/ebx: (payload list var)
20479     68/push 0/imm32/next
20480     68/push 0/imm32/next
20481     53/push-ebx/formal-var
20482     68/push 0x11/imm32/alloc-id:fake
20483     68/push 0x11/imm32/alloc-id:fake:payload
20484     89/<- %ebx 4/r32/esp
20485 $test-emit-subx-stmt-select-primitive:initialize-primitive2:
20486     # var primitive2/edi: (payload primitive)
20487     68/push 0/imm32/next
20488     68/push 0/imm32/next
20489     68/push 0/imm32/output-is-write-only
20490     68/push 0/imm32/no-disp32
20491     68/push 0/imm32/no-imm8
20492     68/push 0/imm32/no-imm32
20493     68/push 0/imm32/no-r32
20494     68/push 3/imm32/rm32-is-first-output
20495     68/push 0/imm32/subx-name
20496     68/push 0/imm32/subx-name
20497     53/push-ebx/outputs
20498     68/push 0x11/imm32/alloc-id:fake
20499     68/push 0/imm32/no-inouts
20500     68/push 0/imm32/no-inouts
20501     68/push 0/imm32/name
20502     68/push 0/imm32/name
20503     68/push 0x11/imm32/alloc-id:fake:payload
20504     89/<- %edi 4/r32/esp
20505 $test-emit-subx-stmt-select-primitive:initialize-primitive2-name:
20506     # primitives->name = "increment"
20507     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
20508     (copy-array Heap "increment" %eax)
20509 $test-emit-subx-stmt-select-primitive:initialize-primitive2-subx-name:
20510     # primitives->subx-name = "ff 0/subop/increment"
20511     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
20512     (copy-array Heap "ff 0/subop/increment" %eax)
20513 $test-emit-subx-stmt-select-primitive:initialize-primitive:
20514     # var primitives/ebx: (addr primitive)
20515     57/push-edi
20516     68/push 0x11/imm32/alloc-id:fake
20517     68/push 0/imm32/output-is-write-only
20518     68/push 0/imm32/no-disp32
20519     68/push 0/imm32/no-imm8
20520     68/push 0/imm32/no-imm32
20521     68/push 0/imm32/no-r32
20522     68/push 1/imm32/rm32-is-first-inout
20523     68/push 0/imm32/subx-name
20524     68/push 0/imm32/subx-name
20525     68/push 0/imm32/no-outputs
20526     68/push 0/imm32/no-outputs
20527     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
20528     68/push 0x11/imm32/alloc-id:fake
20529     68/push 0/imm32/name
20530     68/push 0/imm32/name
20531     89/<- %ebx 4/r32/esp
20532 $test-emit-subx-stmt-select-primitive:initialize-primitive-name:
20533     # primitives->name = "increment"
20534     (copy-array Heap "increment" %ebx)  # Primitive-name
20535 $test-emit-subx-stmt-select-primitive:initialize-primitive-subx-name:
20536     # primitives->subx-name = "ff 0/subop/increment"
20537     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
20538     (copy-array Heap "ff 0/subop/increment" %eax)
20539     # convert
20540     c7 0/subop/copy *Curr-block-depth 0/imm32
20541     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
20542     (flush _test-output-buffered-file)
20543 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20549     # check output
20550     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive")
20551     # . epilogue
20552     89/<- %esp 5/r32/ebp
20553     5d/pop-to-ebp
20554     c3/return
20555 
20556 test-emit-subx-stmt-select-primitive-2:
20557     # Select the right primitive between overloads.
20558     #   increment foo
20559     # =>
20560     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
20561     #
20562     # There's a variable on the var stack as follows:
20563     #   name: 'foo'
20564     #   type: int
20565     #   register: 'eax'
20566     #
20567     # There's two primitives, as follows:
20568     #   - name: 'increment'
20569     #     out: int/reg
20570     #     value: 'ff 0/subop/increment'
20571     #   - name: 'increment'
20572     #     inout: int/mem
20573     #     value: 'ff 0/subop/increment'
20574     #
20575     # . prologue
20576     55/push-ebp
20577     89/<- %ebp 4/r32/esp
20578     # setup
20579     (clear-stream _test-output-stream)
20580     (clear-stream $_test-output-buffered-file->buffer)
20581 $test-emit-subx-stmt-select-primitive-2:initialize-type:
20582     # var type/ecx: (payload type-tree) = int
20583     68/push 0/imm32/right:null
20584     68/push 0/imm32/right:null
20585     68/push 0/imm32/left:unused
20586     68/push 1/imm32/value:int
20587     68/push 1/imm32/is-atom?:true
20588     68/push 0x11/imm32/alloc-id:fake:payload
20589     89/<- %ecx 4/r32/esp
20590 $test-emit-subx-stmt-select-primitive-2:initialize-var:
20591     # var var-foo/ecx: (payload var)
20592     68/push 0/imm32/register
20593     68/push 0/imm32/register
20594     68/push 0/imm32/no-stack-offset
20595     68/push 1/imm32/block-depth
20596     51/push-ecx
20597     68/push 0x11/imm32/alloc-id:fake
20598     68/push 0/imm32/name
20599     68/push 0/imm32/name
20600     68/push 0x11/imm32/alloc-id:fake:payload
20601     89/<- %ecx 4/r32/esp
20602 $test-emit-subx-stmt-select-primitive-2:initialize-var-name:
20603     # var-foo->name = "foo"
20604     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20605     (copy-array Heap "foo" %eax)
20606 $test-emit-subx-stmt-select-primitive-2:initialize-var-register:
20607     # var-foo->register = "eax"
20608     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20609     (copy-array Heap "eax" %eax)
20610 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-var:
20611     # var operand/ebx: (payload stmt-var)
20612     68/push 0/imm32/is-deref:false
20613     68/push 0/imm32/next
20614     68/push 0/imm32/next
20615     51/push-ecx/var-foo
20616     68/push 0x11/imm32/alloc-id:fake
20617     68/push 0x11/imm32/alloc-id:fake:payload
20618     89/<- %ebx 4/r32/esp
20619 $test-emit-subx-stmt-select-primitive-2:initialize-stmt:
20620     # var stmt/esi: (addr statement)
20621     68/push 0/imm32/no-outputs
20622     68/push 0/imm32/no-outputs
20623     53/push-ebx/inouts
20624     68/push 0x11/imm32/alloc-id:fake
20625     68/push 0/imm32/operation
20626     68/push 0/imm32/operation
20627     68/push 1/imm32
20628     89/<- %esi 4/r32/esp
20629 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-operation:
20630     # stmt->operation = "increment"
20631     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20632     (copy-array Heap "increment" %eax)
20633 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var:
20634     # var formal-var/ebx: (payload var)
20635     68/push 0/imm32/register
20636     68/push 0/imm32/register
20637     68/push 0/imm32/no-stack-offset
20638     68/push 1/imm32/block-depth
20639     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
20640     68/push 0x11/imm32/alloc-id:fake
20641     68/push 0/imm32/name
20642     68/push 0/imm32/name
20643     68/push 0x11/imm32/alloc-id:fake:payload
20644     89/<- %ebx 4/r32/esp
20645 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var-name:
20646     # formal-var->name = "dummy"
20647     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
20648     (copy-array Heap "dummy" %eax)
20649 $test-emit-subx-stmt-select-primitive-2:initialize-formal-register:
20650     # formal-var->register = "*"
20651     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
20652     (copy-array Heap "*" %eax)  # Any-register
20653 $test-emit-subx-stmt-select-primitive-2:initialize-var-list:
20654     # var formal-outputs/ebx: (payload list stmt-var)
20655     68/push 0/imm32/next
20656     68/push 0/imm32/next
20657     53/push-ebx/formal-var
20658     68/push 0x11/imm32/alloc-id:fake
20659     68/push 0x11/imm32/alloc-id:fake:payload
20660     89/<- %ebx 4/r32/esp
20661 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2:
20662     # var primitive2/edi: (payload primitive)
20663     68/push 0/imm32/next
20664     68/push 0/imm32/next
20665     68/push 0/imm32/output-is-write-only
20666     68/push 0/imm32/no-disp32
20667     68/push 0/imm32/no-imm8
20668     68/push 0/imm32/no-imm32
20669     68/push 0/imm32/no-r32
20670     68/push 3/imm32/rm32-is-first-output
20671     68/push 0/imm32/subx-name
20672     68/push 0/imm32/subx-name
20673     53/push-ebx/outputs
20674     68/push 0x11/imm32/alloc-id:fake
20675     68/push 0/imm32/no-inouts
20676     68/push 0/imm32/no-inouts
20677     68/push 0/imm32/name
20678     68/push 0/imm32/name
20679     68/push 0x11/imm32/alloc-id:fake:payload
20680     89/<- %edi 4/r32/esp
20681 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-name:
20682     # primitives->name = "increment"
20683     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
20684     (copy-array Heap "increment" %eax)
20685 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-subx-name:
20686     # primitives->subx-name = "ff 0/subop/increment"
20687     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
20688     (copy-array Heap "ff 0/subop/increment" %eax)
20689 $test-emit-subx-stmt-select-primitive-2:initialize-primitive:
20690     # var primitives/ebx: (addr primitive)
20691     57/push-edi
20692     68/push 0x11/imm32/alloc-id:fake
20693     68/push 0/imm32/output-is-write-only
20694     68/push 0/imm32/no-disp32
20695     68/push 0/imm32/no-imm8
20696     68/push 0/imm32/no-imm32
20697     68/push 0/imm32/no-r32
20698     68/push 1/imm32/rm32-is-first-inout
20699     68/push 0/imm32/subx-name
20700     68/push 0/imm32/subx-name
20701     68/push 0/imm32/no-outputs
20702     68/push 0/imm32/no-outputs
20703     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
20704     68/push 0x11/imm32/alloc-id:fake
20705     68/push 0/imm32/name
20706     68/push 0/imm32/name
20707     89/<- %ebx 4/r32/esp
20708 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-name:
20709     # primitives->name = "increment"
20710     (copy-array Heap "increment" %ebx)  # Primitive-name
20711 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-subx-name:
20712     # primitives->subx-name = "ff 0/subop/increment"
20713     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
20714     (copy-array Heap "ff 0/subop/increment" %eax)
20715     # convert
20716     c7 0/subop/copy *Curr-block-depth 0/imm32
20717     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
20718     (flush _test-output-buffered-file)
20719 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20725     # check output
20726     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive-2")
20727     # . epilogue
20728     89/<- %esp 5/r32/ebp
20729     5d/pop-to-ebp
20730     c3/return
20731 
20732 test-increment-register:
20733     # Select the right register between overloads.
20734     #   foo <- increment
20735     # =>
20736     #   50/increment-eax
20737     #
20738     # There's a variable on the var stack as follows:
20739     #   name: 'foo'
20740     #   type: int
20741     #   register: 'eax'
20742     #
20743     # Primitives are the global definitions.
20744     #
20745     # . prologue
20746     55/push-ebp
20747     89/<- %ebp 4/r32/esp
20748     # setup
20749     (clear-stream _test-output-stream)
20750     (clear-stream $_test-output-buffered-file->buffer)
20751 $test-increment-register:initialize-type:
20752     # var type/ecx: (payload type-tree) = int
20753     68/push 0/imm32/right:null
20754     68/push 0/imm32/right:null
20755     68/push 0/imm32/left:unused
20756     68/push 1/imm32/value:int
20757     68/push 1/imm32/is-atom?:true
20758     68/push 0x11/imm32/alloc-id:fake:payload
20759     89/<- %ecx 4/r32/esp
20760 $test-increment-register:initialize-var:
20761     # var var-foo/ecx: (payload var)
20762     68/push 0/imm32/register
20763     68/push 0/imm32/register
20764     68/push 0/imm32/no-stack-offset
20765     68/push 1/imm32/block-depth
20766     51/push-ecx
20767     68/push 0x11/imm32/alloc-id:fake
20768     68/push 0/imm32/name
20769     68/push 0/imm32/name
20770     68/push 0x11/imm32/alloc-id:fake:payload
20771     89/<- %ecx 4/r32/esp
20772 $test-increment-register:initialize-var-name:
20773     # var-foo->name = "foo"
20774     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20775     (copy-array Heap "foo" %eax)
20776 $test-increment-register:initialize-var-register:
20777     # var-foo->register = "eax"
20778     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20779     (copy-array Heap "eax" %eax)
20780 $test-increment-register:initialize-stmt-var:
20781     # var operand/ebx: (payload stmt-var)
20782     68/push 0/imm32/is-deref:false
20783     68/push 0/imm32/next
20784     68/push 0/imm32/next
20785     51/push-ecx/var-foo
20786     68/push 0x11/imm32/alloc-id:fake
20787     68/push 0x11/imm32/alloc-id:fake:payload
20788     89/<- %ebx 4/r32/esp
20789 $test-increment-register:initialize-stmt:
20790     # var stmt/esi: (addr statement)
20791     53/push-ebx/outputs
20792     68/push 0x11/imm32/alloc-id:fake
20793     68/push 0/imm32/no-inouts
20794     68/push 0/imm32/no-inouts
20795     68/push 0/imm32/operation
20796     68/push 0/imm32/operation
20797     68/push 1/imm32
20798     89/<- %esi 4/r32/esp
20799 $test-increment-register:initialize-stmt-operation:
20800     # stmt->operation = "increment"
20801     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20802     (copy-array Heap "increment" %eax)
20803     # convert
20804     c7 0/subop/copy *Curr-block-depth 0/imm32
20805     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
20806     (flush _test-output-buffered-file)
20807 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20813     # check output
20814     (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register")
20815     # . epilogue
20816     89/<- %esp 5/r32/ebp
20817     5d/pop-to-ebp
20818     c3/return
20819 
20820 test-add-reg-to-reg:
20821     #   var1/reg <- add var2/reg
20822     # =>
20823     #   01/add-to %var1 var2
20824     #
20825     # . prologue
20826     55/push-ebp
20827     89/<- %ebp 4/r32/esp
20828     # setup
20829     (clear-stream _test-output-stream)
20830     (clear-stream $_test-output-buffered-file->buffer)
20831 $test-add-reg-to-reg:initialize-type:
20832     # var type/ecx: (payload type-tree) = int
20833     68/push 0/imm32/right:null
20834     68/push 0/imm32/right:null
20835     68/push 0/imm32/left:unused
20836     68/push 1/imm32/value:int
20837     68/push 1/imm32/is-atom?:true
20838     68/push 0x11/imm32/alloc-id:fake:payload
20839     89/<- %ecx 4/r32/esp
20840 $test-add-reg-to-reg:initialize-var1:
20841     # var var1/ecx: (payload var)
20842     68/push 0/imm32/register
20843     68/push 0/imm32/register
20844     68/push 0/imm32/no-stack-offset
20845     68/push 1/imm32/block-depth
20846     51/push-ecx
20847     68/push 0x11/imm32/alloc-id:fake
20848     68/push 0/imm32/name
20849     68/push 0/imm32/name
20850     68/push 0x11/imm32/alloc-id:fake:payload
20851     89/<- %ecx 4/r32/esp
20852 $test-add-reg-to-reg:initialize-var1-name:
20853     # var1->name = "var1"
20854     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20855     (copy-array Heap "var1" %eax)
20856 $test-add-reg-to-reg:initialize-var1-register:
20857     # var1->register = "eax"
20858     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20859     (copy-array Heap "eax" %eax)
20860 $test-add-reg-to-reg:initialize-var2:
20861     # var var2/edx: (payload var)
20862     68/push 0/imm32/register
20863     68/push 0/imm32/register
20864     68/push 0/imm32/no-stack-offset
20865     68/push 1/imm32/block-depth
20866     ff 6/subop/push *(ecx+0x10)
20867     68/push 0x11/imm32/alloc-id:fake
20868     68/push 0/imm32/name
20869     68/push 0/imm32/name
20870     68/push 0x11/imm32/alloc-id:fake:payload
20871     89/<- %edx 4/r32/esp
20872 $test-add-reg-to-reg:initialize-var2-name:
20873     # var2->name = "var2"
20874     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
20875     (copy-array Heap "var2" %eax)
20876 $test-add-reg-to-reg:initialize-var2-register:
20877     # var2->register = "ecx"
20878     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
20879     (copy-array Heap "ecx" %eax)
20880 $test-add-reg-to-reg:initialize-inouts:
20881     # var inouts/esi: (payload stmt-var) = [var2]
20882     68/push 0/imm32/is-deref:false
20883     68/push 0/imm32/next
20884     68/push 0/imm32/next
20885     52/push-edx/var2
20886     68/push 0x11/imm32/alloc-id:fake
20887     68/push 0x11/imm32/alloc-id:fake:payload
20888     89/<- %esi 4/r32/esp
20889 $test-add-reg-to-reg:initialize-outputs:
20890     # var outputs/edi: (payload stmt-var) = [var1]
20891     68/push 0/imm32/is-deref:false
20892     68/push 0/imm32/next
20893     68/push 0/imm32/next
20894     51/push-ecx/var1
20895     68/push 0x11/imm32/alloc-id:fake
20896     68/push 0x11/imm32/alloc-id:fake:payload
20897     89/<- %edi 4/r32/esp
20898 $test-add-reg-to-reg:initialize-stmt:
20899     # var stmt/esi: (addr statement)
20900     68/push 0/imm32/next
20901     68/push 0/imm32/next
20902     57/push-edi/outputs
20903     68/push 0x11/imm32/alloc-id:fake
20904     56/push-esi/inouts
20905     68/push 0x11/imm32/alloc-id:fake
20906     68/push 0/imm32/operation
20907     68/push 0/imm32/operation
20908     68/push 1/imm32/tag:stmt1
20909     89/<- %esi 4/r32/esp
20910 $test-add-reg-to-reg:initialize-stmt-operation:
20911     # stmt->operation = "add"
20912     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20913     (copy-array Heap "add" %eax)
20914     # convert
20915     c7 0/subop/copy *Curr-block-depth 0/imm32
20916     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
20917     (flush _test-output-buffered-file)
20918 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20924     # check output
20925     (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg")
20926     # . epilogue
20927     89/<- %esp 5/r32/ebp
20928     5d/pop-to-ebp
20929     c3/return
20930 
20931 test-add-reg-to-mem:
20932     #   add-to var1 var2/reg
20933     # =>
20934     #   01/add-to *(ebp+__) var2
20935     #
20936     # . prologue
20937     55/push-ebp
20938     89/<- %ebp 4/r32/esp
20939     # setup
20940     (clear-stream _test-output-stream)
20941     (clear-stream $_test-output-buffered-file->buffer)
20942 $test-add-reg-to-mem:initialize-type:
20943     # var type/ecx: (payload type-tree) = int
20944     68/push 0/imm32/right:null
20945     68/push 0/imm32/right:null
20946     68/push 0/imm32/left:unused
20947     68/push 1/imm32/value:int
20948     68/push 1/imm32/is-atom?:true
20949     68/push 0x11/imm32/alloc-id:fake:payload
20950     89/<- %ecx 4/r32/esp
20951 $test-add-reg-to-mem:initialize-var1:
20952     # var var1/ecx: (payload var)
20953     68/push 0/imm32/register
20954     68/push 0/imm32/register
20955     68/push 8/imm32/stack-offset
20956     68/push 1/imm32/block-depth
20957     51/push-ecx
20958     68/push 0x11/imm32/alloc-id:fake
20959     68/push 0/imm32/name
20960     68/push 0/imm32/name
20961     68/push 0x11/imm32/alloc-id:fake:payload
20962     89/<- %ecx 4/r32/esp
20963 $test-add-reg-to-mem:initialize-var1-name:
20964     # var1->name = "var1"
20965     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20966     (copy-array Heap "var1" %eax)
20967 $test-add-reg-to-mem:initialize-var2:
20968     # var var2/edx: (payload var)
20969     68/push 0/imm32/register
20970     68/push 0/imm32/register
20971     68/push 0/imm32/no-stack-offset
20972     68/push 1/imm32/block-depth
20973     ff 6/subop/push *(ecx+0x10)
20974     68/push 0x11/imm32/alloc-id:fake
20975     68/push 0/imm32/name
20976     68/push 0/imm32/name
20977     68/push 0x11/imm32/alloc-id:fake:payload
20978     89/<- %edx 4/r32/esp
20979 $test-add-reg-to-mem:initialize-var2-name:
20980     # var2->name = "var2"
20981     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
20982     (copy-array Heap "var2" %eax)
20983 $test-add-reg-to-mem:initialize-var2-register:
20984     # var2->register = "ecx"
20985     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
20986     (copy-array Heap "ecx" %eax)
20987 $test-add-reg-to-mem:initialize-inouts:
20988     # var inouts/esi: (payload stmt-var) = [var2]
20989     68/push 0/imm32/is-deref:false
20990     68/push 0/imm32/next
20991     68/push 0/imm32/next
20992     52/push-edx/var2
20993     68/push 0x11/imm32/alloc-id:fake
20994     68/push 0x11/imm32/alloc-id:fake:payload
20995     89/<- %esi 4/r32/esp
20996     # inouts = [var1, var2]
20997     68/push 0/imm32/is-deref:false
20998     56/push-esi/next
20999     68/push 0x11/imm32/alloc-id:fake
21000     51/push-ecx/var1
21001     68/push 0x11/imm32/alloc-id:fake
21002     68/push 0x11/imm32/alloc-id:fake:payload
21003     89/<- %esi 4/r32/esp
21004 $test-add-reg-to-mem:initialize-stmt:
21005     # var stmt/esi: (addr statement)
21006     68/push 0/imm32/next
21007     68/push 0/imm32/next
21008     68/push 0/imm32/outputs
21009     68/push 0/imm32/outputs
21010     56/push-esi/inouts
21011     68/push 0x11/imm32/alloc-id:fake
21012     68/push 0/imm32/operation
21013     68/push 0/imm32/operation
21014     68/push 1/imm32/tag:stmt1
21015     89/<- %esi 4/r32/esp
21016 $test-add-reg-to-mem:initialize-stmt-operation:
21017     # stmt->operation = "add-to"
21018     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21019     (copy-array Heap "add-to" %eax)
21020     # convert
21021     c7 0/subop/copy *Curr-block-depth 0/imm32
21022     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21023     (flush _test-output-buffered-file)
21024 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21030     # check output
21031     (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem")
21032     # . epilogue
21033     89/<- %esp 5/r32/ebp
21034     5d/pop-to-ebp
21035     c3/return
21036 
21037 test-add-mem-to-reg:
21038     #   var1/reg <- add var2
21039     # =>
21040     #   03/add *(ebp+__) var1
21041     #
21042     # . prologue
21043     55/push-ebp
21044     89/<- %ebp 4/r32/esp
21045     # setup
21046     (clear-stream _test-output-stream)
21047     (clear-stream $_test-output-buffered-file->buffer)
21048 $test-add-mem-to-reg:initialize-type:
21049     # var type/ecx: (payload type-tree) = int
21050     68/push 0/imm32/right:null
21051     68/push 0/imm32/right:null
21052     68/push 0/imm32/left:unused
21053     68/push 1/imm32/value:int
21054     68/push 1/imm32/is-atom?:true
21055     68/push 0x11/imm32/alloc-id:fake:payload
21056     89/<- %ecx 4/r32/esp
21057 $test-add-mem-to-reg:initialize-var:
21058     # var var1/ecx: (payload var)
21059     68/push 0/imm32/register
21060     68/push 0/imm32/register
21061     68/push 0/imm32/no-stack-offset
21062     68/push 1/imm32/block-depth
21063     51/push-ecx
21064     68/push 0x11/imm32/alloc-id:fake
21065     68/push 0/imm32/name
21066     68/push 0/imm32/name
21067     68/push 0x11/imm32/alloc-id:fake:payload
21068     89/<- %ecx 4/r32/esp
21069 $test-add-mem-to-reg:initialize-var-name:
21070     # var1->name = "foo"
21071     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21072     (copy-array Heap "var1" %eax)
21073 $test-add-mem-to-reg:initialize-var-register:
21074     # var1->register = "eax"
21075     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21076     (copy-array Heap "eax" %eax)
21077 $test-add-mem-to-reg:initialize-var2:
21078     # var var2/edx: (payload var)
21079     68/push 0/imm32/register
21080     68/push 0/imm32/register
21081     68/push 8/imm32/stack-offset
21082     68/push 1/imm32/block-depth
21083     ff 6/subop/push *(ecx+0x10)
21084     68/push 0x11/imm32/alloc-id:fake
21085     68/push 0/imm32/name
21086     68/push 0/imm32/name
21087     68/push 0x11/imm32/alloc-id:fake:payload
21088     89/<- %edx 4/r32/esp
21089 $test-add-mem-to-reg:initialize-var2-name:
21090     # var2->name = "var2"
21091     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21092     (copy-array Heap "var2" %eax)
21093 $test-add-mem-to-reg:initialize-inouts:
21094     # var inouts/esi: (payload stmt-var) = [var2]
21095     68/push 0/imm32/is-deref:false
21096     68/push 0/imm32/next
21097     68/push 0/imm32/next
21098     52/push-edx/var2
21099     68/push 0x11/imm32/alloc-id:fake
21100     68/push 0x11/imm32/alloc-id:fake:payload
21101     89/<- %esi 4/r32/esp
21102 $test-add-mem-to-reg:initialize-outputs:
21103     # var outputs/edi: (payload stmt-var) = [var1]
21104     68/push 0/imm32/is-deref:false
21105     68/push 0/imm32/next
21106     68/push 0/imm32/next
21107     51/push-ecx/var1
21108     68/push 0x11/imm32/alloc-id:fake
21109     68/push 0x11/imm32/alloc-id:fake:payload
21110     89/<- %edi 4/r32/esp
21111 $test-add-mem-to-reg:initialize-stmt:
21112     # var stmt/esi: (addr statement)
21113     68/push 0/imm32/next
21114     68/push 0/imm32/next
21115     57/push-edi/outputs
21116     68/push 0x11/imm32/alloc-id:fake
21117     56/push-esi/inouts
21118     68/push 0x11/imm32/alloc-id:fake
21119     68/push 0/imm32/operation
21120     68/push 0/imm32/operation
21121     68/push 1/imm32/tag:stmt1
21122     89/<- %esi 4/r32/esp
21123 $test-add-mem-to-reg:initialize-stmt-operation:
21124     # stmt->operation = "add"
21125     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21126     (copy-array Heap "add" %eax)
21127     # convert
21128     c7 0/subop/copy *Curr-block-depth 0/imm32
21129     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21130     (flush _test-output-buffered-file)
21131 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21137     # check output
21138     (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg")
21139     # . epilogue
21140     89/<- %esp 5/r32/ebp
21141     5d/pop-to-ebp
21142     c3/return
21143 
21144 test-add-literal-to-eax:
21145     #   var1/eax <- add 0x34
21146     # =>
21147     #   05/add-to-eax 0x34/imm32
21148     #
21149     # . prologue
21150     55/push-ebp
21151     89/<- %ebp 4/r32/esp
21152     # setup
21153     (clear-stream _test-output-stream)
21154     (clear-stream $_test-output-buffered-file->buffer)
21155 $test-add-literal-to-eax:initialize-var-type:
21156     # var type/ecx: (payload type-tree) = int
21157     68/push 0/imm32/right:null
21158     68/push 0/imm32/right:null
21159     68/push 0/imm32/left:unused
21160     68/push 1/imm32/value:int
21161     68/push 1/imm32/is-atom?:true
21162     68/push 0x11/imm32/alloc-id:fake:payload
21163     89/<- %ecx 4/r32/esp
21164 $test-add-literal-to-eax:initialize-var:
21165     # var v/ecx: (payload var)
21166     68/push 0/imm32/register
21167     68/push 0/imm32/register
21168     68/push 0/imm32/no-stack-offset
21169     68/push 1/imm32/block-depth
21170     51/push-ecx
21171     68/push 0x11/imm32/alloc-id:fake
21172     68/push 0/imm32/name
21173     68/push 0/imm32/name
21174     68/push 0x11/imm32/alloc-id:fake:payload
21175     89/<- %ecx 4/r32/esp
21176 $test-add-literal-to-eax:initialize-var-name:
21177     # v->name = "v"
21178     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21179     (copy-array Heap "v" %eax)
21180 $test-add-literal-to-eax:initialize-var-register:
21181     # v->register = "eax"
21182     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21183     (copy-array Heap "eax" %eax)
21184 $test-add-literal-to-eax:initialize-literal-type:
21185     # var type/edx: (payload type-tree) = literal
21186     68/push 0/imm32/right:null
21187     68/push 0/imm32/right:null
21188     68/push 0/imm32/left:unused
21189     68/push 0/imm32/value:literal
21190     68/push 1/imm32/is-atom?:true
21191     68/push 0x11/imm32/alloc-id:fake:payload
21192     89/<- %edx 4/r32/esp
21193 $test-add-literal-to-eax:initialize-literal:
21194     # var l/edx: (payload var)
21195     68/push 0/imm32/register
21196     68/push 0/imm32/register
21197     68/push 0/imm32/no-stack-offset
21198     68/push 1/imm32/block-depth
21199     52/push-edx
21200     68/push 0x11/imm32/alloc-id:fake
21201     68/push 0/imm32/name
21202     68/push 0/imm32/name
21203     68/push 0x11/imm32/alloc-id:fake:payload
21204     89/<- %edx 4/r32/esp
21205 $test-add-literal-to-eax:initialize-literal-value:
21206     # l->name = "0x34"
21207     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21208     (copy-array Heap "0x34" %eax)
21209 $test-add-literal-to-eax:initialize-inouts:
21210     # var inouts/esi: (payload stmt-var) = [l]
21211     68/push 0/imm32/is-deref:false
21212     68/push 0/imm32/next
21213     68/push 0/imm32/next
21214     52/push-edx/l
21215     68/push 0x11/imm32/alloc-id:fake
21216     68/push 0x11/imm32/alloc-id:fake:payload
21217     89/<- %esi 4/r32/esp
21218 $test-add-literal-to-eax:initialize-outputs:
21219     # var outputs/edi: (payload stmt-var) = [v]
21220     68/push 0/imm32/is-deref:false
21221     68/push 0/imm32/next
21222     68/push 0/imm32/next
21223     51/push-ecx/v
21224     68/push 0x11/imm32/alloc-id:fake
21225     68/push 0x11/imm32/alloc-id:fake:payload
21226     89/<- %edi 4/r32/esp
21227 $test-add-literal-to-eax:initialize-stmt:
21228     # var stmt/esi: (addr statement)
21229     68/push 0/imm32/next
21230     68/push 0/imm32/next
21231     57/push-edi/outputs
21232     68/push 0x11/imm32/alloc-id:fake
21233     56/push-esi/inouts
21234     68/push 0x11/imm32/alloc-id:fake
21235     68/push 0/imm32/operation
21236     68/push 0/imm32/operation
21237     68/push 1/imm32/tag:stmt1
21238     89/<- %esi 4/r32/esp
21239 $test-add-literal-to-eax:initialize-stmt-operation:
21240     # stmt->operation = "add"
21241     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21242     (copy-array Heap "add" %eax)
21243     # convert
21244     c7 0/subop/copy *Curr-block-depth 0/imm32
21245     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21246     (flush _test-output-buffered-file)
21247 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21253     # check output
21254     (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax")
21255     # . epilogue
21256     89/<- %esp 5/r32/ebp
21257     5d/pop-to-ebp
21258     c3/return
21259 
21260 test-add-literal-to-reg:
21261     #   var1/ecx <- add 0x34
21262     # =>
21263     #   81 0/subop/add %ecx 0x34/imm32
21264     #
21265     # . prologue
21266     55/push-ebp
21267     89/<- %ebp 4/r32/esp
21268     # setup
21269     (clear-stream _test-output-stream)
21270     (clear-stream $_test-output-buffered-file->buffer)
21271 $test-add-literal-to-reg:initialize-var-type:
21272     # var type/ecx: (payload type-tree) = int
21273     68/push 0/imm32/right:null
21274     68/push 0/imm32/right:null
21275     68/push 0/imm32/left:unused
21276     68/push 1/imm32/value:int
21277     68/push 1/imm32/is-atom?:true
21278     68/push 0x11/imm32/alloc-id:fake:payload
21279     89/<- %ecx 4/r32/esp
21280 $test-add-literal-to-reg:initialize-var:
21281     # var v/ecx: (payload var)
21282     68/push 0/imm32/register
21283     68/push 0/imm32/register
21284     68/push 0/imm32/no-stack-offset
21285     68/push 1/imm32/block-depth
21286     51/push-ecx
21287     68/push 0x11/imm32/alloc-id:fake
21288     68/push 0/imm32/name
21289     68/push 0/imm32/name
21290     68/push 0x11/imm32/alloc-id:fake:payload
21291     89/<- %ecx 4/r32/esp
21292 $test-add-literal-to-reg:initialize-var-name:
21293     # v->name = "v"
21294     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21295     (copy-array Heap "v" %eax)
21296 $test-add-literal-to-reg:initialize-var-register:
21297     # v->register = "ecx"
21298     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21299     (copy-array Heap "ecx" %eax)
21300 $test-add-literal-to-reg:initialize-literal-type:
21301     # var type/edx: (payload type-tree) = literal
21302     68/push 0/imm32/right:null
21303     68/push 0/imm32/right:null
21304     68/push 0/imm32/left:unused
21305     68/push 0/imm32/value:literal
21306     68/push 1/imm32/is-atom?:true
21307     68/push 0x11/imm32/alloc-id:fake:payload
21308     89/<- %edx 4/r32/esp
21309 $test-add-literal-to-reg:initialize-literal:
21310     # var l/edx: (payload var)
21311     68/push 0/imm32/register
21312     68/push 0/imm32/register
21313     68/push 0/imm32/no-stack-offset
21314     68/push 1/imm32/block-depth
21315     52/push-edx
21316     68/push 0x11/imm32/alloc-id:fake
21317     68/push 0/imm32/name
21318     68/push 0/imm32/name
21319     68/push 0x11/imm32/alloc-id:fake:payload
21320     89/<- %edx 4/r32/esp
21321 $test-add-literal-to-reg:initialize-literal-value:
21322     # l->name = "0x34"
21323     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21324     (copy-array Heap "0x34" %eax)
21325 $test-add-literal-to-reg:initialize-inouts:
21326     # var inouts/esi: (payload stmt-var) = [l]
21327     68/push 0/imm32/is-deref:false
21328     68/push 0/imm32/next
21329     68/push 0/imm32/next
21330     52/push-edx/l
21331     68/push 0x11/imm32/alloc-id:fake
21332     68/push 0x11/imm32/alloc-id:fake:payload
21333     89/<- %esi 4/r32/esp
21334 $test-add-literal-to-reg:initialize-outputs:
21335     # var outputs/edi: (payload stmt-var) = [v]
21336     68/push 0/imm32/is-deref:false
21337     68/push 0/imm32/next
21338     68/push 0/imm32/next
21339     51/push-ecx/v
21340     68/push 0x11/imm32/alloc-id:fake
21341     68/push 0x11/imm32/alloc-id:fake:payload
21342     89/<- %edi 4/r32/esp
21343 $test-add-literal-to-reg:initialize-stmt:
21344     # var stmt/esi: (addr statement)
21345     68/push 0/imm32/next
21346     68/push 0/imm32/next
21347     57/push-edi/outputs
21348     68/push 0x11/imm32/alloc-id:fake
21349     56/push-esi/inouts
21350     68/push 0x11/imm32/alloc-id:fake
21351     68/push 0/imm32/operation
21352     68/push 0/imm32/operation
21353     68/push 1/imm32/tag:stmt1
21354     89/<- %esi 4/r32/esp
21355 $test-add-literal-to-reg:initialize-stmt-operation:
21356     # stmt->operation = "add"
21357     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21358     (copy-array Heap "add" %eax)
21359     # convert
21360     c7 0/subop/copy *Curr-block-depth 0/imm32
21361     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21362     (flush _test-output-buffered-file)
21363 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21369     # check output
21370     (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg")
21371     # . epilogue
21372     89/<- %esp 5/r32/ebp
21373     5d/pop-to-ebp
21374     c3/return
21375 
21376 test-add-literal-to-mem:
21377     #   add-to var1, 0x34
21378     # =>
21379     #   81 0/subop/add %eax 0x34/imm32
21380     #
21381     # . prologue
21382     55/push-ebp
21383     89/<- %ebp 4/r32/esp
21384     # setup
21385     (clear-stream _test-output-stream)
21386     (clear-stream $_test-output-buffered-file->buffer)
21387 $test-add-literal-to-mem:initialize-type:
21388     # var type/ecx: (payload type-tree) = int
21389     68/push 0/imm32/right:null
21390     68/push 0/imm32/right:null
21391     68/push 0/imm32/left:unused
21392     68/push 1/imm32/value:int
21393     68/push 1/imm32/is-atom?:true
21394     68/push 0x11/imm32/alloc-id:fake:payload
21395     89/<- %ecx 4/r32/esp
21396 $test-add-literal-to-mem:initialize-var1:
21397     # var var1/ecx: (payload var)
21398     68/push 0/imm32/register
21399     68/push 0/imm32/register
21400     68/push 8/imm32/stack-offset
21401     68/push 1/imm32/block-depth
21402     51/push-ecx
21403     68/push 0x11/imm32/alloc-id:fake
21404     68/push 0/imm32/name
21405     68/push 0/imm32/name
21406     68/push 0x11/imm32/alloc-id:fake:payload
21407     89/<- %ecx 4/r32/esp
21408 $test-add-literal-to-mem:initialize-var1-name:
21409     # var1->name = "var1"
21410     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21411     (copy-array Heap "var1" %eax)
21412 $test-add-literal-to-mem:initialize-literal-type:
21413     # var type/edx: (payload type-tree) = literal
21414     68/push 0/imm32/right:null
21415     68/push 0/imm32/right:null
21416     68/push 0/imm32/left:unused
21417     68/push 0/imm32/value:literal
21418     68/push 1/imm32/is-atom?:true
21419     68/push 0x11/imm32/alloc-id:fake:payload
21420     89/<- %edx 4/r32/esp
21421 $test-add-literal-to-mem:initialize-literal:
21422     # var l/edx: (payload var)
21423     68/push 0/imm32/register
21424     68/push 0/imm32/register
21425     68/push 0/imm32/no-stack-offset
21426     68/push 1/imm32/block-depth
21427     52/push-edx
21428     68/push 0x11/imm32/alloc-id:fake
21429     68/push 0/imm32/name
21430     68/push 0/imm32/name
21431     68/push 0x11/imm32/alloc-id:fake:payload
21432     89/<- %edx 4/r32/esp
21433 $test-add-literal-to-mem:initialize-literal-value:
21434     # l->name = "0x34"
21435     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21436     (copy-array Heap "0x34" %eax)
21437 $test-add-literal-to-mem:initialize-inouts:
21438     # var inouts/esi: (payload stmt-var) = [l]
21439     68/push 0/imm32/is-deref:false
21440     68/push 0/imm32/next
21441     68/push 0/imm32/next
21442     52/push-edx/l
21443     68/push 0x11/imm32/alloc-id:fake
21444     68/push 0x11/imm32/alloc-id:fake:payload
21445     89/<- %esi 4/r32/esp
21446     # var inouts = (handle stmt-var) = [var1, var2]
21447     68/push 0/imm32/is-deref:false
21448     56/push-esi/next
21449     68/push 0x11/imm32/alloc-id:fake
21450     51/push-ecx/var1
21451     68/push 0x11/imm32/alloc-id:fake
21452     68/push 0x11/imm32/alloc-id:fake:payload
21453     89/<- %esi 4/r32/esp
21454 $test-add-literal-to-mem:initialize-stmt:
21455     # var stmt/esi: (addr statement)
21456     68/push 0/imm32/next
21457     68/push 0/imm32/next
21458     68/push 0/imm32/outputs
21459     68/push 0/imm32/outputs
21460     56/push-esi/inouts
21461     68/push 0x11/imm32/alloc-id:fake
21462     68/push 0/imm32/operation
21463     68/push 0/imm32/operation
21464     68/push 1/imm32/tag:stmt1
21465     89/<- %esi 4/r32/esp
21466 $test-add-literal-to-mem:initialize-stmt-operation:
21467     # stmt->operation = "add-to"
21468     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21469     (copy-array Heap "add-to" %eax)
21470     # convert
21471     c7 0/subop/copy *Curr-block-depth 0/imm32
21472     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21473     (flush _test-output-buffered-file)
21474 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21480     # check output
21481     (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem")
21482     # . epilogue
21483     89/<- %esp 5/r32/ebp
21484     5d/pop-to-ebp
21485     c3/return
21486 
21487 test-shift-reg-by-literal:
21488     #   var1/ecx <- shift-left 2
21489     # =>
21490     #   c1/shift 4/subop/left %ecx 2/imm8
21491     #
21492     # . prologue
21493     55/push-ebp
21494     89/<- %ebp 4/r32/esp
21495     # setup
21496     (clear-stream _test-output-stream)
21497     (clear-stream $_test-output-buffered-file->buffer)
21498 $test-shift-reg-by-literal:initialize-var-type:
21499     # var type/ecx: (payload type-tree) = int
21500     68/push 0/imm32/right:null
21501     68/push 0/imm32/right:null
21502     68/push 0/imm32/left:unused
21503     68/push 1/imm32/value:int
21504     68/push 1/imm32/is-atom?:true
21505     68/push 0x11/imm32/alloc-id:fake:payload
21506     89/<- %ecx 4/r32/esp
21507 $test-shift-reg-by-literal:initialize-var:
21508     # var v/ecx: (payload var)
21509     68/push 0/imm32/register
21510     68/push 0/imm32/register
21511     68/push 0/imm32/no-stack-offset
21512     68/push 1/imm32/block-depth
21513     51/push-ecx
21514     68/push 0x11/imm32/alloc-id:fake
21515     68/push 0/imm32/name
21516     68/push 0/imm32/name
21517     68/push 0x11/imm32/alloc-id:fake:payload
21518     89/<- %ecx 4/r32/esp
21519 $test-shift-reg-by-literal:initialize-var-name:
21520     # v->name = "v"
21521     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21522     (copy-array Heap "v" %eax)
21523 $test-shift-reg-by-literal:initialize-var-register:
21524     # v->register = "ecx"
21525     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21526     (copy-array Heap "ecx" %eax)
21527 $test-shift-reg-by-literal:initialize-literal-type:
21528     # var type/edx: (payload type-tree) = literal
21529     68/push 0/imm32/right:null
21530     68/push 0/imm32/right:null
21531     68/push 0/imm32/left:unused
21532     68/push 0/imm32/value:literal
21533     68/push 1/imm32/is-atom?:true
21534     68/push 0x11/imm32/alloc-id:fake:payload
21535     89/<- %edx 4/r32/esp
21536 $test-shift-reg-by-literal:initialize-literal:
21537     # var l/edx: (payload var)
21538     68/push 0/imm32/register
21539     68/push 0/imm32/register
21540     68/push 0/imm32/no-stack-offset
21541     68/push 1/imm32/block-depth
21542     52/push-edx
21543     68/push 0x11/imm32/alloc-id:fake
21544     68/push 0/imm32/name
21545     68/push 0/imm32/name
21546     68/push 0x11/imm32/alloc-id:fake:payload
21547     89/<- %edx 4/r32/esp
21548 $test-shift-reg-by-literal:initialize-literal-value:
21549     # l->name = "2"
21550     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21551     (copy-array Heap "2" %eax)
21552 $test-shift-reg-by-literal:initialize-inouts:
21553     # var inouts/esi: (payload stmt-var) = [l]
21554     68/push 0/imm32/is-deref:false
21555     68/push 0/imm32/next
21556     68/push 0/imm32/next
21557     52/push-edx/l
21558     68/push 0x11/imm32/alloc-id:fake
21559     68/push 0x11/imm32/alloc-id:fake:payload
21560     89/<- %esi 4/r32/esp
21561 $test-shift-reg-by-literal:initialize-outputs:
21562     # var outputs/edi: (payload stmt-var) = [v]
21563     68/push 0/imm32/is-deref:false
21564     68/push 0/imm32/next
21565     68/push 0/imm32/next
21566     51/push-ecx/v
21567     68/push 0x11/imm32/alloc-id:fake
21568     68/push 0x11/imm32/alloc-id:fake:payload
21569     89/<- %edi 4/r32/esp
21570 $test-shift-reg-by-literal:initialize-stmt:
21571     # var stmt/esi: (addr statement)
21572     68/push 0/imm32/next
21573     68/push 0/imm32/next
21574     57/push-edi/outputs
21575     68/push 0x11/imm32/alloc-id:fake
21576     56/push-esi/inouts
21577     68/push 0x11/imm32/alloc-id:fake
21578     68/push 0/imm32/operation
21579     68/push 0/imm32/operation
21580     68/push 1/imm32/tag:stmt1
21581     89/<- %esi 4/r32/esp
21582 $test-shift-reg-by-literal:initialize-stmt-operation:
21583     # stmt->operation = "shift-left"
21584     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21585     (copy-array Heap "shift-left" %eax)
21586     # convert
21587     c7 0/subop/copy *Curr-block-depth 0/imm32
21588     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21589     (flush _test-output-buffered-file)
21590 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21596     # check output
21597     (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left %ecx 2/imm8" "F - test-shift-reg-by-literal")
21598     # . epilogue
21599     89/<- %esp 5/r32/ebp
21600     5d/pop-to-ebp
21601     c3/return
21602 
21603 test-shift-mem-by-literal:
21604     #   shift-left var 3
21605     # =>
21606     #   c1/shift 4/subop/left *(ebp+8) 3/imm8
21607     #
21608     # . prologue
21609     55/push-ebp
21610     89/<- %ebp 4/r32/esp
21611     # setup
21612     (clear-stream _test-output-stream)
21613     (clear-stream $_test-output-buffered-file->buffer)
21614 $test-shift-mem-by-literal:initialize-type:
21615     # var type/ecx: (payload type-tree) = int
21616     68/push 0/imm32/right:null
21617     68/push 0/imm32/right:null
21618     68/push 0/imm32/left:unused
21619     68/push 1/imm32/value:int
21620     68/push 1/imm32/is-atom?:true
21621     68/push 0x11/imm32/alloc-id:fake:payload
21622     89/<- %ecx 4/r32/esp
21623 $test-shift-mem-by-literal:initialize-var1:
21624     # var var1/ecx: (payload var)
21625     68/push 0/imm32/register
21626     68/push 0/imm32/register
21627     68/push 8/imm32/stack-offset
21628     68/push 1/imm32/block-depth
21629     51/push-ecx
21630     68/push 0x11/imm32/alloc-id:fake
21631     68/push 0/imm32/name
21632     68/push 0/imm32/name
21633     68/push 0x11/imm32/alloc-id:fake:payload
21634     89/<- %ecx 4/r32/esp
21635 $test-shift-mem-by-literal:initialize-var1-name:
21636     # var1->name = "var1"
21637     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21638     (copy-array Heap "var1" %eax)
21639 $test-shift-mem-by-literal:initialize-literal-type:
21640     # var type/edx: (payload type-tree) = literal
21641     68/push 0/imm32/right:null
21642     68/push 0/imm32/right:null
21643     68/push 0/imm32/left:unused
21644     68/push 0/imm32/value:literal
21645     68/push 1/imm32/is-atom?:true
21646     68/push 0x11/imm32/alloc-id:fake:payload
21647     89/<- %edx 4/r32/esp
21648 $test-shift-mem-by-literal:initialize-literal:
21649     # var l/edx: (payload var)
21650     68/push 0/imm32/register
21651     68/push 0/imm32/register
21652     68/push 0/imm32/no-stack-offset
21653     68/push 1/imm32/block-depth
21654     52/push-edx
21655     68/push 0x11/imm32/alloc-id:fake
21656     68/push 0/imm32/name
21657     68/push 0/imm32/name
21658     68/push 0x11/imm32/alloc-id:fake:payload
21659     89/<- %edx 4/r32/esp
21660 $test-shift-mem-by-literal:initialize-literal-value:
21661     # l->name = "3"
21662     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21663     (copy-array Heap "3" %eax)
21664 $test-shift-mem-by-literal:initialize-inouts:
21665     # var inouts/esi: (payload stmt-var) = [l]
21666     68/push 0/imm32/is-deref:false
21667     68/push 0/imm32/next
21668     68/push 0/imm32/next
21669     52/push-edx/l
21670     68/push 0x11/imm32/alloc-id:fake
21671     68/push 0x11/imm32/alloc-id:fake:payload
21672     89/<- %esi 4/r32/esp
21673     # var inouts = (handle stmt-var) = [var1, var2]
21674     68/push 0/imm32/is-deref:false
21675     56/push-esi/next
21676     68/push 0x11/imm32/alloc-id:fake
21677     51/push-ecx/var1
21678     68/push 0x11/imm32/alloc-id:fake
21679     68/push 0x11/imm32/alloc-id:fake:payload
21680     89/<- %esi 4/r32/esp
21681 $test-shift-mem-by-literal:initialize-stmt:
21682     # var stmt/esi: (addr statement)
21683     68/push 0/imm32/next
21684     68/push 0/imm32/next
21685     68/push 0/imm32/outputs
21686     68/push 0/imm32/outputs
21687     56/push-esi/inouts
21688     68/push 0x11/imm32/alloc-id:fake
21689     68/push 0/imm32/operation
21690     68/push 0/imm32/operation
21691     68/push 1/imm32/tag:stmt1
21692     89/<- %esi 4/r32/esp
21693 $test-shift-mem-by-literal:initialize-stmt-operation:
21694     # stmt->operation = "shift-left"
21695     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21696     (copy-array Heap "shift-left" %eax)
21697     # convert
21698     c7 0/subop/copy *Curr-block-depth 0/imm32
21699     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21700     (flush _test-output-buffered-file)
21701 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21707     # check output
21708     (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left *(ebp+0x00000008) 3/imm8" "F - test-shift-mem-by-literal")
21709     # . epilogue
21710     89/<- %esp 5/r32/ebp
21711     5d/pop-to-ebp
21712     c3/return
21713 
21714 test-compare-reg-with-reg:
21715     #   compare var1/ecx, var2/eax
21716     # =>
21717     #   39/compare %ecx 0/r32/eax
21718     #
21719     # . prologue
21720     55/push-ebp
21721     89/<- %ebp 4/r32/esp
21722     # setup
21723     (clear-stream _test-output-stream)
21724     (clear-stream $_test-output-buffered-file->buffer)
21725 $test-compare-reg-with-reg:initialize-type:
21726     # var type/ecx: (payload type-tree) = int
21727     68/push 0/imm32/right:null
21728     68/push 0/imm32/right:null
21729     68/push 0/imm32/left:unused
21730     68/push 1/imm32/value:int
21731     68/push 1/imm32/is-atom?:true
21732     68/push 0x11/imm32/alloc-id:fake:payload
21733     89/<- %ecx 4/r32/esp
21734 $test-compare-reg-with-reg:initialize-var1:
21735     # var var1/ecx: (payload var)
21736     68/push 0/imm32/register
21737     68/push 0/imm32/register
21738     68/push 0/imm32/no-stack-offset
21739     68/push 1/imm32/block-depth
21740     51/push-ecx
21741     68/push 0x11/imm32/alloc-id:fake
21742     68/push 0/imm32/name
21743     68/push 0/imm32/name
21744     68/push 0x11/imm32/alloc-id:fake:payload
21745     89/<- %ecx 4/r32/esp
21746 $test-compare-reg-with-reg:initialize-var1-name:
21747     # var1->name = "var1"
21748     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21749     (copy-array Heap "var1" %eax)
21750 $test-compare-reg-with-reg:initialize-var1-register:
21751     # var1->register = "ecx"
21752     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21753     (copy-array Heap "ecx" %eax)
21754 $test-compare-reg-with-reg:initialize-var2:
21755     # var var2/edx: (payload var)
21756     68/push 0/imm32/register
21757     68/push 0/imm32/register
21758     68/push 0/imm32/no-stack-offset
21759     68/push 1/imm32/block-depth
21760     ff 6/subop/push *(ecx+0x10)
21761     68/push 0x11/imm32/alloc-id:fake
21762     68/push 0/imm32/name
21763     68/push 0/imm32/name
21764     68/push 0x11/imm32/alloc-id:fake:payload
21765     89/<- %edx 4/r32/esp
21766 $test-compare-reg-with-reg:initialize-var2-name:
21767     # var2->name = "var2"
21768     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21769     (copy-array Heap "var2" %eax)
21770 $test-compare-reg-with-reg:initialize-var2-register:
21771     # var2->register = "eax"
21772     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
21773     (copy-array Heap "eax" %eax)
21774 $test-compare-reg-with-reg:initialize-inouts:
21775     # var inouts/esi: (payload stmt-var) = [var2]
21776     68/push 0/imm32/is-deref:false
21777     68/push 0/imm32/next
21778     68/push 0/imm32/next
21779     52/push-edx/var2
21780     68/push 0x11/imm32/alloc-id:fake
21781     68/push 0x11/imm32/alloc-id:fake:payload
21782     89/<- %esi 4/r32/esp
21783     # inouts = [var1, var2]
21784     68/push 0/imm32/is-deref:false
21785     56/push-esi/next
21786     68/push 0x11/imm32/alloc-id:fake
21787     51/push-ecx/var1
21788     68/push 0x11/imm32/alloc-id:fake
21789     68/push 0x11/imm32/alloc-id:fake:payload
21790     89/<- %esi 4/r32/esp
21791 $test-compare-reg-with-reg:initialize-stmt:
21792     # var stmt/esi: (addr statement)
21793     68/push 0/imm32/next
21794     68/push 0/imm32/next
21795     68/push 0/imm32/outputs
21796     68/push 0/imm32/outputs
21797     56/push-esi/inouts
21798     68/push 0x11/imm32/alloc-id:fake
21799     68/push 0/imm32/operation
21800     68/push 0/imm32/operation
21801     68/push 1/imm32/tag:stmt1
21802     89/<- %esi 4/r32/esp
21803 $test-compare-reg-with-reg:initialize-stmt-operation:
21804     # stmt->operation = "compare"
21805     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21806     (copy-array Heap "compare" %eax)
21807     # convert
21808     c7 0/subop/copy *Curr-block-depth 0/imm32
21809     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21810     (flush _test-output-buffered-file)
21811 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21817     # check output
21818     (check-next-stream-line-equal _test-output-stream "39/compare-> %ecx 0x00000000/r32" "F - test-compare-reg-with-reg")
21819     # . epilogue
21820     89/<- %esp 5/r32/ebp
21821     5d/pop-to-ebp
21822     c3/return
21823 
21824 test-compare-mem-with-reg:
21825     #   compare var1, var2/eax
21826     # =>
21827     #   39/compare *(ebp+___) 0/r32/eax
21828     #
21829     # . prologue
21830     55/push-ebp
21831     89/<- %ebp 4/r32/esp
21832     # setup
21833     (clear-stream _test-output-stream)
21834     (clear-stream $_test-output-buffered-file->buffer)
21835 $test-compare-mem-with-reg:initialize-type:
21836     # var type/ecx: (payload type-tree) = int
21837     68/push 0/imm32/right:null
21838     68/push 0/imm32/right:null
21839     68/push 0/imm32/left:unused
21840     68/push 1/imm32/value:int
21841     68/push 1/imm32/is-atom?:true
21842     68/push 0x11/imm32/alloc-id:fake:payload
21843     89/<- %ecx 4/r32/esp
21844 $test-compare-mem-with-reg:initialize-var1:
21845     # var var1/ecx: (payload var)
21846     68/push 0/imm32/register
21847     68/push 0/imm32/register
21848     68/push 8/imm32/stack-offset
21849     68/push 1/imm32/block-depth
21850     51/push-ecx
21851     68/push 0x11/imm32/alloc-id:fake
21852     68/push 0/imm32/name
21853     68/push 0/imm32/name
21854     68/push 0x11/imm32/alloc-id:fake:payload
21855     89/<- %ecx 4/r32/esp
21856 $test-compare-mem-with-reg:initialize-var1-name:
21857     # var1->name = "var1"
21858     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21859     (copy-array Heap "var1" %eax)
21860 $test-compare-mem-with-reg:initialize-var2:
21861     # var var2/edx: (payload var)
21862     68/push 0/imm32/register
21863     68/push 0/imm32/register
21864     68/push 0/imm32/no-stack-offset
21865     68/push 1/imm32/block-depth
21866     ff 6/subop/push *(ecx+0x10)
21867     68/push 0x11/imm32/alloc-id:fake
21868     68/push 0/imm32/name
21869     68/push 0/imm32/name
21870     68/push 0x11/imm32/alloc-id:fake:payload
21871     89/<- %edx 4/r32/esp
21872 $test-compare-mem-with-reg:initialize-var2-name:
21873     # var2->name = "var2"
21874     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21875     (copy-array Heap "var2" %eax)
21876 $test-compare-mem-with-reg:initialize-var2-register:
21877     # var2->register = "eax"
21878     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
21879     (copy-array Heap "eax" %eax)
21880 $test-compare-mem-with-reg:initialize-inouts:
21881     # var inouts/esi: (payload stmt-var) = [var2]
21882     68/push 0/imm32/is-deref:false
21883     68/push 0/imm32/next
21884     68/push 0/imm32/next
21885     52/push-edx/var2
21886     68/push 0x11/imm32/alloc-id:fake
21887     68/push 0x11/imm32/alloc-id:fake:payload
21888     89/<- %esi 4/r32/esp
21889     # inouts = [var1, var2]
21890     68/push 0/imm32/is-deref:false
21891     56/push-esi/next
21892     68/push 0x11/imm32/alloc-id:fake
21893     51/push-ecx/var1
21894     68/push 0x11/imm32/alloc-id:fake
21895     68/push 0x11/imm32/alloc-id:fake:payload
21896     89/<- %esi 4/r32/esp
21897 $test-compare-mem-with-reg:initialize-stmt:
21898     # var stmt/esi: (addr statement)
21899     68/push 0/imm32/next
21900     68/push 0/imm32/next
21901     68/push 0/imm32/outputs
21902     68/push 0/imm32/outputs
21903     56/push-esi/inouts
21904     68/push 0x11/imm32/alloc-id:fake
21905     68/push 0/imm32/operation
21906     68/push 0/imm32/operation
21907     68/push 1/imm32/tag:stmt1
21908     89/<- %esi 4/r32/esp
21909 $test-compare-mem-with-reg:initialize-stmt-operation:
21910     # stmt->operation = "compare"
21911     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21912     (copy-array Heap "compare" %eax)
21913     # convert
21914     c7 0/subop/copy *Curr-block-depth 0/imm32
21915     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21916     (flush _test-output-buffered-file)
21917 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21923     # check output
21924     (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg")
21925     # . epilogue
21926     89/<- %esp 5/r32/ebp
21927     5d/pop-to-ebp
21928     c3/return
21929 
21930 test-compare-reg-with-mem:
21931     #   compare var1/eax, var2
21932     # =>
21933     #   3b/compare<- *(ebp+___) 0/r32/eax
21934     #
21935     # . prologue
21936     55/push-ebp
21937     89/<- %ebp 4/r32/esp
21938     # setup
21939     (clear-stream _test-output-stream)
21940     (clear-stream $_test-output-buffered-file->buffer)
21941 $test-compare-reg-with-mem:initialize-type:
21942     # var type/ecx: (payload type-tree) = int
21943     68/push 0/imm32/right:null
21944     68/push 0/imm32/right:null
21945     68/push 0/imm32/left:unused
21946     68/push 1/imm32/value:int
21947     68/push 1/imm32/is-atom?:true
21948     68/push 0x11/imm32/alloc-id:fake:payload
21949     89/<- %ecx 4/r32/esp
21950 $test-compare-reg-with-mem:initialize-var1:
21951     # var var1/ecx: (payload var)
21952     68/push 0/imm32/register
21953     68/push 0/imm32/register
21954     68/push 0/imm32/no-stack-offset
21955     68/push 1/imm32/block-depth
21956     51/push-ecx
21957     68/push 0x11/imm32/alloc-id:fake
21958     68/push 0/imm32/name
21959     68/push 0/imm32/name
21960     68/push 0x11/imm32/alloc-id:fake:payload
21961     89/<- %ecx 4/r32/esp
21962 $test-compare-reg-with-mem:initialize-var1-name:
21963     # var1->name = "var1"
21964     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21965     (copy-array Heap "var1" %eax)
21966 $test-compare-reg-with-mem:initialize-var1-register:
21967     # var1->register = "eax"
21968     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21969     (copy-array Heap "eax" %eax)
21970 $test-compare-reg-with-mem:initialize-var2:
21971     # var var2/edx: (payload var)
21972     68/push 0/imm32/register
21973     68/push 0/imm32/register
21974     68/push 8/imm32/stack-offset
21975     68/push 1/imm32/block-depth
21976     ff 6/subop/push *(ecx+0x10)
21977     68/push 0x11/imm32/alloc-id:fake
21978     68/push 0/imm32/name
21979     68/push 0/imm32/name
21980     68/push 0x11/imm32/alloc-id:fake:payload
21981     89/<- %edx 4/r32/esp
21982 $test-compare-reg-with-mem:initialize-var2-name:
21983     # var2->name = "var2"
21984     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21985     (copy-array Heap "var2" %eax)
21986 $test-compare-reg-with-mem:initialize-inouts:
21987     # var inouts/esi: (payload stmt-var) = [var2]
21988     68/push 0/imm32/is-deref:false
21989     68/push 0/imm32/next
21990     68/push 0/imm32/next
21991     52/push-edx/var2
21992     68/push 0x11/imm32/alloc-id:fake
21993     68/push 0x11/imm32/alloc-id:fake:payload
21994     89/<- %esi 4/r32/esp
21995     # inouts = [var1, var2]
21996     68/push 0/imm32/is-deref:false
21997     56/push-esi/next
21998     68/push 0x11/imm32/alloc-id:fake
21999     51/push-ecx/var1
22000     68/push 0x11/imm32/alloc-id:fake
22001     68/push 0x11/imm32/alloc-id:fake:payload
22002     89/<- %esi 4/r32/esp
22003 $test-compare-reg-with-mem:initialize-stmt:
22004     # var stmt/esi: (addr statement)
22005     68/push 0/imm32/next
22006     68/push 0/imm32/next
22007     68/push 0/imm32/outputs
22008     68/push 0/imm32/outputs
22009     56/push-esi/inouts
22010     68/push 0x11/imm32/alloc-id:fake
22011     68/push 0/imm32/operation
22012     68/push 0/imm32/operation
22013     68/push 1/imm32/tag:stmt1
22014     89/<- %esi 4/r32/esp
22015 $test-compare-reg-with-mem:initialize-stmt-operation:
22016     # stmt->operation = "compare"
22017     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22018     (copy-array Heap "compare" %eax)
22019     # convert
22020     c7 0/subop/copy *Curr-block-depth 0/imm32
22021     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22022     (flush _test-output-buffered-file)
22023 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22029     # check output
22030     (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem")
22031     # . epilogue
22032     89/<- %esp 5/r32/ebp
22033     5d/pop-to-ebp
22034     c3/return
22035 
22036 test-compare-mem-with-literal:
22037     #   compare var1, 0x34
22038     # =>
22039     #   81 7/subop/compare *(ebp+___) 0x34/imm32
22040     #
22041     # . prologue
22042     55/push-ebp
22043     89/<- %ebp 4/r32/esp
22044     # setup
22045     (clear-stream _test-output-stream)
22046     (clear-stream $_test-output-buffered-file->buffer)
22047 $test-compare-mem-with-literal:initialize-type:
22048     # var type/ecx: (payload type-tree) = int
22049     68/push 0/imm32/right:null
22050     68/push 0/imm32/right:null
22051     68/push 0/imm32/left:unused
22052     68/push 1/imm32/value:int
22053     68/push 1/imm32/is-atom?:true
22054     68/push 0x11/imm32/alloc-id:fake:payload
22055     89/<- %ecx 4/r32/esp
22056 $test-compare-mem-with-literal:initialize-var1:
22057     # var var1/ecx: (payload var)
22058     68/push 0/imm32/register
22059     68/push 0/imm32/register
22060     68/push 8/imm32/stack-offset
22061     68/push 1/imm32/block-depth
22062     51/push-ecx
22063     68/push 0x11/imm32/alloc-id:fake
22064     68/push 0/imm32/name
22065     68/push 0/imm32/name
22066     68/push 0x11/imm32/alloc-id:fake:payload
22067     89/<- %ecx 4/r32/esp
22068 $test-compare-mem-with-literal:initialize-var1-name:
22069     # var1->name = "var1"
22070     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22071     (copy-array Heap "var1" %eax)
22072 $test-compare-mem-with-literal:initialize-literal-type:
22073     # var type/edx: (payload type-tree) = literal
22074     68/push 0/imm32/right:null
22075     68/push 0/imm32/right:null
22076     68/push 0/imm32/left:unused
22077     68/push 0/imm32/value:literal
22078     68/push 1/imm32/is-atom?:true
22079     68/push 0x11/imm32/alloc-id:fake:payload
22080     89/<- %edx 4/r32/esp
22081 $test-compare-mem-with-literal:initialize-literal:
22082     # var l/edx: (payload var)
22083     68/push 0/imm32/register
22084     68/push 0/imm32/register
22085     68/push 0/imm32/no-stack-offset
22086     68/push 1/imm32/block-depth
22087     52/push-edx
22088     68/push 0x11/imm32/alloc-id:fake
22089     68/push 0/imm32/name
22090     68/push 0/imm32/name
22091     68/push 0x11/imm32/alloc-id:fake:payload
22092     89/<- %edx 4/r32/esp
22093 $test-compare-mem-with-literal:initialize-literal-value:
22094     # l->name = "0x34"
22095     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22096     (copy-array Heap "0x34" %eax)
22097 $test-compare-mem-with-literal:initialize-inouts:
22098     # var inouts/esi: (payload stmt-var) = [l]
22099     68/push 0/imm32/is-deref:false
22100     68/push 0/imm32/next
22101     68/push 0/imm32/next
22102     52/push-edx/l
22103     68/push 0x11/imm32/alloc-id:fake
22104     68/push 0x11/imm32/alloc-id:fake:payload
22105     89/<- %esi 4/r32/esp
22106     # var inouts = (handle stmt-var) = [var1, var2]
22107     68/push 0/imm32/is-deref:false
22108     56/push-esi/next
22109     68/push 0x11/imm32/alloc-id:fake
22110     51/push-ecx/var1
22111     68/push 0x11/imm32/alloc-id:fake
22112     68/push 0x11/imm32/alloc-id:fake:payload
22113     89/<- %esi 4/r32/esp
22114 $test-compare-mem-with-literal:initialize-stmt:
22115     # var stmt/esi: (addr statement)
22116     68/push 0/imm32/next
22117     68/push 0/imm32/next
22118     68/push 0/imm32/outputs
22119     68/push 0/imm32/outputs
22120     56/push-esi/inouts
22121     68/push 0x11/imm32/alloc-id:fake
22122     68/push 0/imm32/operation
22123     68/push 0/imm32/operation
22124     68/push 1/imm32/tag:stmt1
22125     89/<- %esi 4/r32/esp
22126 $test-compare-mem-with-literal:initialize-stmt-operation:
22127     # stmt->operation = "compare"
22128     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22129     (copy-array Heap "compare" %eax)
22130     # convert
22131     c7 0/subop/copy *Curr-block-depth 0/imm32
22132     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22133     (flush _test-output-buffered-file)
22134 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22140     # check output
22141     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal")
22142     # . epilogue
22143     89/<- %esp 5/r32/ebp
22144     5d/pop-to-ebp
22145     c3/return
22146 
22147 test-compare-eax-with-literal:
22148     #   compare var1/eax 0x34
22149     # =>
22150     #   3d/compare-eax-with 0x34/imm32
22151     #
22152     # . prologue
22153     55/push-ebp
22154     89/<- %ebp 4/r32/esp
22155     # setup
22156     (clear-stream _test-output-stream)
22157     (clear-stream $_test-output-buffered-file->buffer)
22158 $test-compare-eax-with-literal:initialize-type:
22159     # var type/ecx: (payload type-tree) = int
22160     68/push 0/imm32/right:null
22161     68/push 0/imm32/right:null
22162     68/push 0/imm32/left:unused
22163     68/push 1/imm32/value:int
22164     68/push 1/imm32/is-atom?:true
22165     68/push 0x11/imm32/alloc-id:fake:payload
22166     89/<- %ecx 4/r32/esp
22167 $test-compare-eax-with-literal:initialize-var1:
22168     # var var1/ecx: (payload var)
22169     68/push 0/imm32/register
22170     68/push 0/imm32/register
22171     68/push 0/imm32/no-stack-offset
22172     68/push 1/imm32/block-depth
22173     51/push-ecx
22174     68/push 0x11/imm32/alloc-id:fake
22175     68/push 0/imm32/name
22176     68/push 0/imm32/name
22177     68/push 0x11/imm32/alloc-id:fake:payload
22178     89/<- %ecx 4/r32/esp
22179 $test-compare-eax-with-literal:initialize-var1-name:
22180     # var1->name = "var1"
22181     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22182     (copy-array Heap "var1" %eax)
22183 $test-compare-eax-with-literal:initialize-var1-register:
22184     # v->register = "eax"
22185     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22186     (copy-array Heap "eax" %eax)
22187 $test-compare-eax-with-literal:initialize-literal-type:
22188     # var type/edx: (payload type-tree) = literal
22189     68/push 0/imm32/right:null
22190     68/push 0/imm32/right:null
22191     68/push 0/imm32/left:unused
22192     68/push 0/imm32/value:literal
22193     68/push 1/imm32/is-atom?:true
22194     68/push 0x11/imm32/alloc-id:fake:payload
22195     89/<- %edx 4/r32/esp
22196 $test-compare-eax-with-literal:initialize-literal:
22197     # var l/edx: (payload var)
22198     68/push 0/imm32/register
22199     68/push 0/imm32/register
22200     68/push 0/imm32/no-stack-offset
22201     68/push 1/imm32/block-depth
22202     52/push-edx
22203     68/push 0x11/imm32/alloc-id:fake
22204     68/push 0/imm32/name
22205     68/push 0/imm32/name
22206     68/push 0x11/imm32/alloc-id:fake:payload
22207     89/<- %edx 4/r32/esp
22208 $test-compare-eax-with-literal:initialize-literal-value:
22209     # l->name = "0x34"
22210     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22211     (copy-array Heap "0x34" %eax)
22212 $test-compare-eax-with-literal:initialize-inouts:
22213     # var inouts/esi: (payload stmt-var) = [l]
22214     68/push 0/imm32/is-deref:false
22215     68/push 0/imm32/next
22216     68/push 0/imm32/next
22217     52/push-edx/l
22218     68/push 0x11/imm32/alloc-id:fake
22219     68/push 0x11/imm32/alloc-id:fake:payload
22220     89/<- %esi 4/r32/esp
22221     # var inouts = (handle stmt-var) = [var1, var2]
22222     68/push 0/imm32/is-deref:false
22223     56/push-esi/next
22224     68/push 0x11/imm32/alloc-id:fake
22225     51/push-ecx/var1
22226     68/push 0x11/imm32/alloc-id:fake
22227     68/push 0x11/imm32/alloc-id:fake:payload
22228     89/<- %esi 4/r32/esp
22229 $test-compare-eax-with-literal:initialize-stmt:
22230     # var stmt/esi: (addr statement)
22231     68/push 0/imm32/next
22232     68/push 0/imm32/next
22233     68/push 0/imm32/outputs
22234     68/push 0/imm32/outputs
22235     56/push-esi/inouts
22236     68/push 0x11/imm32/alloc-id:fake
22237     68/push 0/imm32/operation
22238     68/push 0/imm32/operation
22239     68/push 1/imm32/tag:stmt1
22240     89/<- %esi 4/r32/esp
22241 $test-compare-eax-with-literal:initialize-stmt-operation:
22242     # stmt->operation = "compare"
22243     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22244     (copy-array Heap "compare" %eax)
22245     # convert
22246     c7 0/subop/copy *Curr-block-depth 0/imm32
22247     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22248     (flush _test-output-buffered-file)
22249 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22255     # check output
22256     (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal")
22257     # . epilogue
22258     89/<- %esp 5/r32/ebp
22259     5d/pop-to-ebp
22260     c3/return
22261 
22262 test-compare-reg-with-literal:
22263     #   compare var1/ecx 0x34
22264     # =>
22265     #   81 7/subop/compare %ecx 0x34/imm32
22266     #
22267     # . prologue
22268     55/push-ebp
22269     89/<- %ebp 4/r32/esp
22270     # setup
22271     (clear-stream _test-output-stream)
22272     (clear-stream $_test-output-buffered-file->buffer)
22273 $test-compare-reg-with-literal:initialize-type:
22274     # var type/ecx: (payload type-tree) = int
22275     68/push 0/imm32/right:null
22276     68/push 0/imm32/right:null
22277     68/push 0/imm32/left:unused
22278     68/push 1/imm32/value:int
22279     68/push 1/imm32/is-atom?:true
22280     68/push 0x11/imm32/alloc-id:fake:payload
22281     89/<- %ecx 4/r32/esp
22282 $test-compare-reg-with-literal:initialize-var1:
22283     # var var1/ecx: (payload var)
22284     68/push 0/imm32/register
22285     68/push 0/imm32/register
22286     68/push 0/imm32/no-stack-offset
22287     68/push 1/imm32/block-depth
22288     51/push-ecx
22289     68/push 0x11/imm32/alloc-id:fake
22290     68/push 0/imm32/name
22291     68/push 0/imm32/name
22292     68/push 0x11/imm32/alloc-id:fake:payload
22293     89/<- %ecx 4/r32/esp
22294 $test-compare-reg-with-literal:initialize-var1-name:
22295     # var1->name = "var1"
22296     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22297     (copy-array Heap "var1" %eax)
22298 $test-compare-reg-with-literal:initialize-var1-register:
22299     # v->register = "ecx"
22300     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22301     (copy-array Heap "ecx" %eax)
22302 $test-compare-reg-with-literal:initialize-literal-type:
22303     # var type/edx: (payload type-tree) = literal
22304     68/push 0/imm32/right:null
22305     68/push 0/imm32/right:null
22306     68/push 0/imm32/left:unused
22307     68/push 0/imm32/value:literal
22308     68/push 1/imm32/is-atom?:true
22309     68/push 0x11/imm32/alloc-id:fake:payload
22310     89/<- %edx 4/r32/esp
22311 $test-compare-reg-with-literal:initialize-literal:
22312     # var l/edx: (payload var)
22313     68/push 0/imm32/register
22314     68/push 0/imm32/register
22315     68/push 0/imm32/no-stack-offset
22316     68/push 1/imm32/block-depth
22317     52/push-edx
22318     68/push 0x11/imm32/alloc-id:fake
22319     68/push 0/imm32/name
22320     68/push 0/imm32/name
22321     68/push 0x11/imm32/alloc-id:fake:payload
22322     89/<- %edx 4/r32/esp
22323 $test-compare-reg-with-literal:initialize-literal-value:
22324     # l->name = "0x34"
22325     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22326     (copy-array Heap "0x34" %eax)
22327 $test-compare-reg-with-literal:initialize-inouts:
22328     # var inouts/esi: (payload stmt-var) = [l]
22329     68/push 0/imm32/is-deref:false
22330     68/push 0/imm32/next
22331     68/push 0/imm32/next
22332     52/push-edx/l
22333     68/push 0x11/imm32/alloc-id:fake
22334     68/push 0x11/imm32/alloc-id:fake:payload
22335     89/<- %esi 4/r32/esp
22336     # var inouts = (handle stmt-var) = [var1, var2]
22337     68/push 0/imm32/is-deref:false
22338     56/push-esi/next
22339     68/push 0x11/imm32/alloc-id:fake
22340     51/push-ecx/var1
22341     68/push 0x11/imm32/alloc-id:fake
22342     68/push 0x11/imm32/alloc-id:fake:payload
22343     89/<- %esi 4/r32/esp
22344 $test-compare-reg-with-literal:initialize-stmt:
22345     # var stmt/esi: (addr statement)
22346     68/push 0/imm32/next
22347     68/push 0/imm32/next
22348     68/push 0/imm32/outputs
22349     68/push 0/imm32/outputs
22350     56/push-esi/inouts
22351     68/push 0x11/imm32/alloc-id:fake
22352     68/push 0/imm32/operation
22353     68/push 0/imm32/operation
22354     68/push 1/imm32/tag:stmt1
22355     89/<- %esi 4/r32/esp
22356 $test-compare-reg-with-literal:initialize-stmt-operation:
22357     # stmt->operation = "compare"
22358     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22359     (copy-array Heap "compare" %eax)
22360     # convert
22361     c7 0/subop/copy *Curr-block-depth 0/imm32
22362     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22363     (flush _test-output-buffered-file)
22364 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22370     # check output
22371     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal")
22372     # . epilogue
22373     89/<- %esp 5/r32/ebp
22374     5d/pop-to-ebp
22375     c3/return
22376 
22377 test-emit-subx-stmt-function-call:
22378     # Call a function on a variable on the stack.
22379     #   f foo
22380     # =>
22381     #   (f *(ebp-8))
22382     # (Changing the function name supports overloading in general, but here it
22383     # just serves to help disambiguate things.)
22384     #
22385     # There's a variable on the var stack as follows:
22386     #   name: 'foo'
22387     #   type: int
22388     #   stack-offset: -8
22389     #
22390     # There's nothing in primitives.
22391     #
22392     # We don't perform any checking here on the type of 'f'.
22393     #
22394     # . prologue
22395     55/push-ebp
22396     89/<- %ebp 4/r32/esp
22397     # setup
22398     (clear-stream _test-output-stream)
22399     (clear-stream $_test-output-buffered-file->buffer)
22400 $test-emit-subx-function-call:initialize-type:
22401     # var type/ecx: (payload type-tree) = int
22402     68/push 0/imm32/right:null
22403     68/push 0/imm32/right:null
22404     68/push 0/imm32/left:unused
22405     68/push 1/imm32/value:int
22406     68/push 1/imm32/is-atom?:true
22407     68/push 0x11/imm32/alloc-id:fake:payload
22408     89/<- %ecx 4/r32/esp
22409 $test-emit-subx-function-call:initialize-var:
22410     # var var-foo/ecx: (payload var) = var(type)
22411     68/push 0/imm32/no-register
22412     68/push 0/imm32/no-register
22413     68/push -8/imm32/stack-offset
22414     68/push 1/imm32/block-depth
22415     51/push-ecx/type
22416     68/push 0x11/imm32/alloc-id:fake
22417     68/push 0/imm32/name
22418     68/push 0/imm32/name
22419     68/push 0x11/imm32/alloc-id:fake:payload
22420     89/<- %ecx 4/r32/esp
22421 $test-emit-subx-function-call:initialize-var-name:
22422     # var-foo->name = "foo"
22423     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22424     (copy-array Heap "foo" %eax)
22425 $test-emit-subx-function-call:initialize-stmt-var:
22426     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
22427     68/push 0/imm32/is-deref:false
22428     68/push 0/imm32/next
22429     68/push 0/imm32/next
22430     51/push-ecx/var-foo
22431     68/push 0x11/imm32/alloc-id:fake
22432     68/push 0x11/imm32/alloc-id:fake:payload
22433     89/<- %ebx 4/r32/esp
22434 $test-emit-subx-function-call:initialize-stmt:
22435     # var stmt/esi: (addr statement)
22436     68/push 0/imm32/no-outputs
22437     68/push 0/imm32/no-outputs
22438     53/push-ebx/inouts
22439     68/push 0x11/imm32/alloc-id:fake
22440     68/push 0/imm32/operation
22441     68/push 0/imm32/operation
22442     68/push 1/imm32/tag
22443     89/<- %esi 4/r32/esp
22444 $test-emit-subx-function-call:initialize-stmt-operation:
22445     # stmt->operation = "f"
22446     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22447     (copy-array Heap "f" %eax)
22448     # convert
22449     c7 0/subop/copy *Curr-block-depth 0/imm32
22450     (emit-subx-stmt _test-output-buffered-file %esi 0 Stderr 0)
22451     (flush _test-output-buffered-file)
22452 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22458     # check output
22459     (check-next-stream-line-equal _test-output-stream "(f *(ebp+0xfffffff8))" "F - test-emit-subx-stmt-function-call")
22460     # . epilogue
22461     89/<- %esp 5/r32/ebp
22462     5d/pop-to-ebp
22463     c3/return
22464 
22465 test-emit-subx-stmt-function-call-with-literal-arg:
22466     # Call a function on a literal.
22467     #   f 0x34
22468     # =>
22469     #   (f2 0x34)
22470     #
22471     # . prologue
22472     55/push-ebp
22473     89/<- %ebp 4/r32/esp
22474     # setup
22475     (clear-stream _test-output-stream)
22476     (clear-stream $_test-output-buffered-file->buffer)
22477 $test-emit-subx-function-call-with-literal-arg:initialize-type:
22478     # var type/ecx: (payload type-tree) = int
22479     68/push 0/imm32/right:null
22480     68/push 0/imm32/right:null
22481     68/push 0/imm32/left:unused
22482     68/push 0/imm32/value:literal
22483     68/push 1/imm32/is-atom?:true
22484     68/push 0x11/imm32/alloc-id:fake:payload
22485     89/<- %ecx 4/r32/esp
22486 $test-emit-subx-function-call-with-literal-arg:initialize-var:
22487     # var var-foo/ecx: (payload var) = var(lit)
22488     68/push 0/imm32/no-register
22489     68/push 0/imm32/no-register
22490     68/push 0/imm32/no-stack-offset
22491     68/push 1/imm32/block-depth
22492     51/push-ecx/type
22493     68/push 0x11/imm32/alloc-id:fake
22494     68/push 0/imm32/name
22495     68/push 0/imm32/name
22496     68/push 0x11/imm32/alloc-id:fake:payload
22497     89/<- %ecx 4/r32/esp
22498 $test-emit-subx-function-call-with-literal-arg:initialize-var-name:
22499     # var-foo->name = "0x34"
22500     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22501     (copy-array Heap "0x34" %eax)
22502 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-var:
22503     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
22504     68/push 0/imm32/is-deref:false
22505     68/push 0/imm32/next
22506     68/push 0/imm32/next
22507     51/push-ecx/var-foo
22508     68/push 0x11/imm32/alloc-id:fake
22509     68/push 0x11/imm32/alloc-id:fake:payload
22510     89/<- %ebx 4/r32/esp
22511 $test-emit-subx-function-call-with-literal-arg:initialize-stmt:
22512     # var stmt/esi: (addr statement)
22513     68/push 0/imm32/no-outputs
22514     68/push 0/imm32/no-outputs
22515     53/push-ebx/inouts
22516     68/push 0x11/imm32/alloc-id:fake
22517     68/push 0/imm32/operation
22518     68/push 0/imm32/operation
22519     68/push 1/imm32/tag
22520     89/<- %esi 4/r32/esp
22521 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-operation:
22522     # stmt->operation = "f"
22523     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22524     (copy-array Heap "f" %eax)
22525     # convert
22526     c7 0/subop/copy *Curr-block-depth 0/imm32
22527     (emit-subx-stmt _test-output-buffered-file %esi 0 %ebx Stderr 0)
22528     (flush _test-output-buffered-file)
22529 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22535     # check output
22536     (check-next-stream-line-equal _test-output-stream "(f 0x34)" "F - test-emit-subx-stmt-function-call-with-literal-arg")
22537     # . epilogue
22538     89/<- %esp 5/r32/ebp
22539     5d/pop-to-ebp
22540     c3/return
22541 
22542 emit-indent:  # out: (addr buffered-file), n: int
22543     # . prologue
22544     55/push-ebp
22545     89/<- %ebp 4/r32/esp
22546     # . save registers
22547     50/push-eax
22548     # var i/eax: int = n
22549     8b/-> *(ebp+0xc) 0/r32/eax
22550     {
22551       # if (i <= 0) break
22552       3d/compare-eax-with 0/imm32
22553       7e/jump-if-<= break/disp8
22554       (write-buffered *(ebp+8) "  ")
22555       48/decrement-eax
22556       eb/jump loop/disp8
22557     }
22558 $emit-indent:end:
22559     # . restore registers
22560     58/pop-to-eax
22561     # . epilogue
22562     89/<- %esp 5/r32/ebp
22563     5d/pop-to-ebp
22564     c3/return
22565 
22566 emit-subx-prologue:  # out: (addr buffered-file)
22567     # . prologue
22568     55/push-ebp
22569     89/<- %ebp 4/r32/esp
22570     #
22571     (write-buffered *(ebp+8) "  # . prologue\n")
22572     (write-buffered *(ebp+8) "  55/push-ebp\n")
22573     (write-buffered *(ebp+8) "  89/<- %ebp 4/r32/esp\n")
22574 $emit-subx-prologue:end:
22575     # . epilogue
22576     89/<- %esp 5/r32/ebp
22577     5d/pop-to-ebp
22578     c3/return
22579 
22580 emit-subx-epilogue:  # out: (addr buffered-file)
22581     # . prologue
22582     55/push-ebp
22583     89/<- %ebp 4/r32/esp
22584     #
22585     (write-buffered *(ebp+8) "  # . epilogue\n")
22586     (write-buffered *(ebp+8) "  89/<- %esp 5/r32/ebp\n")
22587     (write-buffered *(ebp+8) "  5d/pop-to-ebp\n")
22588     (write-buffered *(ebp+8) "  c3/return\n")
22589 $emit-subx-epilogue:end:
22590     # . epilogue
22591     89/<- %esp 5/r32/ebp
22592     5d/pop-to-ebp
22593     c3/return