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   # Keep Primitive-type-ids in sync if you add types here.
  411                           0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  412   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  413   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  414   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 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 
  419 Primitive-type-ids:  # (addr int)
  420   0x2c
  421 
  422 # == Type definitions
  423 # Program->types contains some typeinfo for each type definition.
  424 # Types contain vars with types, but can't specify registers.
  425 Typeinfo-id:  # type-id
  426   0/imm32
  427 Typeinfo-fields:  # (handle table (handle array byte) (handle typeinfo-entry))
  428   4/imm32
  429 # Total size must be >= 0
  430 # During parsing it may take on two additional values:
  431 #   -2: not yet initialized
  432 #   -1: in process of being computed
  433 # See populate-mu-type-sizes for details.
  434 Typeinfo-total-size-in-bytes:  # int
  435   0xc/imm32
  436 Typeinfo-next:  # (handle typeinfo)
  437   0x10/imm32
  438 Typeinfo-size:  # (addr int)
  439   0x18/imm32
  440 
  441 # Each entry in the typeinfo->fields table has a pointer to a string and a
  442 # pointer to a typeinfo-entry.
  443 Typeinfo-fields-row-size:  # (addr int)
  444   0x10/imm32
  445 
  446 # typeinfo-entry objects have information about a field in a single record type
  447 #
  448 # each field of a type is represented using two var's:
  449 #   1. the input var: expected type of the field; convenient for creating using parse-var-with-type
  450 #   2. the output var: a constant containing the byte offset; convenient for code-generation
  451 # computing the output happens after parsing; in the meantime we preserve the
  452 # order of fields in the 'index' field.
  453 Typeinfo-entry-input-var:  # (handle var)
  454   0/imm32
  455 Typeinfo-entry-index:  # int
  456   8/imm32
  457 Typeinfo-entry-output-var:  # (handle var)
  458   0xc/imm32
  459 Typeinfo-entry-size:  # (addr int)
  460   0x14/imm32
  461 
  462 == code
  463 
  464 Entry:
  465     # . prologue
  466     89/<- %ebp 4/r32/esp
  467     (new-segment *Heap-size Heap)
  468     # if (argv[1] == "test') run-tests()
  469     {
  470       # if (argc <= 1) break
  471       81 7/subop/compare *ebp 1/imm32
  472       7e/jump-if-<= break/disp8
  473       # if (argv[1] != "test") break
  474       (kernel-string-equal? *(ebp+8) "test")  # => eax
  475       3d/compare-eax-and 0/imm32/false
  476       74/jump-if-= break/disp8
  477       #
  478       (run-tests)
  479       # syscall(exit, *Num-test-failures)
  480       8b/-> *Num-test-failures 3/r32/ebx
  481       eb/jump $mu-main:end/disp8
  482     }
  483     # otherwise convert Stdin
  484     (convert-mu Stdin Stdout Stderr 0)
  485     (flush Stdout)
  486     # syscall(exit, 0)
  487     bb/copy-to-ebx 0/imm32
  488 $mu-main:end:
  489     e8/call syscall_exit/disp32
  490 
  491 convert-mu:  # in: (addr buffered-file), out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
  492     # . prologue
  493     55/push-ebp
  494     89/<- %ebp 4/r32/esp
  495     # . save registers
  496     50/push-eax
  497     # initialize global data structures
  498     c7 0/subop/copy *Next-block-index 1/imm32
  499     8b/-> *Primitive-type-ids 0/r32/eax
  500     89/<- *Type-id 0/r32/eax  # stream-write
  501     c7 0/subop/copy *_Program-functions 0/imm32
  502     c7 0/subop/copy *_Program-functions->payload 0/imm32
  503     c7 0/subop/copy *_Program-types 0/imm32
  504     c7 0/subop/copy *_Program-types->payload 0/imm32
  505     c7 0/subop/copy *_Program-signatures 0/imm32
  506     c7 0/subop/copy *_Program-signatures->payload 0/imm32
  507     #
  508     (parse-mu *(ebp+8) *(ebp+0x10) *(ebp+0x14))
  509     (populate-mu-type-sizes *(ebp+0x10) *(ebp+0x14))
  510 #?     (dump-typeinfos "=== typeinfos\n")
  511     (check-mu-types *(ebp+0x10) *(ebp+0x14))
  512     (emit-subx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
  513 $convert-mu:end:
  514     # . restore registers
  515     58/pop-to-eax
  516     # . epilogue
  517     89/<- %esp 5/r32/ebp
  518     5d/pop-to-ebp
  519     c3/return
  520 
  521 test-convert-empty-input:
  522     # empty input => empty output
  523     # . prologue
  524     55/push-ebp
  525     89/<- %ebp 4/r32/esp
  526     # setup
  527     (clear-stream _test-input-stream)
  528     (clear-stream $_test-input-buffered-file->buffer)
  529     (clear-stream _test-output-stream)
  530     (clear-stream $_test-output-buffered-file->buffer)
  531     #
  532     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  533     (flush _test-output-buffered-file)
  534     (check-stream-equal _test-output-stream "" "F - test-convert-empty-input")
  535     # . epilogue
  536     89/<- %esp 5/r32/ebp
  537     5d/pop-to-ebp
  538     c3/return
  539 
  540 test-convert-function-skeleton:
  541     # . prologue
  542     55/push-ebp
  543     89/<- %ebp 4/r32/esp
  544     # setup
  545     (clear-stream _test-input-stream)
  546     (clear-stream $_test-input-buffered-file->buffer)
  547     (clear-stream _test-output-stream)
  548     (clear-stream $_test-output-buffered-file->buffer)
  549     #
  550     (write _test-input-stream "fn foo {\n")
  551     (write _test-input-stream "}\n")
  552     # convert
  553     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  554     (flush _test-output-buffered-file)
  555 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  561     # check output
  562     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-skeleton/0")
  563     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-skeleton/1")
  564     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-skeleton/2")
  565     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-skeleton/3")
  566     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-skeleton/4")
  567     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-skeleton/5")
  568     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-skeleton/6")
  569     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-skeleton/7")
  570     # . epilogue
  571     89/<- %esp 5/r32/ebp
  572     5d/pop-to-ebp
  573     c3/return
  574 
  575 test-convert-multiple-function-skeletons:
  576     # . prologue
  577     55/push-ebp
  578     89/<- %ebp 4/r32/esp
  579     # setup
  580     (clear-stream _test-input-stream)
  581     (clear-stream $_test-input-buffered-file->buffer)
  582     (clear-stream _test-output-stream)
  583     (clear-stream $_test-output-buffered-file->buffer)
  584     #
  585     (write _test-input-stream "fn foo {\n")
  586     (write _test-input-stream "}\n")
  587     (write _test-input-stream "fn bar {\n")
  588     (write _test-input-stream "}\n")
  589     # convert
  590     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  591     (flush _test-output-buffered-file)
  592 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  598     # check first function
  599     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-multiple-function-skeletons/0")
  600     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/1")
  601     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/2")
  602     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/3")
  603     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/4")
  604     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/5")
  605     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/6")
  606     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/7")
  607     # check second function
  608     (check-next-stream-line-equal _test-output-stream "bar:"                    "F - test-convert-multiple-function-skeletons/10")
  609     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/11")
  610     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/12")
  611     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/13")
  612     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/14")
  613     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/15")
  614     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/16")
  615     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/17")
  616     # . epilogue
  617     89/<- %esp 5/r32/ebp
  618     5d/pop-to-ebp
  619     c3/return
  620 
  621 test-convert-function-with-arg:
  622     # . prologue
  623     55/push-ebp
  624     89/<- %ebp 4/r32/esp
  625     # setup
  626     (clear-stream _test-input-stream)
  627     (clear-stream $_test-input-buffered-file->buffer)
  628     (clear-stream _test-output-stream)
  629     (clear-stream $_test-output-buffered-file->buffer)
  630     #
  631     (write _test-input-stream "fn foo n: int {\n")
  632     (write _test-input-stream "}\n")
  633     # convert
  634     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  635     (flush _test-output-buffered-file)
  636 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  642     # check output
  643     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg/0")
  644     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg/1")
  645     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg/2")
  646     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg/3")
  647     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg/4")
  648     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg/5")
  649     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg/6")
  650     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg/7")
  651     # . epilogue
  652     89/<- %esp 5/r32/ebp
  653     5d/pop-to-ebp
  654     c3/return
  655 
  656 test-convert-function-with-arg-and-body:
  657     # . prologue
  658     55/push-ebp
  659     89/<- %ebp 4/r32/esp
  660     # setup
  661     (clear-stream _test-input-stream)
  662     (clear-stream $_test-input-buffered-file->buffer)
  663     (clear-stream _test-output-stream)
  664     (clear-stream $_test-output-buffered-file->buffer)
  665     #
  666     (write _test-input-stream "fn foo n: int {\n")
  667     (write _test-input-stream "  increment n\n")
  668     (write _test-input-stream "}\n")
  669     # convert
  670     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  671     (flush _test-output-buffered-file)
  672 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  678     # check output
  679     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg-and-body/0")
  680     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg-and-body/1")
  681     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg-and-body/2")
  682     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg-and-body/3")
  683     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-arg-and-body/4")
  684     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-arg-and-body/5")
  685     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-arg-and-body/6")
  686     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-arg-and-body/7")
  687     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-arg-and-body/8")
  688     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg-and-body/9")
  689     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg-and-body/10")
  690     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg-and-body/11")
  691     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg-and-body/12")
  692     # . epilogue
  693     89/<- %esp 5/r32/ebp
  694     5d/pop-to-ebp
  695     c3/return
  696 
  697 test-convert-function-distinguishes-args:
  698     # . prologue
  699     55/push-ebp
  700     89/<- %ebp 4/r32/esp
  701     # setup
  702     (clear-stream _test-input-stream)
  703     (clear-stream $_test-input-buffered-file->buffer)
  704     (clear-stream _test-output-stream)
  705     (clear-stream $_test-output-buffered-file->buffer)
  706     #
  707     (write _test-input-stream "fn foo a: int, b: int {\n")
  708     (write _test-input-stream "  increment b\n")
  709     (write _test-input-stream "}\n")
  710     # convert
  711     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  712     (flush _test-output-buffered-file)
  713 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  719     # check output
  720     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-distinguishes-args/0")
  721     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-distinguishes-args/1")
  722     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-distinguishes-args/2")
  723     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-distinguishes-args/3")
  724     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-distinguishes-args/4")
  725     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-distinguishes-args/5")
  726     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x0000000c)"  "F - test-convert-function-distinguishes-args/6")
  727     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-distinguishes-args/7")
  728     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-distinguishes-args/8")
  729     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-distinguishes-args/9")
  730     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-distinguishes-args/10")
  731     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-distinguishes-args/11")
  732     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-distinguishes-args/12")
  733     # . epilogue
  734     89/<- %esp 5/r32/ebp
  735     5d/pop-to-ebp
  736     c3/return
  737 
  738 test-convert-function-returns-result:
  739     # . prologue
  740     55/push-ebp
  741     89/<- %ebp 4/r32/esp
  742     # setup
  743     (clear-stream _test-input-stream)
  744     (clear-stream $_test-input-buffered-file->buffer)
  745     (clear-stream _test-output-stream)
  746     (clear-stream $_test-output-buffered-file->buffer)
  747     #
  748     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  749     (write _test-input-stream "  result <- copy a\n")
  750     (write _test-input-stream "  result <- increment\n")
  751     (write _test-input-stream "}\n")
  752     # convert
  753     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  754     (flush _test-output-buffered-file)
  755 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  761     # check output
  762     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-returns-result/0")
  763     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-returns-result/1")
  764     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-returns-result/2")
  765     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-returns-result/3")
  766     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-returns-result/4")
  767     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-returns-result/5")
  768     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-returns-result/6")
  769     (check-next-stream-line-equal _test-output-stream "    40/increment-eax"    "F - test-convert-function-returns-result/7")
  770     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-returns-result/8")
  771     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-returns-result/9")
  772     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-returns-result/10")
  773     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-returns-result/11")
  774     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-returns-result/12")
  775     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-returns-result/13")
  776     # . epilogue
  777     89/<- %esp 5/r32/ebp
  778     5d/pop-to-ebp
  779     c3/return
  780 
  781 test-convert-function-with-literal-arg:
  782     # . prologue
  783     55/push-ebp
  784     89/<- %ebp 4/r32/esp
  785     # setup
  786     (clear-stream _test-input-stream)
  787     (clear-stream $_test-input-buffered-file->buffer)
  788     (clear-stream _test-output-stream)
  789     (clear-stream $_test-output-buffered-file->buffer)
  790     #
  791     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  792     (write _test-input-stream "  result <- copy a\n")
  793     (write _test-input-stream "  result <- add 1\n")
  794     (write _test-input-stream "}\n")
  795     # convert
  796     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  797     (flush _test-output-buffered-file)
  798 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  804     # check output
  805     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg/0")
  806     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg/1")
  807     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg/2")
  808     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg/3")
  809     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg/4")
  810     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg/5")
  811     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-with-literal-arg/6")
  812     (check-next-stream-line-equal _test-output-stream "    05/add-to-eax 1/imm32"  "F - test-convert-function-with-literal-arg/7")
  813     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg/8")
  814     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg/9")
  815     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg/10")
  816     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg/11")
  817     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg/12")
  818     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg/13")
  819     # . epilogue
  820     89/<- %esp 5/r32/ebp
  821     5d/pop-to-ebp
  822     c3/return
  823 
  824 test-convert-function-with-literal-arg-2:
  825     # . prologue
  826     55/push-ebp
  827     89/<- %ebp 4/r32/esp
  828     # setup
  829     (clear-stream _test-input-stream)
  830     (clear-stream $_test-input-buffered-file->buffer)
  831     (clear-stream _test-output-stream)
  832     (clear-stream $_test-output-buffered-file->buffer)
  833     #
  834     (write _test-input-stream "fn foo a: int, b: int -> result/ebx: int {\n")
  835     (write _test-input-stream "  result <- copy a\n")
  836     (write _test-input-stream "  result <- add 1\n")
  837     (write _test-input-stream "}\n")
  838     # convert
  839     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  840     (flush _test-output-buffered-file)
  841 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  847     # check output
  848     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg-2/0")
  849     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg-2/1")
  850     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg-2/2")
  851     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg-2/3")
  852     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg-2/4")
  853     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg-2/5")
  854     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-with-literal-arg-2/6")
  855     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %ebx 1/imm32"  "F - test-convert-function-with-literal-arg-2/7")
  856     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg-2/8")
  857     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg-2/9")
  858     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg-2/10")
  859     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg-2/11")
  860     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg-2/12")
  861     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg-2/13")
  862     # . epilogue
  863     89/<- %esp 5/r32/ebp
  864     5d/pop-to-ebp
  865     c3/return
  866 
  867 test-convert-function-call-with-literal-arg:
  868     # . prologue
  869     55/push-ebp
  870     89/<- %ebp 4/r32/esp
  871     # setup
  872     (clear-stream _test-input-stream)
  873     (clear-stream $_test-input-buffered-file->buffer)
  874     (clear-stream _test-output-stream)
  875     (clear-stream $_test-output-buffered-file->buffer)
  876     #
  877     (write _test-input-stream "fn main -> result/ebx: int {\n")
  878     (write _test-input-stream "  result <- do-add 3 4\n")
  879     (write _test-input-stream "}\n")
  880     (write _test-input-stream "fn do-add a: int, b: int -> result/ebx: int {\n")
  881     (write _test-input-stream "  result <- copy a\n")
  882     (write _test-input-stream "  result <- add b\n")
  883     (write _test-input-stream "}\n")
  884     # convert
  885     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  886     (flush _test-output-buffered-file)
  887 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  893     # check output
  894     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-literal-arg/0")
  895     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/1")
  896     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/2")
  897     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/3")
  898     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/4")
  899     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-literal-arg/5")
  900     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-literal-arg/6")
  901     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/7")
  902     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-literal-arg/8")
  903     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/9")
  904     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/10")
  905     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/11")
  906     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/12")
  907     (check-next-stream-line-equal _test-output-stream "do-add:"                 "F - test-convert-function-call-with-literal-arg/13")
  908     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/14")
  909     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/15")
  910     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/16")
  911     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/17")
  912     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:loop:"  "F - test-convert-function-call-with-literal-arg/18")
  913     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/19")
  914     (check-next-stream-line-equal _test-output-stream "    03/add *(ebp+0x0000000c) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/20")
  915     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/21")
  916     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:break:"  "F - test-convert-function-call-with-literal-arg/22")
  917     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/23")
  918     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/24")
  919     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/25")
  920     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/26")
  921     # . epilogue
  922     89/<- %esp 5/r32/ebp
  923     5d/pop-to-ebp
  924     c3/return
  925 
  926 test-convert-function-call-with-signature:
  927     # . prologue
  928     55/push-ebp
  929     89/<- %ebp 4/r32/esp
  930     # setup
  931     (clear-stream _test-input-stream)
  932     (clear-stream $_test-input-buffered-file->buffer)
  933     (clear-stream _test-output-stream)
  934     (clear-stream $_test-output-buffered-file->buffer)
  935     #
  936     (write _test-input-stream "fn main -> result/ebx: int {\n")
  937     (write _test-input-stream "  result <- do-add 3 4\n")
  938     (write _test-input-stream "}\n")
  939     (write _test-input-stream "sig do-add a: int, b: int -> result/ebx: int\n")
  940     # convert
  941     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  942     (flush _test-output-buffered-file)
  943 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  949     # check output
  950     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-signature/0")
  951     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-signature/1")
  952     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-signature/2")
  953     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-signature/3")
  954     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-signature/4")
  955     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-signature/5")
  956     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-signature/6")
  957     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-signature/7")
  958     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-signature/8")
  959     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-signature/9")
  960     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-signature/10")
  961     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-signature/11")
  962     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-signature/12")
  963     # . epilogue
  964     89/<- %esp 5/r32/ebp
  965     5d/pop-to-ebp
  966     c3/return
  967 
  968 test-convert-function-with-local-var-in-mem:
  969     # . prologue
  970     55/push-ebp
  971     89/<- %ebp 4/r32/esp
  972     # setup
  973     (clear-stream _test-input-stream)
  974     (clear-stream $_test-input-buffered-file->buffer)
  975     (clear-stream _test-output-stream)
  976     (clear-stream $_test-output-buffered-file->buffer)
  977     #
  978     (write _test-input-stream "fn foo {\n")
  979     (write _test-input-stream "  var x: int\n")
  980     (write _test-input-stream "  increment x\n")
  981     (write _test-input-stream "}\n")
  982     # convert
  983     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  984     (flush _test-output-buffered-file)
  985 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  991     # check output
  992     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-mem/0")
  993     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-mem/1")
  994     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-mem/2")
  995     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-mem/3")
  996     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-mem/4")
  997     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-mem/5")
  998     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-in-mem/6")
  999     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-mem/7")
 1000     (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")
 1001     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-mem/9")
 1002     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-mem/10")
 1003     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-mem/11")
 1004     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-mem/12")
 1005     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-mem/13")
 1006     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-mem/14")
 1007     # . epilogue
 1008     89/<- %esp 5/r32/ebp
 1009     5d/pop-to-ebp
 1010     c3/return
 1011 
 1012 test-convert-invalid-literal:
 1013     # . prologue
 1014     55/push-ebp
 1015     89/<- %ebp 4/r32/esp
 1016     # setup
 1017     (clear-stream _test-input-stream)
 1018     (clear-stream $_test-input-buffered-file->buffer)
 1019     (clear-stream _test-output-stream)
 1020     (clear-stream $_test-output-buffered-file->buffer)
 1021     (clear-stream _test-error-stream)
 1022     (clear-stream $_test-error-buffered-file->buffer)
 1023     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1024     68/push 0/imm32
 1025     68/push 0/imm32
 1026     89/<- %edx 4/r32/esp
 1027     (tailor-exit-descriptor %edx 0x10)
 1028     #
 1029     (write _test-input-stream "fn foo {\n")
 1030     (write _test-input-stream "  increment 1n\n")
 1031     (write _test-input-stream "}\n")
 1032     # convert
 1033     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1034     # registers except esp clobbered at this point
 1035     # restore ed
 1036     89/<- %edx 4/r32/esp
 1037     (flush _test-output-buffered-file)
 1038     (flush _test-error-buffered-file)
 1039 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1045     # check output
 1046     (check-stream-equal _test-output-stream  ""  "F - test-convert-invalid-literal: output should be empty")
 1047     (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")
 1048     # check that stop(1) was called
 1049     (check-ints-equal *(edx+4) 2 "F - test-convert-invalid-literal: exit status")
 1050     # don't restore from ebp
 1051     81 0/subop/add %esp 8/imm32
 1052     # . epilogue
 1053     5d/pop-to-ebp
 1054     c3/return
 1055 
 1056 test-local-var-in-mem-has-no-initializer:
 1057     # . prologue
 1058     55/push-ebp
 1059     89/<- %ebp 4/r32/esp
 1060     # setup
 1061     (clear-stream _test-input-stream)
 1062     (clear-stream $_test-input-buffered-file->buffer)
 1063     (clear-stream _test-output-stream)
 1064     (clear-stream $_test-output-buffered-file->buffer)
 1065     (clear-stream _test-error-stream)
 1066     (clear-stream $_test-error-buffered-file->buffer)
 1067     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1068     68/push 0/imm32
 1069     68/push 0/imm32
 1070     89/<- %edx 4/r32/esp
 1071     (tailor-exit-descriptor %edx 0x10)
 1072     #
 1073     (write _test-input-stream "fn foo {\n")
 1074     (write _test-input-stream "  var x: int <- copy 0\n")
 1075     (write _test-input-stream "  increment x\n")
 1076     (write _test-input-stream "}\n")
 1077     # convert
 1078     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1079     # registers except esp clobbered at this point
 1080     # restore ed
 1081     89/<- %edx 4/r32/esp
 1082     (flush _test-output-buffered-file)
 1083     (flush _test-error-buffered-file)
 1084 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1090     # check output
 1091     (check-stream-equal _test-output-stream  ""  "F - test-var-in-mem-has-no-initializer: output should be empty")
 1092     (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")
 1093     # check that stop(1) was called
 1094     (check-ints-equal *(edx+4) 2 "F - test-var-in-mem-has-no-initializer: exit status")
 1095     # don't restore from ebp
 1096     81 0/subop/add %esp 8/imm32
 1097     # . epilogue
 1098     5d/pop-to-ebp
 1099     c3/return
 1100 
 1101 test-convert-function-with-local-var-with-compound-type-in-mem:
 1102     # . prologue
 1103     55/push-ebp
 1104     89/<- %ebp 4/r32/esp
 1105     # setup
 1106     (clear-stream _test-input-stream)
 1107     (clear-stream $_test-input-buffered-file->buffer)
 1108     (clear-stream _test-output-stream)
 1109     (clear-stream $_test-output-buffered-file->buffer)
 1110     #
 1111     (write _test-input-stream "fn foo {\n")
 1112     (write _test-input-stream "  var x: (addr int)\n")
 1113     (write _test-input-stream "  copy-to x, 0\n")
 1114     (write _test-input-stream "}\n")
 1115     # convert
 1116     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1117     (flush _test-output-buffered-file)
 1118 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1124     # check output
 1125     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-compound-type-in-mem/0")
 1126     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/1")
 1127     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-compound-type-in-mem/2")
 1128     (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")
 1129     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/4")
 1130     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-compound-type-in-mem/5")
 1131     (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")
 1132     (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")
 1133     (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")
 1134     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/9")
 1135     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/10")
 1136     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/11")
 1137     (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")
 1138     (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")
 1139     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-compound-type-in-mem/14")
 1140     # . epilogue
 1141     89/<- %esp 5/r32/ebp
 1142     5d/pop-to-ebp
 1143     c3/return
 1144 
 1145 test-convert-function-with-local-var-in-reg:
 1146     # . prologue
 1147     55/push-ebp
 1148     89/<- %ebp 4/r32/esp
 1149     # setup
 1150     (clear-stream _test-input-stream)
 1151     (clear-stream $_test-input-buffered-file->buffer)
 1152     (clear-stream _test-output-stream)
 1153     (clear-stream $_test-output-buffered-file->buffer)
 1154     #
 1155     (write _test-input-stream "fn foo {\n")
 1156     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1157     (write _test-input-stream "  x <- increment\n")
 1158     (write _test-input-stream "}\n")
 1159     # convert
 1160     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1161     (flush _test-output-buffered-file)
 1162 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1168     # check output
 1169     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-reg/0")
 1170     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-reg/1")
 1171     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-reg/2")
 1172     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-reg/3")
 1173     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-reg/4")
 1174     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-reg/5")
 1175     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-in-reg/6")
 1176     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-local-var-in-reg/7")
 1177     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-local-var-in-reg/8")
 1178     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-reg/9")
 1179     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-reg/10")
 1180     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-reg/11")
 1181     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-reg/12")
 1182     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-reg/13")
 1183     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-reg/14")
 1184     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-reg/15")
 1185     # . epilogue
 1186     89/<- %esp 5/r32/ebp
 1187     5d/pop-to-ebp
 1188     c3/return
 1189 
 1190 test-convert-function-with-allocate:
 1191     # . prologue
 1192     55/push-ebp
 1193     89/<- %ebp 4/r32/esp
 1194     # setup
 1195     (clear-stream _test-input-stream)
 1196     (clear-stream $_test-input-buffered-file->buffer)
 1197     (clear-stream _test-output-stream)
 1198     (clear-stream $_test-output-buffered-file->buffer)
 1199     #
 1200     (write _test-input-stream "fn foo {\n")
 1201     (write _test-input-stream "  var x/ecx: (addr handle int) <- copy 0\n")
 1202     (write _test-input-stream "  allocate x\n")
 1203     (write _test-input-stream "}\n")
 1204     # convert
 1205     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1206     (flush _test-output-buffered-file)
 1207 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1213     # check output
 1214     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-allocate/0")
 1215     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-allocate/1")
 1216     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-allocate/2")
 1217     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-allocate/3")
 1218     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-allocate/4")
 1219     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-allocate/5")
 1220     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-allocate/6")
 1221     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-allocate/7")
 1222     (check-next-stream-line-equal _test-output-stream "    (allocate Heap 0x00000004 %ecx)"  "F - test-convert-function-with-allocate/8")  # 4 = size-of(int)
 1223     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-allocate/9")
 1224     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-allocate/10")
 1225     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-allocate/11")
 1226     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-allocate/12")
 1227     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-allocate/13")
 1228     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-allocate/14")
 1229     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-allocate/15")
 1230     # . epilogue
 1231     89/<- %esp 5/r32/ebp
 1232     5d/pop-to-ebp
 1233     c3/return
 1234 
 1235 test-initializer-in-hex:
 1236     # . prologue
 1237     55/push-ebp
 1238     89/<- %ebp 4/r32/esp
 1239     # setup
 1240     (clear-stream _test-input-stream)
 1241     (clear-stream $_test-input-buffered-file->buffer)
 1242     (clear-stream _test-output-stream)
 1243     (clear-stream $_test-output-buffered-file->buffer)
 1244     (clear-stream _test-error-stream)
 1245     (clear-stream $_test-error-buffered-file->buffer)
 1246     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1247     68/push 0/imm32
 1248     68/push 0/imm32
 1249     89/<- %edx 4/r32/esp
 1250     (tailor-exit-descriptor %edx 0x10)
 1251     #
 1252     (write _test-input-stream "fn foo {\n")
 1253     (write _test-input-stream "  var x/ecx: int <- copy 10\n")
 1254     (write _test-input-stream "}\n")
 1255     # convert
 1256     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1257     # registers except esp clobbered at this point
 1258     # restore ed
 1259     89/<- %edx 4/r32/esp
 1260     (flush _test-output-buffered-file)
 1261     (flush _test-error-buffered-file)
 1262 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1268     # check output
 1269     (check-stream-equal _test-output-stream  ""  "F - test-initializer-in-hex: output should be empty")
 1270     (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")
 1271     # check that stop(1) was called
 1272     (check-ints-equal *(edx+4) 2 "F - test-initializer-in-hex: exit status")
 1273     # don't restore from ebp
 1274     81 0/subop/add %esp 8/imm32
 1275     # . epilogue
 1276     5d/pop-to-ebp
 1277     c3/return
 1278 
 1279 test-convert-function-with-second-local-var-in-same-reg:
 1280     # . prologue
 1281     55/push-ebp
 1282     89/<- %ebp 4/r32/esp
 1283     # setup
 1284     (clear-stream _test-input-stream)
 1285     (clear-stream $_test-input-buffered-file->buffer)
 1286     (clear-stream _test-output-stream)
 1287     (clear-stream $_test-output-buffered-file->buffer)
 1288     #
 1289     (write _test-input-stream "fn foo {\n")
 1290     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1291     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1292     (write _test-input-stream "  y <- increment\n")
 1293     (write _test-input-stream "}\n")
 1294     # convert
 1295     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1296     (flush _test-output-buffered-file)
 1297 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1303     # check output
 1304     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-second-local-var-in-same-reg/0")
 1305     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-second-local-var-in-same-reg/1")
 1306     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-second-local-var-in-same-reg/2")
 1307     (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")
 1308     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-second-local-var-in-same-reg/4")
 1309     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-second-local-var-in-same-reg/5")
 1310     (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")
 1311     (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")
 1312     (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")
 1313     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-second-local-var-in-same-reg/9")
 1314     (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")
 1315     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-second-local-var-in-same-reg/11")
 1316     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-second-local-var-in-same-reg/12")
 1317     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-second-local-var-in-same-reg/13")
 1318     (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")
 1319     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-second-local-var-in-same-reg/15")
 1320     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-second-local-var-in-same-reg/16")
 1321     # . epilogue
 1322     89/<- %esp 5/r32/ebp
 1323     5d/pop-to-ebp
 1324     c3/return
 1325 
 1326 test-read-clobbered-reg-var:
 1327     # . prologue
 1328     55/push-ebp
 1329     89/<- %ebp 4/r32/esp
 1330     # setup
 1331     (clear-stream _test-input-stream)
 1332     (clear-stream $_test-input-buffered-file->buffer)
 1333     (clear-stream _test-output-stream)
 1334     (clear-stream $_test-output-buffered-file->buffer)
 1335     (clear-stream _test-error-stream)
 1336     (clear-stream $_test-error-buffered-file->buffer)
 1337     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
 1338     68/push 0/imm32
 1339     68/push 0/imm32
 1340     89/<- %edx 4/r32/esp
 1341     (tailor-exit-descriptor %edx 0x10)
 1342     #
 1343     (write _test-input-stream "fn foo {\n")
 1344     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1345     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1346     (write _test-input-stream "  x <- increment\n")
 1347     (write _test-input-stream "}\n")
 1348     # convert
 1349     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1350     # registers except esp clobbered at this point
 1351     # restore ed
 1352     89/<- %edx 4/r32/esp
 1353     (flush _test-output-buffered-file)
 1354     (flush _test-error-buffered-file)
 1355 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1361     # check output
 1362     (check-stream-equal _test-output-stream  ""  "F - test-read-clobbered-reg-var: output should be empty")
 1363     (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")
 1364     # check that stop(1) was called
 1365     (check-ints-equal *(edx+4) 2 "F - test-read-clobbered-reg-var: exit status")
 1366     # don't restore from ebp
 1367     81 0/subop/add %esp 8/imm32
 1368     # . epilogue
 1369     5d/pop-to-ebp
 1370     c3/return
 1371 
 1372 test-convert-function-call:
 1373     # . prologue
 1374     55/push-ebp
 1375     89/<- %ebp 4/r32/esp
 1376     # setup
 1377     (clear-stream _test-input-stream)
 1378     (clear-stream $_test-input-buffered-file->buffer)
 1379     (clear-stream _test-output-stream)
 1380     (clear-stream $_test-output-buffered-file->buffer)
 1381     #
 1382     (write _test-input-stream "fn main -> result/ebx: int {\n")
 1383     (write _test-input-stream "  result <- foo\n")
 1384     (write _test-input-stream "}\n")
 1385     (write _test-input-stream "fn foo -> result/ebx: int {\n")
 1386     (write _test-input-stream "  result <- copy 3\n")
 1387     (write _test-input-stream "}\n")
 1388     # convert
 1389     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1390     (flush _test-output-buffered-file)
 1391 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1397     # check output
 1398     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call/0")
 1399     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/1")
 1400     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/2")
 1401     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/3")
 1402     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/4")
 1403     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call/5")
 1404     (check-next-stream-line-equal _test-output-stream "    (foo)"               "F - test-convert-function-call/6")
 1405     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/7")
 1406     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call/8")
 1407     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/9")
 1408     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/10")
 1409     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/11")
 1410     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/12")
 1411     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call/13")
 1412     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/14")
 1413     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/15")
 1414     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/16")
 1415     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/17")
 1416     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"  "F - test-convert-function-call/18")
 1417     (check-next-stream-line-equal _test-output-stream "    bb/copy-to-ebx 3/imm32"  "F - test-convert-function-call/19")
 1418     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/20")
 1419     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-call/21")
 1420     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/22")
 1421     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/23")
 1422     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/24")
 1423     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/25")
 1424     # . epilogue
 1425     89/<- %esp 5/r32/ebp
 1426     5d/pop-to-ebp
 1427     c3/return
 1428 
 1429 test-convert-function-call-with-inout-with-compound-type:
 1430     # . prologue
 1431     55/push-ebp
 1432     89/<- %ebp 4/r32/esp
 1433     # setup
 1434     (clear-stream _test-input-stream)
 1435     (clear-stream $_test-input-buffered-file->buffer)
 1436     (clear-stream _test-output-stream)
 1437     (clear-stream $_test-output-buffered-file->buffer)
 1438     #
 1439     (write _test-input-stream "fn f {\n")
 1440     (write _test-input-stream "  var x: (addr int)\n")
 1441     (write _test-input-stream "  g x\n")
 1442     (write _test-input-stream "}\n")
 1443     (write _test-input-stream "fn g a: (addr int) {\n")
 1444     (write _test-input-stream "}\n")
 1445     # convert
 1446     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1447     (flush _test-output-buffered-file)
 1448 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1454     # check output
 1455     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-inout-with-compound-type/0")
 1456     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-inout-with-compound-type/1")
 1457     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-inout-with-compound-type/2")
 1458     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-inout-with-compound-type/3")
 1459     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-inout-with-compound-type/4")
 1460     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-inout-with-compound-type/5")
 1461     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-inout-with-compound-type/6")
 1462     (check-next-stream-line-equal _test-output-stream "    (g *(ebp+0xfffffffc))"  "F - test-convert-function-call-with-inout-with-compound-type/7")
 1463     (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")
 1464     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-inout-with-compound-type/9")
 1465     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-inout-with-compound-type/10")
 1466     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-inout-with-compound-type/11")
 1467     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-inout-with-compound-type/12")
 1468     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-inout-with-compound-type/13")
 1469     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-inout-with-compound-type/14")
 1470     (check-next-stream-line-equal _test-output-stream "g:"                      "F - test-convert-function-call-with-inout-with-compound-type/15")
 1471     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-inout-with-compound-type/16")
 1472     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-inout-with-compound-type/17")
 1473     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-inout-with-compound-type/18")
 1474     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-inout-with-compound-type/19")
 1475     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-inout-with-compound-type/20")
 1476     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-inout-with-compound-type/21")
 1477     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-inout-with-compound-type/22")
 1478     # . epilogue
 1479     89/<- %esp 5/r32/ebp
 1480     5d/pop-to-ebp
 1481     c3/return
 1482 
 1483 test-convert-function-call-with-inout-with-type-parameter:
 1484     # . prologue
 1485     55/push-ebp
 1486     89/<- %ebp 4/r32/esp
 1487     # setup
 1488     (clear-stream _test-input-stream)
 1489     (clear-stream $_test-input-buffered-file->buffer)
 1490     (clear-stream _test-output-stream)
 1491     (clear-stream $_test-output-buffered-file->buffer)
 1492     (clear-stream _test-error-stream)
 1493     (clear-stream $_test-error-buffered-file->buffer)
 1494     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1495     68/push 0/imm32
 1496     68/push 0/imm32
 1497     89/<- %edx 4/r32/esp
 1498     (tailor-exit-descriptor %edx 0x10)
 1499     #
 1500     (write _test-input-stream "fn f {\n")
 1501     (write _test-input-stream "  var x: (addr int)\n")
 1502     (write _test-input-stream "  g x\n")
 1503     (write _test-input-stream "}\n")
 1504     (write _test-input-stream "fn g a: (addr _) {\n")
 1505     (write _test-input-stream "}\n")
 1506     # convert
 1507     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1508     # registers except esp clobbered at this point
 1509     # restore ed
 1510     89/<- %edx 4/r32/esp
 1511     (flush _test-output-buffered-file)
 1512     (flush _test-error-buffered-file)
 1513 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1519     # no error; types matched
 1520     (check-stream-equal _test-error-stream  ""  "F - test-convert-function-call-with-inout-with-type-parameter: error stream should be empty")
 1521     # don't bother checking the generated code; that's in the test 'test-local-clobbered-by-fn-output' below
 1522     # don't restore from ebp
 1523     81 0/subop/add %esp 8/imm32
 1524     # . epilogue
 1525     5d/pop-to-ebp
 1526     c3/return
 1527 
 1528 test-convert-function-call-with-incorrect-inout-type:
 1529     # . prologue
 1530     55/push-ebp
 1531     89/<- %ebp 4/r32/esp
 1532     # setup
 1533     (clear-stream _test-input-stream)
 1534     (clear-stream $_test-input-buffered-file->buffer)
 1535     (clear-stream _test-output-stream)
 1536     (clear-stream $_test-output-buffered-file->buffer)
 1537     (clear-stream _test-error-stream)
 1538     (clear-stream $_test-error-buffered-file->buffer)
 1539     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1540     68/push 0/imm32
 1541     68/push 0/imm32
 1542     89/<- %edx 4/r32/esp
 1543     (tailor-exit-descriptor %edx 0x10)
 1544     #
 1545     (write _test-input-stream "fn f {\n")
 1546     (write _test-input-stream "  var x: int\n")
 1547     (write _test-input-stream "  g x\n")
 1548     (write _test-input-stream "}\n")
 1549     (write _test-input-stream "fn g a: foo {\n")
 1550     (write _test-input-stream "}\n")
 1551     # convert
 1552     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1553     # registers except esp clobbered at this point
 1554     # restore ed
 1555     89/<- %edx 4/r32/esp
 1556     (flush _test-output-buffered-file)
 1557     (flush _test-error-buffered-file)
 1558 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1564     # check output
 1565     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-inout-type: output should be empty")
 1566     (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")
 1567     # check that stop(1) was called
 1568     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-inout-type: exit status")
 1569     # don't restore from ebp
 1570     81 0/subop/add %esp 8/imm32
 1571     5d/pop-to-ebp
 1572     c3/return
 1573 
 1574 test-convert-function-call-with-inout-with-incorrect-compound-type:
 1575     # . prologue
 1576     55/push-ebp
 1577     89/<- %ebp 4/r32/esp
 1578     # setup
 1579     (clear-stream _test-input-stream)
 1580     (clear-stream $_test-input-buffered-file->buffer)
 1581     (clear-stream _test-output-stream)
 1582     (clear-stream $_test-output-buffered-file->buffer)
 1583     (clear-stream _test-error-stream)
 1584     (clear-stream $_test-error-buffered-file->buffer)
 1585     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1586     68/push 0/imm32
 1587     68/push 0/imm32
 1588     89/<- %edx 4/r32/esp
 1589     (tailor-exit-descriptor %edx 0x10)
 1590     #
 1591     (write _test-input-stream "fn f {\n")
 1592     (write _test-input-stream "  var x: (addr int)\n")
 1593     (write _test-input-stream "  g x\n")
 1594     (write _test-input-stream "}\n")
 1595     (write _test-input-stream "fn g a: (addr bool) {\n")
 1596     (write _test-input-stream "}\n")
 1597     # convert
 1598     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1599     # registers except esp clobbered at this point
 1600     # restore ed
 1601     89/<- %edx 4/r32/esp
 1602     (flush _test-output-buffered-file)
 1603     (flush _test-error-buffered-file)
 1604 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1610     # check output
 1611     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-inout-with-incorrect-compound-type: output should be empty")
 1612     (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")
 1613     # don't restore from ebp
 1614     81 0/subop/add %esp 8/imm32
 1615     # . epilogue
 1616     5d/pop-to-ebp
 1617     c3/return
 1618 
 1619 test-convert-function-call-with-inout-with-multiple-type-parameters:
 1620     # . prologue
 1621     55/push-ebp
 1622     89/<- %ebp 4/r32/esp
 1623     # setup
 1624     (clear-stream _test-input-stream)
 1625     (clear-stream $_test-input-buffered-file->buffer)
 1626     (clear-stream _test-output-stream)
 1627     (clear-stream $_test-output-buffered-file->buffer)
 1628     (clear-stream _test-error-stream)
 1629     (clear-stream $_test-error-buffered-file->buffer)
 1630     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1631     68/push 0/imm32
 1632     68/push 0/imm32
 1633     89/<- %edx 4/r32/esp
 1634     (tailor-exit-descriptor %edx 0x10)
 1635     #
 1636     (write _test-input-stream "fn f {\n")
 1637     (write _test-input-stream "  var x: (addr int)\n")
 1638     (write _test-input-stream "  var y: (addr int)\n")
 1639     (write _test-input-stream "  g x, y\n")
 1640     (write _test-input-stream "}\n")
 1641     (write _test-input-stream "fn g a: (addr _), b: (addr _) {\n")
 1642     (write _test-input-stream "}\n")
 1643     # convert
 1644     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1645     # registers except esp clobbered at this point
 1646     # restore ed
 1647     89/<- %edx 4/r32/esp
 1648     (flush _test-output-buffered-file)
 1649     (flush _test-error-buffered-file)
 1650 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1656     # no errors
 1657     (check-stream-equal _test-error-stream  ""  "F - test-convert-function-call-with-inout-with-multiple-type-parameters: error stream should be empty")
 1658     # don't bother checking the generated code
 1659     # don't restore from ebp
 1660     81 0/subop/add %esp 8/imm32
 1661     # . epilogue
 1662     5d/pop-to-ebp
 1663     c3/return
 1664 
 1665 test-convert-function-call-with-inout-with-incompatible-type-parameters:
 1666     # . prologue
 1667     55/push-ebp
 1668     89/<- %ebp 4/r32/esp
 1669     # setup
 1670     (clear-stream _test-input-stream)
 1671     (clear-stream $_test-input-buffered-file->buffer)
 1672     (clear-stream _test-output-stream)
 1673     (clear-stream $_test-output-buffered-file->buffer)
 1674     (clear-stream _test-error-stream)
 1675     (clear-stream $_test-error-buffered-file->buffer)
 1676     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1677     68/push 0/imm32
 1678     68/push 0/imm32
 1679     89/<- %edx 4/r32/esp
 1680     (tailor-exit-descriptor %edx 0x10)
 1681     #
 1682     (write _test-input-stream "fn f {\n")
 1683     (write _test-input-stream "  var x: (addr int)\n")
 1684     (write _test-input-stream "  var y: (addr boolean)\n")
 1685     (write _test-input-stream "  g x, y\n")
 1686     (write _test-input-stream "}\n")
 1687     (write _test-input-stream "fn g a: (addr _T), b: (addr _T) {\n")
 1688     (write _test-input-stream "}\n")
 1689     # convert
 1690     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1691     # registers except esp clobbered at this point
 1692     # restore ed
 1693     89/<- %edx 4/r32/esp
 1694     (flush _test-output-buffered-file)
 1695     (flush _test-error-buffered-file)
 1696 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1702     # check output
 1703     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-inout-with-incompatible-type-parameters: output should be empty")
 1704     (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")
 1705     # don't restore from ebp
 1706     81 0/subop/add %esp 8/imm32
 1707     # . epilogue
 1708     5d/pop-to-ebp
 1709     c3/return
 1710 
 1711 test-convert-function-call-with-too-few-inouts:
 1712     # . prologue
 1713     55/push-ebp
 1714     89/<- %ebp 4/r32/esp
 1715     # setup
 1716     (clear-stream _test-input-stream)
 1717     (clear-stream $_test-input-buffered-file->buffer)
 1718     (clear-stream _test-output-stream)
 1719     (clear-stream $_test-output-buffered-file->buffer)
 1720     (clear-stream _test-error-stream)
 1721     (clear-stream $_test-error-buffered-file->buffer)
 1722     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1723     68/push 0/imm32
 1724     68/push 0/imm32
 1725     89/<- %edx 4/r32/esp
 1726     (tailor-exit-descriptor %edx 0x10)
 1727     #
 1728     (write _test-input-stream "fn f {\n")
 1729     (write _test-input-stream "  g\n")
 1730     (write _test-input-stream "}\n")
 1731     (write _test-input-stream "fn g a: int {\n")
 1732     (write _test-input-stream "}\n")
 1733     # convert
 1734     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1735     # registers except esp clobbered at this point
 1736     # restore ed
 1737     89/<- %edx 4/r32/esp
 1738     (flush _test-output-buffered-file)
 1739     (flush _test-error-buffered-file)
 1740 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1746     # check output
 1747     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-inouts: output should be empty")
 1748     (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")
 1749     # check that stop(1) was called
 1750     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-inouts: exit status")
 1751     # don't restore from ebp
 1752     81 0/subop/add %esp 8/imm32
 1753     5d/pop-to-ebp
 1754     c3/return
 1755 
 1756 test-convert-function-call-with-too-many-inouts:
 1757     # . prologue
 1758     55/push-ebp
 1759     89/<- %ebp 4/r32/esp
 1760     # setup
 1761     (clear-stream _test-input-stream)
 1762     (clear-stream $_test-input-buffered-file->buffer)
 1763     (clear-stream _test-output-stream)
 1764     (clear-stream $_test-output-buffered-file->buffer)
 1765     (clear-stream _test-error-stream)
 1766     (clear-stream $_test-error-buffered-file->buffer)
 1767     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1768     68/push 0/imm32
 1769     68/push 0/imm32
 1770     89/<- %edx 4/r32/esp
 1771     (tailor-exit-descriptor %edx 0x10)
 1772     #
 1773     (write _test-input-stream "fn f {\n")
 1774     (write _test-input-stream "  var x: int\n")
 1775     (write _test-input-stream "  g x\n")
 1776     (write _test-input-stream "}\n")
 1777     (write _test-input-stream "fn g {\n")
 1778     (write _test-input-stream "}\n")
 1779     # convert
 1780     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1781     # registers except esp clobbered at this point
 1782     # restore ed
 1783     89/<- %edx 4/r32/esp
 1784     (flush _test-output-buffered-file)
 1785     (flush _test-error-buffered-file)
 1786 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1792     # check output
 1793     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-inouts: output should be empty")
 1794     (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")
 1795     # check that stop(1) was called
 1796     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-inouts: exit status")
 1797     # don't restore from ebp
 1798     81 0/subop/add %esp 8/imm32
 1799     5d/pop-to-ebp
 1800     c3/return
 1801 
 1802 test-convert-function-call-with-incorrect-output-type:
 1803     # . prologue
 1804     55/push-ebp
 1805     89/<- %ebp 4/r32/esp
 1806     # setup
 1807     (clear-stream _test-input-stream)
 1808     (clear-stream $_test-input-buffered-file->buffer)
 1809     (clear-stream _test-output-stream)
 1810     (clear-stream $_test-output-buffered-file->buffer)
 1811     (clear-stream _test-error-stream)
 1812     (clear-stream $_test-error-buffered-file->buffer)
 1813     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1814     68/push 0/imm32
 1815     68/push 0/imm32
 1816     89/<- %edx 4/r32/esp
 1817     (tailor-exit-descriptor %edx 0x10)
 1818     #
 1819     (write _test-input-stream "fn f {\n")
 1820     (write _test-input-stream "  var x/eax: int <- g\n")
 1821     (write _test-input-stream "}\n")
 1822     (write _test-input-stream "fn g -> a/eax: foo {\n")
 1823     (write _test-input-stream "}\n")
 1824     # convert
 1825     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1826     # registers except esp clobbered at this point
 1827     # restore ed
 1828     89/<- %edx 4/r32/esp
 1829     (flush _test-output-buffered-file)
 1830     (flush _test-error-buffered-file)
 1831 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1837     # check output
 1838     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-type: output should be empty")
 1839     (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")
 1840     # check that stop(1) was called
 1841     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-type: exit status")
 1842     # don't restore from ebp
 1843     81 0/subop/add %esp 8/imm32
 1844     5d/pop-to-ebp
 1845     c3/return
 1846 
 1847 test-convert-function-call-with-too-few-outputs:
 1848     # . prologue
 1849     55/push-ebp
 1850     89/<- %ebp 4/r32/esp
 1851     # setup
 1852     (clear-stream _test-input-stream)
 1853     (clear-stream $_test-input-buffered-file->buffer)
 1854     (clear-stream _test-output-stream)
 1855     (clear-stream $_test-output-buffered-file->buffer)
 1856     (clear-stream _test-error-stream)
 1857     (clear-stream $_test-error-buffered-file->buffer)
 1858     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1859     68/push 0/imm32
 1860     68/push 0/imm32
 1861     89/<- %edx 4/r32/esp
 1862     (tailor-exit-descriptor %edx 0x10)
 1863     #
 1864     (write _test-input-stream "fn f {\n")
 1865     (write _test-input-stream "  g\n")
 1866     (write _test-input-stream "}\n")
 1867     (write _test-input-stream "fn g -> a/eax: int {\n")
 1868     (write _test-input-stream "}\n")
 1869     # convert
 1870     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1871     # registers except esp clobbered at this point
 1872     # restore ed
 1873     89/<- %edx 4/r32/esp
 1874     (flush _test-output-buffered-file)
 1875     (flush _test-error-buffered-file)
 1876 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1882     # check output
 1883     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-outputs: output should be empty")
 1884     (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")
 1885     # check that stop(1) was called
 1886     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-outputs: exit status")
 1887     # don't restore from ebp
 1888     81 0/subop/add %esp 8/imm32
 1889     5d/pop-to-ebp
 1890     c3/return
 1891 
 1892 test-convert-function-call-with-too-many-outputs:
 1893     # . prologue
 1894     55/push-ebp
 1895     89/<- %ebp 4/r32/esp
 1896     # setup
 1897     (clear-stream _test-input-stream)
 1898     (clear-stream $_test-input-buffered-file->buffer)
 1899     (clear-stream _test-output-stream)
 1900     (clear-stream $_test-output-buffered-file->buffer)
 1901     (clear-stream _test-error-stream)
 1902     (clear-stream $_test-error-buffered-file->buffer)
 1903     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1904     68/push 0/imm32
 1905     68/push 0/imm32
 1906     89/<- %edx 4/r32/esp
 1907     (tailor-exit-descriptor %edx 0x10)
 1908     #
 1909     (write _test-input-stream "fn f {\n")
 1910     (write _test-input-stream "  var x/eax: int <- g\n")
 1911     (write _test-input-stream "}\n")
 1912     (write _test-input-stream "fn g {\n")
 1913     (write _test-input-stream "}\n")
 1914     # convert
 1915     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1916     # registers except esp clobbered at this point
 1917     # restore ed
 1918     89/<- %edx 4/r32/esp
 1919     (flush _test-output-buffered-file)
 1920     (flush _test-error-buffered-file)
 1921 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1927     # check output
 1928     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-outputs: output should be empty")
 1929     (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")
 1930     # check that stop(1) was called
 1931     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-outputs: exit status")
 1932     # don't restore from ebp
 1933     81 0/subop/add %esp 8/imm32
 1934     5d/pop-to-ebp
 1935     c3/return
 1936 
 1937 test-convert-function-call-with-incorrect-output-register:
 1938     # . prologue
 1939     55/push-ebp
 1940     89/<- %ebp 4/r32/esp
 1941     # setup
 1942     (clear-stream _test-input-stream)
 1943     (clear-stream $_test-input-buffered-file->buffer)
 1944     (clear-stream _test-output-stream)
 1945     (clear-stream $_test-output-buffered-file->buffer)
 1946     (clear-stream _test-error-stream)
 1947     (clear-stream $_test-error-buffered-file->buffer)
 1948     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1949     68/push 0/imm32
 1950     68/push 0/imm32
 1951     89/<- %edx 4/r32/esp
 1952     (tailor-exit-descriptor %edx 0x10)
 1953     #
 1954     (write _test-input-stream "fn f {\n")
 1955     (write _test-input-stream "  var x/ecx: int <- g\n")
 1956     (write _test-input-stream "}\n")
 1957     (write _test-input-stream "fn g -> a/eax: int {\n")
 1958     (write _test-input-stream "}\n")
 1959     # convert
 1960     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1961     # registers except esp clobbered at this point
 1962     # restore ed
 1963     89/<- %edx 4/r32/esp
 1964     (flush _test-output-buffered-file)
 1965     (flush _test-error-buffered-file)
 1966 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1972     # check output
 1973     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-register: output should be empty")
 1974     (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")
 1975     # check that stop(1) was called
 1976     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-register: exit status")
 1977     # don't restore from ebp
 1978     81 0/subop/add %esp 8/imm32
 1979     5d/pop-to-ebp
 1980     c3/return
 1981 
 1982 test-convert-function-with-local-var-dereferenced:
 1983     # . prologue
 1984     55/push-ebp
 1985     89/<- %ebp 4/r32/esp
 1986     # setup
 1987     (clear-stream _test-input-stream)
 1988     (clear-stream $_test-input-buffered-file->buffer)
 1989     (clear-stream _test-output-stream)
 1990     (clear-stream $_test-output-buffered-file->buffer)
 1991     #
 1992     (write _test-input-stream "fn foo {\n")
 1993     (write _test-input-stream "  var x/ecx: (addr int) <- copy 0\n")
 1994     (write _test-input-stream "  increment *x\n")
 1995     (write _test-input-stream "}\n")
 1996     # convert
 1997     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1998     (flush _test-output-buffered-file)
 1999 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2005     # check output
 2006     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-dereferenced/0")
 2007     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-dereferenced/1")
 2008     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-dereferenced/2")
 2009     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-dereferenced/3")
 2010     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-dereferenced/4")
 2011     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-dereferenced/5")
 2012     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-dereferenced/6")
 2013     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-local-var-dereferenced/7")
 2014     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *ecx"  "F - test-convert-function-with-local-var-dereferenced/8")
 2015     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-dereferenced/9")
 2016     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-dereferenced/10")
 2017     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-dereferenced/11")
 2018     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-dereferenced/12")
 2019     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-dereferenced/13")
 2020     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-dereferenced/14")
 2021     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-dereferenced/15")
 2022     # . epilogue
 2023     89/<- %esp 5/r32/ebp
 2024     5d/pop-to-ebp
 2025     c3/return
 2026 
 2027 # variables of type 'byte' are not allowed on the stack
 2028 test-convert-function-with-byte-operations:
 2029     # . prologue
 2030     55/push-ebp
 2031     89/<- %ebp 4/r32/esp
 2032     # setup
 2033     (clear-stream _test-input-stream)
 2034     (clear-stream $_test-input-buffered-file->buffer)
 2035     (clear-stream _test-output-stream)
 2036     (clear-stream $_test-output-buffered-file->buffer)
 2037     #
 2038     (write _test-input-stream "fn foo {\n")
 2039     (write _test-input-stream "  var x/eax: byte <- copy 0\n")
 2040     (write _test-input-stream "  var y/ecx: byte <- copy 0\n")
 2041     (write _test-input-stream "  y <- copy-byte x\n")
 2042     (write _test-input-stream "  var z/edx: (addr byte) <- copy 0\n")
 2043     (write _test-input-stream "  y <- copy-byte *z\n")
 2044     (write _test-input-stream "  copy-byte-to *z, x\n")
 2045     (write _test-input-stream "}\n")
 2046     # convert
 2047     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2048     (flush _test-output-buffered-file)
 2049 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2055     # check output
 2056     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-function-with-byte-operations/0")
 2057     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-function-with-byte-operations/1")
 2058     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-function-with-byte-operations/2")
 2059     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-function-with-byte-operations/3")
 2060     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-function-with-byte-operations/4")
 2061     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-function-with-byte-operations/5")
 2062     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-function-with-byte-operations/6")
 2063     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-function-with-byte-operations/7")
 2064     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-function-with-byte-operations/8")
 2065     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"                  "F - test-convert-function-with-byte-operations/9")
 2066     (check-next-stream-line-equal _test-output-stream "    8a/byte-> %eax 0x00000001/r32"           "F - test-convert-function-with-byte-operations/10")
 2067     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %edx"                    "F - test-convert-function-with-byte-operations/11")
 2068     (check-next-stream-line-equal _test-output-stream "    ba/copy-to-edx 0/imm32"                  "F - test-convert-function-with-byte-operations/12")
 2069     (check-next-stream-line-equal _test-output-stream "    8a/byte-> *edx 0x00000001/r32"           "F - test-convert-function-with-byte-operations/13")
 2070     (check-next-stream-line-equal _test-output-stream "    88/byte<- *edx 0x00000000/r32"           "F - test-convert-function-with-byte-operations/14")
 2071     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %edx"                     "F - test-convert-function-with-byte-operations/15")
 2072     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-function-with-byte-operations/16")
 2073     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-function-with-byte-operations/17")
 2074     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-function-with-byte-operations/18")
 2075     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-function-with-byte-operations/19")
 2076     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-function-with-byte-operations/20")
 2077     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-function-with-byte-operations/21")
 2078     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-function-with-byte-operations/22")
 2079     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-function-with-byte-operations/23")
 2080     # . epilogue
 2081     89/<- %esp 5/r32/ebp
 2082     5d/pop-to-ebp
 2083     c3/return
 2084 
 2085 # variables of type 'byte' _can_ be function args. They then occupy 4 bytes.
 2086 test-copy-byte-var-from-fn-arg:
 2087     # . prologue
 2088     55/push-ebp
 2089     89/<- %ebp 4/r32/esp
 2090     # setup
 2091     (clear-stream _test-input-stream)
 2092     (clear-stream $_test-input-buffered-file->buffer)
 2093     (clear-stream _test-output-stream)
 2094     (clear-stream $_test-output-buffered-file->buffer)
 2095     #
 2096     (write _test-input-stream "fn foo x: byte, y: int {\n")
 2097     (write _test-input-stream "  var a/eax: byte <- copy x\n")
 2098     (write _test-input-stream "  var b/eax: int <- copy y\n")
 2099     (write _test-input-stream "}\n")
 2100     # convert
 2101     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2102     (flush _test-output-buffered-file)
 2103 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2109     # check output
 2110     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-copy-byte-from-fn-arg/0")
 2111     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-copy-byte-from-fn-arg/1")
 2112     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-copy-byte-from-fn-arg/2")
 2113     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-copy-byte-from-fn-arg/3")
 2114     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-copy-byte-from-fn-arg/4")
 2115     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-copy-byte-from-fn-arg/5")
 2116     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-copy-byte-from-fn-arg/6")
 2117     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/7")
 2118     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x0000000c) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/8")
 2119     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"   "F - test-copy-byte-from-fn-arg/9")
 2120     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-copy-byte-from-fn-arg/10")
 2121     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-copy-byte-from-fn-arg/11")
 2122     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-copy-byte-from-fn-arg/12")
 2123     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-copy-byte-from-fn-arg/13")
 2124     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-copy-byte-from-fn-arg/14")
 2125     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-copy-byte-from-fn-arg/15")
 2126     # . epilogue
 2127     89/<- %esp 5/r32/ebp
 2128     5d/pop-to-ebp
 2129     c3/return
 2130 
 2131 test-convert-compare-register-with-literal:
 2132     # . prologue
 2133     55/push-ebp
 2134     89/<- %ebp 4/r32/esp
 2135     # setup
 2136     (clear-stream _test-input-stream)
 2137     (clear-stream $_test-input-buffered-file->buffer)
 2138     (clear-stream _test-output-stream)
 2139     (clear-stream $_test-output-buffered-file->buffer)
 2140     #
 2141     (write _test-input-stream "fn foo {\n")
 2142     (write _test-input-stream "  var x/ecx: int <- copy 0\n")
 2143     (write _test-input-stream "  compare x, 0\n")
 2144     (write _test-input-stream "}\n")
 2145     # convert
 2146     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2147     (flush _test-output-buffered-file)
 2148 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2154     # check output
 2155     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-compare-register-with-literal/0")
 2156     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-compare-register-with-literal/1")
 2157     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-compare-register-with-literal/2")
 2158     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-compare-register-with-literal/3")
 2159     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-compare-register-with-literal/4")
 2160     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-compare-register-with-literal/5")
 2161     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 2162     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-compare-register-with-literal/7")
 2163     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0/imm32"  "F - test-convert-compare-register-with-literal/8")
 2164     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 2165     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-compare-register-with-literal/10")
 2166     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-compare-register-with-literal/11")
 2167     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-compare-register-with-literal/12")
 2168     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-compare-register-with-literal/13")
 2169     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-compare-register-with-literal/14")
 2170     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-compare-register-with-literal/15")
 2171     # . epilogue
 2172     89/<- %esp 5/r32/ebp
 2173     5d/pop-to-ebp
 2174     c3/return
 2175 
 2176 test-unknown-variable:
 2177     # . prologue
 2178     55/push-ebp
 2179     89/<- %ebp 4/r32/esp
 2180     # setup
 2181     (clear-stream _test-input-stream)
 2182     (clear-stream $_test-input-buffered-file->buffer)
 2183     (clear-stream _test-output-stream)
 2184     (clear-stream $_test-output-buffered-file->buffer)
 2185     (clear-stream _test-error-stream)
 2186     (clear-stream $_test-error-buffered-file->buffer)
 2187     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2188     68/push 0/imm32
 2189     68/push 0/imm32
 2190     89/<- %edx 4/r32/esp
 2191     (tailor-exit-descriptor %edx 0x10)
 2192     #
 2193     (write _test-input-stream "fn foo {\n")
 2194     (write _test-input-stream "  compare x, 0\n")
 2195     (write _test-input-stream "}\n")
 2196     # convert
 2197     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2198     # registers except esp clobbered at this point
 2199     # restore ed
 2200     89/<- %edx 4/r32/esp
 2201     (flush _test-output-buffered-file)
 2202     (flush _test-error-buffered-file)
 2203 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 2209     # check output
 2210     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable: output should be empty")
 2211     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable: error message")
 2212     # check that stop(1) was called
 2213     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable: exit status")
 2214     # don't restore from ebp
 2215     81 0/subop/add %esp 8/imm32
 2216     # . epilogue
 2217     5d/pop-to-ebp
 2218     c3/return
 2219 
 2220 test-convert-function-with-local-var-in-block:
 2221     # . prologue
 2222     55/push-ebp
 2223     89/<- %ebp 4/r32/esp
 2224     # setup
 2225     (clear-stream _test-input-stream)
 2226     (clear-stream $_test-input-buffered-file->buffer)
 2227     (clear-stream _test-output-stream)
 2228     (clear-stream $_test-output-buffered-file->buffer)
 2229     #
 2230     (write _test-input-stream "fn foo {\n")
 2231     (write _test-input-stream "  {\n")
 2232     (write _test-input-stream "    var x: int\n")
 2233     (write _test-input-stream "    increment x\n")
 2234     (write _test-input-stream "  }\n")
 2235     (write _test-input-stream "}\n")
 2236     # convert
 2237     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2238     (flush _test-output-buffered-file)
 2239 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2245     # check output
 2246     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-block/0")
 2247     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-block/1")
 2248     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-block/2")
 2249     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-block/3")
 2250     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-block/4")
 2251     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-block/5")
 2252     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-block/6")
 2253     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-local-var-in-block/7")
 2254     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-block/8")
 2255     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-block/9")
 2256     (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")
 2257     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-block/11")
 2258     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-local-var-in-block/12")
 2259     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-block/13")
 2260     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-block/14")
 2261     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-block/15")
 2262     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-block/16")
 2263     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-block/17")
 2264     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-block/18")
 2265     # . epilogue
 2266     89/<- %esp 5/r32/ebp
 2267     5d/pop-to-ebp
 2268     c3/return
 2269 
 2270 test-convert-function-with-local-var-in-named-block:
 2271     # . prologue
 2272     55/push-ebp
 2273     89/<- %ebp 4/r32/esp
 2274     # setup
 2275     (clear-stream _test-input-stream)
 2276     (clear-stream $_test-input-buffered-file->buffer)
 2277     (clear-stream _test-output-stream)
 2278     (clear-stream $_test-output-buffered-file->buffer)
 2279     #
 2280     (write _test-input-stream "fn foo {\n")
 2281     (write _test-input-stream "  $bar: {\n")
 2282     (write _test-input-stream "    var x: int\n")
 2283     (write _test-input-stream "    increment x\n")
 2284     (write _test-input-stream "  }\n")
 2285     (write _test-input-stream "}\n")
 2286     # convert
 2287     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2288     (flush _test-output-buffered-file)
 2289 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2295     # check output
 2296     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-named-block/0")
 2297     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-named-block/1")
 2298     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-named-block/2")
 2299     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-named-block/3")
 2300     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-named-block/4")
 2301     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-named-block/5")
 2302     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-named-block/6")
 2303     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-local-var-in-named-block/7")
 2304     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-named-block/8")
 2305     (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")
 2306     (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")
 2307     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-named-block/11")
 2308     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-local-var-in-named-block/12")
 2309     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-named-block/13")
 2310     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-named-block/14")
 2311     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-named-block/15")
 2312     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-named-block/16")
 2313     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-named-block/17")
 2314     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-named-block/18")
 2315     # . epilogue
 2316     89/<- %esp 5/r32/ebp
 2317     5d/pop-to-ebp
 2318     c3/return
 2319 
 2320 test-unknown-variable-in-named-block:
 2321     # . prologue
 2322     55/push-ebp
 2323     89/<- %ebp 4/r32/esp
 2324     # setup
 2325     (clear-stream _test-input-stream)
 2326     (clear-stream $_test-input-buffered-file->buffer)
 2327     (clear-stream _test-output-stream)
 2328     (clear-stream $_test-output-buffered-file->buffer)
 2329     (clear-stream _test-error-stream)
 2330     (clear-stream $_test-error-buffered-file->buffer)
 2331     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2332     68/push 0/imm32
 2333     68/push 0/imm32
 2334     89/<- %edx 4/r32/esp
 2335     (tailor-exit-descriptor %edx 0x10)
 2336     #
 2337     (write _test-input-stream "fn foo {\n")
 2338     (write _test-input-stream "  $a: {\n")
 2339     (write _test-input-stream "    compare x, 0\n")
 2340     (write _test-input-stream "  }\n")
 2341     (write _test-input-stream "}\n")
 2342     # convert
 2343     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2344     # registers except esp clobbered at this point
 2345     # restore ed
 2346     89/<- %edx 4/r32/esp
 2347     (flush _test-output-buffered-file)
 2348     (flush _test-error-buffered-file)
 2349 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 2355     # check output
 2356     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable-in-named-block: output should be empty")
 2357     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable-in-named-block: error message")
 2358     # check that stop(1) was called
 2359     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable-in-named-block: exit status")
 2360     # don't restore from ebp
 2361     81 0/subop/add %esp 8/imm32
 2362     # . epilogue
 2363     5d/pop-to-ebp
 2364     c3/return
 2365 
 2366 test-always-shadow-outermost-reg-vars-in-function:
 2367     # . prologue
 2368     55/push-ebp
 2369     89/<- %ebp 4/r32/esp
 2370     # setup
 2371     (clear-stream _test-input-stream)
 2372     (clear-stream $_test-input-buffered-file->buffer)
 2373     (clear-stream _test-output-stream)
 2374     (clear-stream $_test-output-buffered-file->buffer)
 2375     #
 2376     (write _test-input-stream "fn foo {\n")
 2377     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2378     (write _test-input-stream "}\n")
 2379     # convert
 2380     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2381     (flush _test-output-buffered-file)
 2382 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2388     # check output
 2389     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-always-shadow-outermost-reg-vars-in-function/0")
 2390     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-always-shadow-outermost-reg-vars-in-function/1")
 2391     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-always-shadow-outermost-reg-vars-in-function/2")
 2392     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-always-shadow-outermost-reg-vars-in-function/3")
 2393     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-always-shadow-outermost-reg-vars-in-function/4")
 2394     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-always-shadow-outermost-reg-vars-in-function/5")
 2395     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 2396     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-always-shadow-outermost-reg-vars-in-function/8")
 2397     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 2398     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-always-shadow-outermost-reg-vars-in-function/12")
 2399     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-always-shadow-outermost-reg-vars-in-function/13")
 2400     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-always-shadow-outermost-reg-vars-in-function/14")
 2401     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-always-shadow-outermost-reg-vars-in-function/15")
 2402     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-always-shadow-outermost-reg-vars-in-function/16")
 2403     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-always-shadow-outermost-reg-vars-in-function/17")
 2404     # . epilogue
 2405     89/<- %esp 5/r32/ebp
 2406     5d/pop-to-ebp
 2407     c3/return
 2408 
 2409 _pending-test-clobber-dead-local:
 2410     # . prologue
 2411     55/push-ebp
 2412     89/<- %ebp 4/r32/esp
 2413     # setup
 2414     (clear-stream _test-input-stream)
 2415     (clear-stream $_test-input-buffered-file->buffer)
 2416     (clear-stream _test-output-stream)
 2417     (clear-stream $_test-output-buffered-file->buffer)
 2418     #
 2419     (write _test-input-stream "fn foo {\n")
 2420     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2421     (write _test-input-stream "  {\n")
 2422     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2423     (write _test-input-stream "  }\n")
 2424     (write _test-input-stream "}\n")
 2425     # convert
 2426     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2427     (flush _test-output-buffered-file)
 2428 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2434     # check output
 2435     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-clobber-dead-local/0")
 2436     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-clobber-dead-local/1")
 2437     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-clobber-dead-local/2")
 2438     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-clobber-dead-local/3")
 2439     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-clobber-dead-local/4")
 2440     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-clobber-dead-local/5")
 2441     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-clobber-dead-local/6")
 2442     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-clobber-dead-local/7")
 2443     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-clobber-dead-local/8")
 2444     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-clobber-dead-local/9")
 2445     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-clobber-dead-local/10")  # no push/pop here
 2446     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-clobber-dead-local/11")
 2447     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-clobber-dead-local/12")
 2448     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-clobber-dead-local/13")
 2449     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-clobber-dead-local/14")
 2450     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-clobber-dead-local/15")
 2451     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-clobber-dead-local/16")
 2452     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-clobber-dead-local/17")
 2453     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-clobber-dead-local/18")
 2454     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-clobber-dead-local/19")
 2455     # . epilogue
 2456     89/<- %esp 5/r32/ebp
 2457     5d/pop-to-ebp
 2458     c3/return
 2459 
 2460 test-shadow-live-local:
 2461     # . prologue
 2462     55/push-ebp
 2463     89/<- %ebp 4/r32/esp
 2464     # setup
 2465     (clear-stream _test-input-stream)
 2466     (clear-stream $_test-input-buffered-file->buffer)
 2467     (clear-stream _test-output-stream)
 2468     (clear-stream $_test-output-buffered-file->buffer)
 2469     #
 2470     (write _test-input-stream "fn foo {\n")
 2471     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2472     (write _test-input-stream "  {\n")
 2473     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2474     (write _test-input-stream "  }\n")
 2475     (write _test-input-stream "  x <- increment\n")
 2476     (write _test-input-stream "}\n")
 2477     # convert
 2478     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2479     (flush _test-output-buffered-file)
 2480 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2486     # check output
 2487     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-local/0")
 2488     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-local/1")
 2489     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-local/2")
 2490     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-local/3")
 2491     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-local/4")
 2492     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-local/5")
 2493     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-live-local/6")
 2494     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-live-local/7")
 2495     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-local/8")
 2496     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-local/9")
 2497     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-local/10")
 2498     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-local/11")
 2499     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-local/12")
 2500     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-local/13")
 2501     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-local/14")
 2502     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-local/15")
 2503     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-live-local/16")
 2504     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-local/17")
 2505     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-local/18")
 2506     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-local/19")
 2507     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-local/20")
 2508     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-local/21")
 2509     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-local/22")
 2510     # . epilogue
 2511     89/<- %esp 5/r32/ebp
 2512     5d/pop-to-ebp
 2513     c3/return
 2514 
 2515 test-shadow-name:
 2516     # . prologue
 2517     55/push-ebp
 2518     89/<- %ebp 4/r32/esp
 2519     # setup
 2520     (clear-stream _test-input-stream)
 2521     (clear-stream $_test-input-buffered-file->buffer)
 2522     (clear-stream _test-output-stream)
 2523     (clear-stream $_test-output-buffered-file->buffer)
 2524     #
 2525     (write _test-input-stream "fn foo {\n")
 2526     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2527     (write _test-input-stream "  {\n")
 2528     (write _test-input-stream "    var x/edx: int <- copy 4\n")
 2529     (write _test-input-stream "  }\n")
 2530     (write _test-input-stream "  x <- increment\n")
 2531     (write _test-input-stream "}\n")
 2532     # convert
 2533     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2534     (flush _test-output-buffered-file)
 2535 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2541     # check output
 2542     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name/0")
 2543     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name/1")
 2544     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name/2")
 2545     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name/3")
 2546     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name/4")
 2547     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name/5")
 2548     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name/6")
 2549     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name/7")
 2550     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name/8")
 2551     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name/9")
 2552     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name/10")
 2553     (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name/11")
 2554     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name/12")
 2555     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name/13")
 2556     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name/14")
 2557     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name/15")
 2558     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name/16")
 2559     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name/17")
 2560     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name/18")
 2561     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name/19")
 2562     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name/20")
 2563     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name/21")
 2564     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name/22")
 2565     # . epilogue
 2566     89/<- %esp 5/r32/ebp
 2567     5d/pop-to-ebp
 2568     c3/return
 2569 
 2570 test-shadow-name-2:
 2571     # . prologue
 2572     55/push-ebp
 2573     89/<- %ebp 4/r32/esp
 2574     # setup
 2575     (clear-stream _test-input-stream)
 2576     (clear-stream $_test-input-buffered-file->buffer)
 2577     (clear-stream _test-output-stream)
 2578     (clear-stream $_test-output-buffered-file->buffer)
 2579     #
 2580     (write _test-input-stream "fn foo {\n")
 2581     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2582     (write _test-input-stream "  {\n")
 2583     (write _test-input-stream "    var x/edx: int <- copy 4\n")
 2584     (write _test-input-stream "    var y/ecx: int <- copy 5\n")
 2585     (write _test-input-stream "  }\n")
 2586     (write _test-input-stream "  x <- increment\n")
 2587     (write _test-input-stream "}\n")
 2588     # convert
 2589     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2590     (flush _test-output-buffered-file)
 2591 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2597     # check output
 2598     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name-2/0")
 2599     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name-2/1")
 2600     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name-2/2")
 2601     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name-2/3")
 2602     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name-2/4")
 2603     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name-2/5")
 2604     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name-2/6")
 2605     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name-2/7")
 2606     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name-2/8")
 2607     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name-2/9")
 2608     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name-2/10")
 2609     (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name-2/11")
 2610     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-name-2/12")
 2611     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 5/imm32"  "F - test-shadow-name-2/13")
 2612     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-name-2/14")
 2613     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name-2/15")
 2614     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name-2/16")
 2615     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name-2/17")
 2616     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name-2/18")
 2617     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name-2/19")
 2618     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name-2/20")
 2619     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name-2/21")
 2620     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name-2/22")
 2621     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name-2/23")
 2622     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name-2/24")
 2623     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name-2/25")
 2624     # . epilogue
 2625     89/<- %esp 5/r32/ebp
 2626     5d/pop-to-ebp
 2627     c3/return
 2628 
 2629 test-do-not-spill-same-register-in-block:
 2630     # . prologue
 2631     55/push-ebp
 2632     89/<- %ebp 4/r32/esp
 2633     # setup
 2634     (clear-stream _test-input-stream)
 2635     (clear-stream $_test-input-buffered-file->buffer)
 2636     (clear-stream _test-output-stream)
 2637     (clear-stream $_test-output-buffered-file->buffer)
 2638     #
 2639     (write _test-input-stream "fn foo {\n")
 2640     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2641     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2642     (write _test-input-stream "  y <- increment\n")
 2643     (write _test-input-stream "}\n")
 2644     # convert
 2645     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2646     (flush _test-output-buffered-file)
 2647 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2653     # check output
 2654     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-do-not-spill-same-register-in-block/0")
 2655     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-do-not-spill-same-register-in-block/1")
 2656     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-do-not-spill-same-register-in-block/2")
 2657     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-do-not-spill-same-register-in-block/3")
 2658     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-do-not-spill-same-register-in-block/4")
 2659     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-do-not-spill-same-register-in-block/5")
 2660     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-do-not-spill-same-register-in-block/6")
 2661     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-do-not-spill-same-register-in-block/7")
 2662     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-do-not-spill-same-register-in-block/8")
 2663     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-do-not-spill-same-register-in-block/9")
 2664     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-do-not-spill-same-register-in-block/10")
 2665     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-do-not-spill-same-register-in-block/11")
 2666     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-do-not-spill-same-register-in-block/12")
 2667     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-do-not-spill-same-register-in-block/13")
 2668     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-do-not-spill-same-register-in-block/14")
 2669     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-do-not-spill-same-register-in-block/15")
 2670     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-do-not-spill-same-register-in-block/16")
 2671     # . epilogue
 2672     89/<- %esp 5/r32/ebp
 2673     5d/pop-to-ebp
 2674     c3/return
 2675 
 2676 test-spill-different-register-in-block:
 2677     # . prologue
 2678     55/push-ebp
 2679     89/<- %ebp 4/r32/esp
 2680     # setup
 2681     (clear-stream _test-input-stream)
 2682     (clear-stream $_test-input-buffered-file->buffer)
 2683     (clear-stream _test-output-stream)
 2684     (clear-stream $_test-output-buffered-file->buffer)
 2685     #
 2686     (write _test-input-stream "fn foo {\n")
 2687     (write _test-input-stream "  var x/eax: int <- copy 3\n")
 2688     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2689     (write _test-input-stream "  y <- increment\n")
 2690     (write _test-input-stream "}\n")
 2691     # convert
 2692     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2693     (flush _test-output-buffered-file)
 2694 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2700     # check output
 2701     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-spill-different-register-in-block/0")
 2702     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-spill-different-register-in-block/1")
 2703     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-spill-different-register-in-block/2")
 2704     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-spill-different-register-in-block/3")
 2705     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-spill-different-register-in-block/4")
 2706     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-spill-different-register-in-block/5")
 2707     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-spill-different-register-in-block/6")
 2708     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-spill-different-register-in-block/7")
 2709     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-spill-different-register-in-block/8")
 2710     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-spill-different-register-in-block/9")
 2711     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-spill-different-register-in-block/10")
 2712     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-spill-different-register-in-block/11")
 2713     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-spill-different-register-in-block/12")
 2714     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-spill-different-register-in-block/13")
 2715     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-spill-different-register-in-block/14")
 2716     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-spill-different-register-in-block/15")
 2717     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-spill-different-register-in-block/16")
 2718     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-spill-different-register-in-block/17")
 2719     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-spill-different-register-in-block/18")
 2720     # . epilogue
 2721     89/<- %esp 5/r32/ebp
 2722     5d/pop-to-ebp
 2723     c3/return
 2724 
 2725 test-shadow-live-output:
 2726     # . prologue
 2727     55/push-ebp
 2728     89/<- %ebp 4/r32/esp
 2729     # setup
 2730     (clear-stream _test-input-stream)
 2731     (clear-stream $_test-input-buffered-file->buffer)
 2732     (clear-stream _test-output-stream)
 2733     (clear-stream $_test-output-buffered-file->buffer)
 2734     #
 2735     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2736     (write _test-input-stream "  x <- copy 3\n")
 2737     (write _test-input-stream "  {\n")
 2738     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2739     (write _test-input-stream "  }\n")
 2740     (write _test-input-stream "  x <- increment\n")
 2741     (write _test-input-stream "}\n")
 2742     # convert
 2743     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2744     (flush _test-output-buffered-file)
 2745 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2751     # check output
 2752     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-output/0")
 2753     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-output/1")
 2754     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-output/2")
 2755     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-output/3")
 2756     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-output/4")
 2757     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-output/5")
 2758     (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
 2759     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-output/8")
 2760     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-output/9")
 2761     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-output/10")
 2762     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-output/11")
 2763     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-output/12")
 2764     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-output/13")
 2765     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-output/14")
 2766     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-output/15")
 2767     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-output/17")
 2768     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-output/18")
 2769     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-output/19")
 2770     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-output/20")
 2771     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-output/21")
 2772     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-output/21")
 2773     # . epilogue
 2774     89/<- %esp 5/r32/ebp
 2775     5d/pop-to-ebp
 2776     c3/return
 2777 
 2778 test-stmt-defines-output-in-same-register-as-inout:
 2779     # . prologue
 2780     55/push-ebp
 2781     89/<- %ebp 4/r32/esp
 2782     # setup
 2783     (clear-stream _test-input-stream)
 2784     (clear-stream $_test-input-buffered-file->buffer)
 2785     (clear-stream _test-output-stream)
 2786     (clear-stream $_test-output-buffered-file->buffer)
 2787     (clear-stream _test-error-stream)
 2788     (clear-stream $_test-error-buffered-file->buffer)
 2789     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2790     68/push 0/imm32
 2791     68/push 0/imm32
 2792     89/<- %edx 4/r32/esp
 2793     (tailor-exit-descriptor %edx 0x10)
 2794     #
 2795     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2796     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2797     (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
 2798     (write _test-input-stream "}\n")
 2799     # convert
 2800     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2801     # registers except esp clobbered at this point
 2802     # restore ed
 2803     89/<- %edx 4/r32/esp
 2804     (flush _test-output-buffered-file)
 2805     (flush _test-error-buffered-file)
 2806 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 2812     # no error; we looked up 'y' correctly before pushing the binding for 'x'
 2813     (check-stream-equal _test-error-stream  ""  "F - test-stmt-defines-output-in-same-register-as-inout: error stream should be empty")
 2814     # don't bother checking the generated code; that's in the test 'test-local-clobbered-by-fn-output' below
 2815     # don't restore from ebp
 2816     81 0/subop/add %esp 8/imm32
 2817     # . epilogue
 2818     5d/pop-to-ebp
 2819     c3/return
 2820 
 2821 test-local-clobbered-by-fn-output:
 2822     # . prologue
 2823     55/push-ebp
 2824     89/<- %ebp 4/r32/esp
 2825     # setup
 2826     (clear-stream _test-input-stream)
 2827     (clear-stream $_test-input-buffered-file->buffer)
 2828     (clear-stream _test-output-stream)
 2829     (clear-stream $_test-output-buffered-file->buffer)
 2830     #
 2831     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2832     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2833     (write _test-input-stream "  x <- copy y\n")
 2834     (write _test-input-stream "}\n")
 2835     # convert
 2836     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2837     (flush _test-output-buffered-file)
 2838 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2844     # check output
 2845     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-local-clobbered-by-fn-output/0")
 2846     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-local-clobbered-by-fn-output/1")
 2847     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-local-clobbered-by-fn-output/2")
 2848     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-local-clobbered-by-fn-output/3")
 2849     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-local-clobbered-by-fn-output/4")
 2850     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-local-clobbered-by-fn-output/5")
 2851     (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
 2852     (check-next-stream-line-equal _test-output-stream "    89/<- %ecx 0x00000001/r32"  "F - test-local-clobbered-by-fn-output/7")
 2853     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-local-clobbered-by-fn-output/8")
 2854     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-local-clobbered-by-fn-output/9")
 2855     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-local-clobbered-by-fn-output/10")
 2856     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-local-clobbered-by-fn-output/11")
 2857     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-local-clobbered-by-fn-output/12")
 2858     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-local-clobbered-by-fn-output/13")
 2859     # . epilogue
 2860     89/<- %esp 5/r32/ebp
 2861     5d/pop-to-ebp
 2862     c3/return
 2863 
 2864 test-read-output:
 2865     # . prologue
 2866     55/push-ebp
 2867     89/<- %ebp 4/r32/esp
 2868     # setup
 2869     (clear-stream _test-input-stream)
 2870     (clear-stream $_test-input-buffered-file->buffer)
 2871     (clear-stream _test-output-stream)
 2872     (clear-stream $_test-output-buffered-file->buffer)
 2873     #
 2874     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2875     (write _test-input-stream "  x <- copy 0x34\n")
 2876     (write _test-input-stream "  compare x, 0x35\n")
 2877     (write _test-input-stream "}\n")
 2878     # convert
 2879     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2880     (flush _test-output-buffered-file)
 2881 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2887     # check output
 2888     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-read-output/0")
 2889     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-read-output/1")
 2890     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-read-output/2")
 2891     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-read-output/3")
 2892     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-read-output/4")
 2893     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-read-output/5")
 2894     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x34/imm32"  "F - test-read-output/6")
 2895     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0x35/imm32"  "F - test-read-output/7")
 2896     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-read-output/8")
 2897     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-read-output/9")
 2898     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-read-output/10")
 2899     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-read-output/11")
 2900     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-read-output/12")
 2901     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-read-output/13")
 2902     # . epilogue
 2903     89/<- %esp 5/r32/ebp
 2904     5d/pop-to-ebp
 2905     c3/return
 2906 
 2907 test-fn-output-written-in-inner-block:
 2908     # . prologue
 2909     55/push-ebp
 2910     89/<- %ebp 4/r32/esp
 2911     # setup
 2912     (clear-stream _test-input-stream)
 2913     (clear-stream $_test-input-buffered-file->buffer)
 2914     (clear-stream _test-output-stream)
 2915     (clear-stream $_test-output-buffered-file->buffer)
 2916     #
 2917     (write _test-input-stream "fn foo -> out/edi: int {\n")
 2918     (write _test-input-stream "  var a/eax: int <- copy 3\n")  # define outer local
 2919     (write _test-input-stream "  {\n")
 2920     (write _test-input-stream "    var a/ecx: int <- copy 4\n")  # shadow outer local
 2921     (write _test-input-stream "    out <- copy a\n")  # write to fn output
 2922     (write _test-input-stream "  }\n")
 2923     (write _test-input-stream "  compare a, 0\n")  # use outer local
 2924     (write _test-input-stream "}\n")
 2925     # convert
 2926     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2927     (flush _test-output-buffered-file)
 2928 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2934     # no error; defining 'out' didn't interfere with the reclamation of 'b'
 2935     # check output
 2936     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-fn-output-written-in-inner-block/0")
 2937     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-fn-output-written-in-inner-block/1")
 2938     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-fn-output-written-in-inner-block/2")
 2939     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-fn-output-written-in-inner-block/3")
 2940     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-fn-output-written-in-inner-block/4")
 2941     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-fn-output-written-in-inner-block/5")
 2942     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-fn-output-written-in-inner-block/6")
 2943     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-fn-output-written-in-inner-block/7")
 2944     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-fn-output-written-in-inner-block/8")
 2945     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-fn-output-written-in-inner-block/9")
 2946     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-fn-output-written-in-inner-block/10")
 2947     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-fn-output-written-in-inner-block/10")
 2948     (check-next-stream-line-equal _test-output-stream "      89/<- %edi 0x00000001/r32"  "F - test-fn-output-written-in-inner-block/11")
 2949     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx"  "F - test-fn-output-written-in-inner-block/12")
 2950     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-fn-output-written-in-inner-block/13")
 2951     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-fn-output-written-in-inner-block/14")
 2952     (check-next-stream-line-equal _test-output-stream "    3d/compare-eax-with 0/imm32"  "F - test-fn-output-written-in-inner-block/15")
 2953     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-fn-output-written-in-inner-block/16")
 2954     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-fn-output-written-in-inner-block/17")
 2955     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-fn-output-written-in-inner-block/18")
 2956     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-fn-output-written-in-inner-block/19")
 2957     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-fn-output-written-in-inner-block/20")
 2958     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-fn-output-written-in-inner-block/21")
 2959     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-fn-output-written-in-inner-block/22")
 2960     # . epilogue
 2961     89/<- %esp 5/r32/ebp
 2962     5d/pop-to-ebp
 2963     c3/return
 2964 
 2965 test-convert-function-with-branches-in-block:
 2966     # . prologue
 2967     55/push-ebp
 2968     89/<- %ebp 4/r32/esp
 2969     # setup
 2970     (clear-stream _test-input-stream)
 2971     (clear-stream $_test-input-buffered-file->buffer)
 2972     (clear-stream _test-output-stream)
 2973     (clear-stream $_test-output-buffered-file->buffer)
 2974     #
 2975     (write _test-input-stream "fn foo x: int {\n")
 2976     (write _test-input-stream "  {\n")
 2977     (write _test-input-stream "    break-if->=\n")
 2978     (write _test-input-stream "    loop-if-addr<\n")
 2979     (write _test-input-stream "    increment x\n")
 2980     (write _test-input-stream "    loop\n")
 2981     (write _test-input-stream "  }\n")
 2982     (write _test-input-stream "}\n")
 2983     # convert
 2984     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2985     (flush _test-output-buffered-file)
 2986 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2992     # check output
 2993     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-block/0")
 2994     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-block/1")
 2995     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-block/2")
 2996     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-block/3")
 2997     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-block/4")
 2998     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-block/5")
 2999     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-block/6")
 3000     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-in-block/7")
 3001     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/8")
 3002     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-block/9")
 3003     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-in-block/10")
 3004     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/11")
 3005     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/12")
 3006     (check-next-stream-line-equal _test-output-stream "        0f 83/jump-if-addr>= break/disp32"  "F - test-convert-function-with-branches-in-block/13")
 3007     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:loop/disp32"  "F - test-convert-function-with-branches-in-block/14")
 3008     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/15")
 3009     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-block/16")
 3010     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-in-block/17")
 3011     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-block/18")
 3012     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-in-block/19")
 3013     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-block/20")
 3014     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-block/21")
 3015     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-block/22")
 3016     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-block/23")
 3017     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-block/24")
 3018     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-block/25")
 3019     # . epilogue
 3020     89/<- %esp 5/r32/ebp
 3021     5d/pop-to-ebp
 3022     c3/return
 3023 
 3024 test-convert-function-with-branches-in-named-block:
 3025     # . prologue
 3026     55/push-ebp
 3027     89/<- %ebp 4/r32/esp
 3028     # setup
 3029     (clear-stream _test-input-stream)
 3030     (clear-stream $_test-input-buffered-file->buffer)
 3031     (clear-stream _test-output-stream)
 3032     (clear-stream $_test-output-buffered-file->buffer)
 3033     #
 3034     (write _test-input-stream "fn foo x: int {\n")
 3035     (write _test-input-stream "  $bar: {\n")
 3036     (write _test-input-stream "    break-if->= $bar\n")
 3037     (write _test-input-stream "    loop-if-addr< $bar\n")
 3038     (write _test-input-stream "    increment x\n")
 3039     (write _test-input-stream "    loop\n")
 3040     (write _test-input-stream "  }\n")
 3041     (write _test-input-stream "}\n")
 3042     # convert
 3043     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3044     (flush _test-output-buffered-file)
 3045 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3051     # check output
 3052     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-named-block/0")
 3053     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-named-block/1")
 3054     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-named-block/2")
 3055     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-named-block/3")
 3056     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-named-block/4")
 3057     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-named-block/5")
 3058     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-named-block/6")
 3059     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-branches-in-named-block/7")
 3060     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/8")
 3061     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-named-block/9")
 3062     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:break/disp32"  "F - test-convert-function-with-branches-in-named-block/10")
 3063     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/11")
 3064     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/12")
 3065     (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")
 3066     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:loop/disp32"  "F - test-convert-function-with-branches-in-named-block/14")
 3067     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/15")
 3068     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-named-block/16")
 3069     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"   "F - test-convert-function-with-branches-in-named-block/17")
 3070     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-named-block/18")
 3071     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-branches-in-named-block/19")
 3072     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-named-block/20")
 3073     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-named-block/21")
 3074     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-named-block/22")
 3075     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-named-block/23")
 3076     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-named-block/24")
 3077     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-named-block/25")
 3078     # . epilogue
 3079     89/<- %esp 5/r32/ebp
 3080     5d/pop-to-ebp
 3081     c3/return
 3082 
 3083 test-convert-function-with-var-in-nested-block:
 3084     # . prologue
 3085     55/push-ebp
 3086     89/<- %ebp 4/r32/esp
 3087     # setup
 3088     (clear-stream _test-input-stream)
 3089     (clear-stream $_test-input-buffered-file->buffer)
 3090     (clear-stream _test-output-stream)
 3091     (clear-stream $_test-output-buffered-file->buffer)
 3092     #
 3093     (write _test-input-stream "fn foo x: int {\n")
 3094     (write _test-input-stream "  {\n")
 3095     (write _test-input-stream "    {\n")
 3096     (write _test-input-stream "      var x: int\n")
 3097     (write _test-input-stream "      increment x\n")
 3098     (write _test-input-stream "    }\n")
 3099     (write _test-input-stream "  }\n")
 3100     (write _test-input-stream "}\n")
 3101     # convert
 3102     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3103     (flush _test-output-buffered-file)
 3104 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3110     # check output
 3111     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-var-in-nested-block/0")
 3112     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-var-in-nested-block/1")
 3113     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-var-in-nested-block/2")
 3114     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-var-in-nested-block/3")
 3115     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-var-in-nested-block/4")
 3116     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-var-in-nested-block/5")
 3117     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-var-in-nested-block/6")
 3118     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-var-in-nested-block/7")
 3119     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-var-in-nested-block/8")
 3120     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-var-in-nested-block/9")
 3121     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-var-in-nested-block/10")
 3122     (check-next-stream-line-equal _test-output-stream "        ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-var-in-nested-block/11")
 3123     (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")
 3124     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-var-in-nested-block/13")
 3125     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-var-in-nested-block/14")
 3126     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-var-in-nested-block/15")
 3127     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-var-in-nested-block/16")
 3128     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-var-in-nested-block/17")
 3129     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-var-in-nested-block/18")
 3130     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-var-in-nested-block/19")
 3131     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-var-in-nested-block/20")
 3132     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-var-in-nested-block/21")
 3133     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-var-in-nested-block/22")
 3134     # . epilogue
 3135     89/<- %esp 5/r32/ebp
 3136     5d/pop-to-ebp
 3137     c3/return
 3138 
 3139 test-convert-function-with-multiple-vars-in-nested-blocks:
 3140     # . prologue
 3141     55/push-ebp
 3142     89/<- %ebp 4/r32/esp
 3143     # setup
 3144     (clear-stream _test-input-stream)
 3145     (clear-stream $_test-input-buffered-file->buffer)
 3146     (clear-stream _test-output-stream)
 3147     (clear-stream $_test-output-buffered-file->buffer)
 3148     #
 3149     (write _test-input-stream "fn foo x: int {\n")
 3150     (write _test-input-stream "  {\n")
 3151     (write _test-input-stream "    var x/eax: int <- copy 0\n")
 3152     (write _test-input-stream "    {\n")
 3153     (write _test-input-stream "      var y: int\n")
 3154     (write _test-input-stream "      x <- add y\n")
 3155     (write _test-input-stream "    }\n")
 3156     (write _test-input-stream "  }\n")
 3157     (write _test-input-stream "}\n")
 3158     # convert
 3159     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3160     (flush _test-output-buffered-file)
 3161 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3167     # check output
 3168     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-multiple-vars-in-nested-blocks/0")
 3169     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/1")
 3170     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-multiple-vars-in-nested-blocks/2")
 3171     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/3")
 3172     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/4")
 3173     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/5")
 3174     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/6")
 3175     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/7")
 3176     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %eax"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/8")
 3177     (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")
 3178     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/10")
 3179     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/11")
 3180     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/12")
 3181     (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")
 3182     (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")
 3183     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/15")
 3184     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/16")
 3185     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %eax"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/17")
 3186     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/18")
 3187     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/19")
 3188     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/20")
 3189     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/21")
 3190     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/22")
 3191     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/23")
 3192     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-multiple-vars-in-nested-blocks/24")
 3193     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-multiple-vars-in-nested-blocks/25")
 3194     # . epilogue
 3195     89/<- %esp 5/r32/ebp
 3196     5d/pop-to-ebp
 3197     c3/return
 3198 
 3199 test-convert-function-with-branches-and-local-vars:
 3200     # A conditional 'break' after a 'var' in a block is converted into a
 3201     # nested block that performs all necessary cleanup before jumping. This
 3202     # results in some ugly code duplication.
 3203     # . prologue
 3204     55/push-ebp
 3205     89/<- %ebp 4/r32/esp
 3206     # setup
 3207     (clear-stream _test-input-stream)
 3208     (clear-stream $_test-input-buffered-file->buffer)
 3209     (clear-stream _test-output-stream)
 3210     (clear-stream $_test-output-buffered-file->buffer)
 3211     #
 3212     (write _test-input-stream "fn foo {\n")
 3213     (write _test-input-stream "  {\n")
 3214     (write _test-input-stream "    var x: int\n")
 3215     (write _test-input-stream "    break-if->=\n")
 3216     (write _test-input-stream "    increment x\n")
 3217     (write _test-input-stream "  }\n")
 3218     (write _test-input-stream "}\n")
 3219     # convert
 3220     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3221     (flush _test-output-buffered-file)
 3222 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3228     # check output
 3229     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-local-vars/0")
 3230     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-local-vars/1")
 3231     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-local-vars/2")
 3232     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-and-local-vars/3")
 3233     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-local-vars/4")
 3234     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-local-vars/5")
 3235     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-local-vars/6")
 3236     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-local-vars/7")
 3237     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-local-vars/8")
 3238     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-local-vars/9")
 3239     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-and-local-vars/10")
 3240     (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")
 3241     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-and-local-vars/12")
 3242     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-local-vars/13")
 3243     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-branches-and-local-vars/14")
 3244     (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")
 3245     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-local-vars/16")
 3246     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-local-vars/17")
 3247     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-local-vars/18")
 3248     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-local-vars/19")
 3249     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-local-vars/20")
 3250     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-and-local-vars/21")
 3251     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-local-vars/22")
 3252     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-local-vars/23")
 3253     # . epilogue
 3254     89/<- %esp 5/r32/ebp
 3255     5d/pop-to-ebp
 3256     c3/return
 3257 
 3258 test-convert-function-with-conditional-loops-and-local-vars:
 3259     # A conditional 'loop' after a 'var' in a block is converted into a nested
 3260     # block that performs all necessary cleanup before jumping. This results
 3261     # in some ugly code duplication.
 3262     # . prologue
 3263     55/push-ebp
 3264     89/<- %ebp 4/r32/esp
 3265     # setup
 3266     (clear-stream _test-input-stream)
 3267     (clear-stream $_test-input-buffered-file->buffer)
 3268     (clear-stream _test-output-stream)
 3269     (clear-stream $_test-output-buffered-file->buffer)
 3270     #
 3271     (write _test-input-stream "fn foo {\n")
 3272     (write _test-input-stream "  {\n")
 3273     (write _test-input-stream "    var x: int\n")
 3274     (write _test-input-stream "    loop-if->=\n")
 3275     (write _test-input-stream "    increment x\n")
 3276     (write _test-input-stream "  }\n")
 3277     (write _test-input-stream "}\n")
 3278     # convert
 3279     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3280     (flush _test-output-buffered-file)
 3281 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3287     # check output
 3288     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-conditional-loops-and-local-vars/0")
 3289     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-conditional-loops-and-local-vars/1")
 3290     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-conditional-loops-and-local-vars/2")
 3291     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-conditional-loops-and-local-vars/3")
 3292     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-conditional-loops-and-local-vars/4")
 3293     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/5")
 3294     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-conditional-loops-and-local-vars/6")
 3295     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/7")
 3296     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-conditional-loops-and-local-vars/8")
 3297     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-conditional-loops-and-local-vars/9")
 3298     (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")
 3299     (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")
 3300     (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")
 3301     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-conditional-loops-and-local-vars/13")
 3302     (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")
 3303     (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")
 3304     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-conditional-loops-and-local-vars/16")
 3305     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/17")
 3306     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-conditional-loops-and-local-vars/18")
 3307     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/19")
 3308     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-conditional-loops-and-local-vars/20")
 3309     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-conditional-loops-and-local-vars/21")
 3310     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-conditional-loops-and-local-vars/22")
 3311     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-conditional-loops-and-local-vars/23")
 3312     # . epilogue
 3313     89/<- %esp 5/r32/ebp
 3314     5d/pop-to-ebp
 3315     c3/return
 3316 
 3317 test-convert-function-with-unconditional-loops-and-local-vars:
 3318     # An unconditional 'loop' after a 'var' in a block is emitted _after_ the
 3319     # regular block cleanup. Any instructions after 'loop' are dead and
 3320     # therefore skipped.
 3321     # . prologue
 3322     55/push-ebp
 3323     89/<- %ebp 4/r32/esp
 3324     # setup
 3325     (clear-stream _test-input-stream)
 3326     (clear-stream $_test-input-buffered-file->buffer)
 3327     (clear-stream _test-output-stream)
 3328     (clear-stream $_test-output-buffered-file->buffer)
 3329     #
 3330     (write _test-input-stream "fn foo {\n")
 3331     (write _test-input-stream "  {\n")
 3332     (write _test-input-stream "    var x: int\n")
 3333     (write _test-input-stream "    loop\n")
 3334     (write _test-input-stream "    increment x\n")
 3335     (write _test-input-stream "  }\n")
 3336     (write _test-input-stream "}\n")
 3337     # convert
 3338     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3339     (flush _test-output-buffered-file)
 3340 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3346     # check output
 3347     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-loops-and-local-vars/0")
 3348     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/1")
 3349     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-loops-and-local-vars/2")
 3350     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/3")
 3351     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/4")
 3352     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/5")
 3353     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/6")
 3354     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/7")
 3355     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-loops-and-local-vars/8")
 3356     (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")
 3357     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-unconditional-loops-and-local-vars/10")
 3358     # not emitted:                                           ff 0/subop/increment *(ebp+0xfffffffc)
 3359     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/11")
 3360     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/12")
 3361     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/13")
 3362     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/14")
 3363     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/15")
 3364     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/16")
 3365     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-loops-and-local-vars/17")
 3366     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-loops-and-local-vars/18")
 3367     # . epilogue
 3368     89/<- %esp 5/r32/ebp
 3369     5d/pop-to-ebp
 3370     c3/return
 3371 
 3372 test-convert-function-with-branches-and-loops-and-local-vars:
 3373     # . prologue
 3374     55/push-ebp
 3375     89/<- %ebp 4/r32/esp
 3376     # setup
 3377     (clear-stream _test-input-stream)
 3378     (clear-stream $_test-input-buffered-file->buffer)
 3379     (clear-stream _test-output-stream)
 3380     (clear-stream $_test-output-buffered-file->buffer)
 3381     #
 3382     (write _test-input-stream "fn foo {\n")
 3383     (write _test-input-stream "  {\n")
 3384     (write _test-input-stream "    var x: int\n")
 3385     (write _test-input-stream "    break-if->=\n")
 3386     (write _test-input-stream "    increment x\n")
 3387     (write _test-input-stream "    loop\n")
 3388     (write _test-input-stream "  }\n")
 3389     (write _test-input-stream "}\n")
 3390     # convert
 3391     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3392     (flush _test-output-buffered-file)
 3393 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3399     # check output
 3400     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-loops-and-local-vars/0")
 3401     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/1")
 3402     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-loops-and-local-vars/2")
 3403     (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")
 3404     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/4")
 3405     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/5")
 3406     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/6")
 3407     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/7")
 3408     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-loops-and-local-vars/8")
 3409     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/9")
 3410     (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")
 3411     (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")
 3412     (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")
 3413     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/13")
 3414     (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")
 3415     (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")
 3416     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/16")
 3417     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/17")
 3418     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/18")
 3419     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/19")
 3420     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/20")
 3421     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/21")
 3422     (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")
 3423     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-loops-and-local-vars/23")
 3424     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-loops-and-local-vars/24")
 3425     # . epilogue
 3426     89/<- %esp 5/r32/ebp
 3427     5d/pop-to-ebp
 3428     c3/return
 3429 
 3430 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars:
 3431     # . prologue
 3432     55/push-ebp
 3433     89/<- %ebp 4/r32/esp
 3434     # setup
 3435     (clear-stream _test-input-stream)
 3436     (clear-stream $_test-input-buffered-file->buffer)
 3437     (clear-stream _test-output-stream)
 3438     (clear-stream $_test-output-buffered-file->buffer)
 3439     #
 3440     (write _test-input-stream "fn foo {\n")
 3441     (write _test-input-stream "  a: {\n")
 3442     (write _test-input-stream "    var x: int\n")
 3443     (write _test-input-stream "    {\n")
 3444     (write _test-input-stream "      var y: int\n")
 3445     (write _test-input-stream "      break-if->= a\n")
 3446     (write _test-input-stream "      increment x\n")
 3447     (write _test-input-stream "      loop\n")
 3448     (write _test-input-stream "    }\n")
 3449     (write _test-input-stream "  }\n")
 3450     (write _test-input-stream "}\n")
 3451     # convert
 3452     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3453     (flush _test-output-buffered-file)
 3454 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3460     # check output
 3461     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/0")
 3462     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/1")
 3463     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/2")
 3464     (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")
 3465     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/4")
 3466     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/5")
 3467     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/6")
 3468     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/7")
 3469     (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")
 3470     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/9")
 3471     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/10")
 3472     (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")
 3473     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/12")
 3474     (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")
 3475     (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")
 3476     (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")
 3477     (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")
 3478     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/17")
 3479     (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")
 3480     (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")
 3481     (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")
 3482     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/21")
 3483     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/22")
 3484     (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")
 3485     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/24")
 3486     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/25")
 3487     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/26")
 3488     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/27")
 3489     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/28")
 3490     (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")
 3491     (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")
 3492     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/31")
 3493     # . epilogue
 3494     89/<- %esp 5/r32/ebp
 3495     5d/pop-to-ebp
 3496     c3/return
 3497 
 3498 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2:
 3499     # . prologue
 3500     55/push-ebp
 3501     89/<- %ebp 4/r32/esp
 3502     # setup
 3503     (clear-stream _test-input-stream)
 3504     (clear-stream $_test-input-buffered-file->buffer)
 3505     (clear-stream _test-output-stream)
 3506     (clear-stream $_test-output-buffered-file->buffer)
 3507     # non-local conditional branch from a block without a local variable,
 3508     # unwinding a local on the stack
 3509     (write _test-input-stream "fn foo {\n")
 3510     (write _test-input-stream "  a: {\n")
 3511     (write _test-input-stream "    var x: int\n")
 3512     (write _test-input-stream "    {\n")
 3513     (write _test-input-stream "      break-if->= a\n")
 3514     (write _test-input-stream "    }\n")
 3515     (write _test-input-stream "  }\n")
 3516     (write _test-input-stream "}\n")
 3517     # convert
 3518     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3519     (flush _test-output-buffered-file)
 3520 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3526     # check output
 3527     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/0")
 3528     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/1")
 3529     (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")
 3530     (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")
 3531     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/4")
 3532     (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")
 3533     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/6")
 3534     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/7")
 3535     (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")
 3536     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/9")
 3537     (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")
 3538     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/11")
 3539     (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")
 3540     (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")
 3541     (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")
 3542     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/15")
 3543     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/16")
 3544     (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")
 3545     (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")
 3546     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/19")
 3547     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/20")
 3548     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/21")
 3549     (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")
 3550     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/23")
 3551     (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")
 3552     (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")
 3553     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/26")
 3554     # . epilogue
 3555     89/<- %esp 5/r32/ebp
 3556     5d/pop-to-ebp
 3557     c3/return
 3558 
 3559 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3:
 3560     # . prologue
 3561     55/push-ebp
 3562     89/<- %ebp 4/r32/esp
 3563     # setup
 3564     (clear-stream _test-input-stream)
 3565     (clear-stream $_test-input-buffered-file->buffer)
 3566     (clear-stream _test-output-stream)
 3567     (clear-stream $_test-output-buffered-file->buffer)
 3568     # non-local unconditional branch from a block without a local variable,
 3569     # unwinding a local on the stack
 3570     (write _test-input-stream "fn foo {\n")
 3571     (write _test-input-stream "  a: {\n")
 3572     (write _test-input-stream "    var x: int\n")
 3573     (write _test-input-stream "    {\n")
 3574     (write _test-input-stream "      break a\n")
 3575     (write _test-input-stream "    }\n")
 3576     (write _test-input-stream "  }\n")
 3577     (write _test-input-stream "}\n")
 3578     # convert
 3579     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3580     (flush _test-output-buffered-file)
 3581 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3587     # check output
 3588     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/0")
 3589     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/1")
 3590     (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")
 3591     (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")
 3592     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/4")
 3593     (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")
 3594     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/6")
 3595     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/7")
 3596     (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")
 3597     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/9")
 3598     (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")
 3599     (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")
 3600     (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")
 3601     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/14")
 3602     (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")
 3603     (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")
 3604     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/17")
 3605     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/18")
 3606     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/19")
 3607     (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")
 3608     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/21")
 3609     (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")
 3610     (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")
 3611     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/24")
 3612     # . epilogue
 3613     89/<- %esp 5/r32/ebp
 3614     5d/pop-to-ebp
 3615     c3/return
 3616 
 3617 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4:
 3618     # . prologue
 3619     55/push-ebp
 3620     89/<- %ebp 4/r32/esp
 3621     # setup
 3622     (clear-stream _test-input-stream)
 3623     (clear-stream $_test-input-buffered-file->buffer)
 3624     (clear-stream _test-output-stream)
 3625     (clear-stream $_test-output-buffered-file->buffer)
 3626     #
 3627     (write _test-input-stream "fn foo {\n")
 3628     (write _test-input-stream "  a: {\n")
 3629     (write _test-input-stream "    var x/esi: int <- copy 0\n")
 3630     (write _test-input-stream "    {\n")
 3631     (write _test-input-stream "      break a\n")
 3632     (write _test-input-stream "    }\n")
 3633     (write _test-input-stream "  }\n")
 3634     (write _test-input-stream "}\n")
 3635     # convert
 3636     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3637     (flush _test-output-buffered-file)
 3638 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3644     # check output
 3645     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/0")
 3646     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/1")
 3647     (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")
 3648     (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")
 3649     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/4")
 3650     (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")
 3651     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/6")
 3652     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/7")
 3653     (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")
 3654     (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")
 3655     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/10")
 3656     (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")
 3657     (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")
 3658     (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")
 3659     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/14")
 3660     (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")
 3661     (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")
 3662     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/17")
 3663     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/18")
 3664     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/19")
 3665     (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")
 3666     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/21")
 3667     (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")
 3668     (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")
 3669     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/24")
 3670     # . epilogue
 3671     89/<- %esp 5/r32/ebp
 3672     5d/pop-to-ebp
 3673     c3/return
 3674 
 3675 test-convert-function-with-nonlocal-unconditional-break-and-local-vars:
 3676     # . prologue
 3677     55/push-ebp
 3678     89/<- %ebp 4/r32/esp
 3679     # setup
 3680     (clear-stream _test-input-stream)
 3681     (clear-stream $_test-input-buffered-file->buffer)
 3682     (clear-stream _test-output-stream)
 3683     (clear-stream $_test-output-buffered-file->buffer)
 3684     #
 3685     (write _test-input-stream "fn foo {\n")
 3686     (write _test-input-stream "  a: {\n")
 3687     (write _test-input-stream "    var x: int\n")
 3688     (write _test-input-stream "    {\n")
 3689     (write _test-input-stream "      var y: int\n")
 3690     (write _test-input-stream "      break a\n")
 3691     (write _test-input-stream "      increment x\n")
 3692     (write _test-input-stream "    }\n")
 3693     (write _test-input-stream "  }\n")
 3694     (write _test-input-stream "}\n")
 3695     # convert
 3696     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3697     (flush _test-output-buffered-file)
 3698 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3704     # check output
 3705     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/0")
 3706     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/1")
 3707     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/2")
 3708     (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")
 3709     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/4")
 3710     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/5")
 3711     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/6")
 3712     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/7")
 3713     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/8")
 3714     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/9")
 3715     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/10")
 3716     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/11")
 3717     (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")
 3718     (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")
 3719     (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")
 3720     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/15")
 3721     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/16")
 3722     (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")
 3723     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/18")
 3724     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/19")
 3725     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/20")
 3726     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/21")
 3727     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/22")
 3728     (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")
 3729     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/24")
 3730     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/25")
 3731     # . epilogue
 3732     89/<- %esp 5/r32/ebp
 3733     5d/pop-to-ebp
 3734     c3/return
 3735 
 3736 test-convert-function-with-unconditional-break-and-local-vars:
 3737     # . prologue
 3738     55/push-ebp
 3739     89/<- %ebp 4/r32/esp
 3740     # setup
 3741     (clear-stream _test-input-stream)
 3742     (clear-stream $_test-input-buffered-file->buffer)
 3743     (clear-stream _test-output-stream)
 3744     (clear-stream $_test-output-buffered-file->buffer)
 3745     #
 3746     (write _test-input-stream "fn foo {\n")
 3747     (write _test-input-stream "  {\n")
 3748     (write _test-input-stream "    var x: int\n")
 3749     (write _test-input-stream "    {\n")
 3750     (write _test-input-stream "      var y: int\n")
 3751     (write _test-input-stream "      break\n")
 3752     (write _test-input-stream "      increment x\n")
 3753     (write _test-input-stream "    }\n")
 3754     (write _test-input-stream "  }\n")
 3755     (write _test-input-stream "}\n")
 3756     # convert
 3757     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3758     (flush _test-output-buffered-file)
 3759 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3765     # check output
 3766     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-break-and-local-vars/0")
 3767     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-break-and-local-vars/1")
 3768     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-break-and-local-vars/2")
 3769     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-break-and-local-vars/3")
 3770     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-break-and-local-vars/4")
 3771     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/5")
 3772     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-break-and-local-vars/6")
 3773     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/7")
 3774     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-break-and-local-vars/8")
 3775     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-unconditional-break-and-local-vars/9")
 3776     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/10")
 3777     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/11")
 3778     (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")
 3779     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-unconditional-break-and-local-vars/13")
 3780     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/14")
 3781     (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")
 3782     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-break-and-local-vars/16")
 3783     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/17")
 3784     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-break-and-local-vars/18")
 3785     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/19")
 3786     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-break-and-local-vars/20")
 3787     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-break-and-local-vars/21")
 3788     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-break-and-local-vars/22")
 3789     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-break-and-local-vars/23")
 3790     # . epilogue
 3791     89/<- %esp 5/r32/ebp
 3792     5d/pop-to-ebp
 3793     c3/return
 3794 
 3795 test-convert-function-with-nonlocal-unconditional-loop-and-local-vars:
 3796     # . prologue
 3797     55/push-ebp
 3798     89/<- %ebp 4/r32/esp
 3799     # setup
 3800     (clear-stream _test-input-stream)
 3801     (clear-stream $_test-input-buffered-file->buffer)
 3802     (clear-stream _test-output-stream)
 3803     (clear-stream $_test-output-buffered-file->buffer)
 3804     #
 3805     (write _test-input-stream "fn foo {\n")
 3806     (write _test-input-stream "  a: {\n")
 3807     (write _test-input-stream "    var x: int\n")
 3808     (write _test-input-stream "    {\n")
 3809     (write _test-input-stream "      var y: int\n")
 3810     (write _test-input-stream "      loop a\n")
 3811     (write _test-input-stream "      increment x\n")
 3812     (write _test-input-stream "    }\n")
 3813     (write _test-input-stream "  }\n")
 3814     (write _test-input-stream "}\n")
 3815     # convert
 3816     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3817     (flush _test-output-buffered-file)
 3818 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3824     # check output
 3825     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/0")
 3826     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/1")
 3827     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/2")
 3828     (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")
 3829     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/4")
 3830     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/5")
 3831     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/6")
 3832     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/7")
 3833     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/8")
 3834     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/9")
 3835     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/10")
 3836     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/11")
 3837     (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")
 3838     (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")
 3839     (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")
 3840     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/15")
 3841     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/16")
 3842     (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")
 3843     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/18")
 3844     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/19")
 3845     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/20")
 3846     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/21")
 3847     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/22")
 3848     (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")
 3849     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/24")
 3850     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/25")
 3851     # . epilogue
 3852     89/<- %esp 5/r32/ebp
 3853     5d/pop-to-ebp
 3854     c3/return
 3855 
 3856 test-convert-function-with-local-array-var-in-mem:
 3857     # . prologue
 3858     55/push-ebp
 3859     89/<- %ebp 4/r32/esp
 3860     # setup
 3861     (clear-stream _test-input-stream)
 3862     (clear-stream $_test-input-buffered-file->buffer)
 3863     (clear-stream _test-output-stream)
 3864     (clear-stream $_test-output-buffered-file->buffer)
 3865     #
 3866     (write _test-input-stream "fn foo {\n")
 3867     (write _test-input-stream "  var x: (array int 3)\n")
 3868     (write _test-input-stream "}\n")
 3869     # convert
 3870     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3871     (flush _test-output-buffered-file)
 3872 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3878     # check output
 3879     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-var-in-mem/0")
 3880     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-var-in-mem/1")
 3881     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-var-in-mem/2")
 3882     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-array-var-in-mem/3")
 3883     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-var-in-mem/4")
 3884     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-var-in-mem/5")
 3885     # define x
 3886     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-function-with-local-array-var-in-mem/7")
 3887     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-function-with-local-array-var-in-mem/8")
 3888     # reclaim x
 3889     (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")
 3890     #
 3891     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-var-in-mem/10")
 3892     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-var-in-mem/11")
 3893     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-var-in-mem/12")
 3894     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-array-var-in-mem/13")
 3895     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-var-in-mem/14")
 3896     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-var-in-mem/15")
 3897     # . epilogue
 3898     89/<- %esp 5/r32/ebp
 3899     5d/pop-to-ebp
 3900     c3/return
 3901 
 3902 test-array-size-in-hex:
 3903     # . prologue
 3904     55/push-ebp
 3905     89/<- %ebp 4/r32/esp
 3906     # setup
 3907     (clear-stream _test-input-stream)
 3908     (clear-stream $_test-input-buffered-file->buffer)
 3909     (clear-stream _test-output-stream)
 3910     (clear-stream $_test-output-buffered-file->buffer)
 3911     (clear-stream _test-error-stream)
 3912     (clear-stream $_test-error-buffered-file->buffer)
 3913     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 3914     68/push 0/imm32
 3915     68/push 0/imm32
 3916     89/<- %edx 4/r32/esp
 3917     (tailor-exit-descriptor %edx 0x10)
 3918     #
 3919     (write _test-input-stream "fn foo {\n")
 3920     (write _test-input-stream "  var x: (array int 10)\n")
 3921     (write _test-input-stream "}\n")
 3922     # convert
 3923     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 3924     # registers except esp clobbered at this point
 3925     # restore ed
 3926     89/<- %edx 4/r32/esp
 3927     (flush _test-output-buffered-file)
 3928     (flush _test-error-buffered-file)
 3929 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 3935     # check output
 3936     (check-stream-equal _test-output-stream  ""  "F - test-array-size-in-hex: output should be empty")
 3937     (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")
 3938     # check that stop(1) was called
 3939     (check-ints-equal *(edx+4) 2 "F - test-array-size-in-hex: exit status")
 3940     # don't restore from ebp
 3941     81 0/subop/add %esp 8/imm32
 3942     # . epilogue
 3943     5d/pop-to-ebp
 3944     c3/return
 3945 
 3946 test-convert-function-with-populate:
 3947     # . prologue
 3948     55/push-ebp
 3949     89/<- %ebp 4/r32/esp
 3950     # setup
 3951     (clear-stream _test-input-stream)
 3952     (clear-stream $_test-input-buffered-file->buffer)
 3953     (clear-stream _test-output-stream)
 3954     (clear-stream $_test-output-buffered-file->buffer)
 3955     #
 3956     (write _test-input-stream "fn foo {\n")
 3957     (write _test-input-stream "  var x/ecx: (addr handle array int) <- copy 0\n")
 3958     (write _test-input-stream "  populate x, 7\n")
 3959     (write _test-input-stream "}\n")
 3960     # convert
 3961     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3962     (flush _test-output-buffered-file)
 3963 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3969     # check output
 3970     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-populate/0")
 3971     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-populate/1")
 3972     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-populate/2")
 3973     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-populate/3")
 3974     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-populate/4")
 3975     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-populate/5")
 3976     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-populate/6")
 3977     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-populate/7")
 3978     (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)
 3979     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-populate/9")
 3980     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-populate/10")
 3981     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-populate/11")
 3982     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-populate/12")
 3983     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-populate/13")
 3984     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-populate/14")
 3985     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-populate/15")
 3986     # . epilogue
 3987     89/<- %esp 5/r32/ebp
 3988     5d/pop-to-ebp
 3989     c3/return
 3990 
 3991 # special-case for size(byte) when allocating array
 3992 test-convert-function-with-local-array-of-bytes-in-mem:
 3993     # . prologue
 3994     55/push-ebp
 3995     89/<- %ebp 4/r32/esp
 3996     # setup
 3997     (clear-stream _test-input-stream)
 3998     (clear-stream $_test-input-buffered-file->buffer)
 3999     (clear-stream _test-output-stream)
 4000     (clear-stream $_test-output-buffered-file->buffer)
 4001     #
 4002     (write _test-input-stream "fn foo {\n")
 4003     (write _test-input-stream "  var x: (array byte 3)\n")
 4004     (write _test-input-stream "}\n")
 4005     # convert
 4006     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4007     (flush _test-output-buffered-file)
 4008 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4014     # check output
 4015     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-of-bytes-in-mem/0")
 4016     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/1")
 4017     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-of-bytes-in-mem/2")
 4018     (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")
 4019     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/4")
 4020     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-of-bytes-in-mem/5")
 4021     # define x
 4022     (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")
 4023     (check-next-stream-line-equal _test-output-stream "    68/push 0x00000003/imm32"  "F - test-convert-function-with-local-array-of-bytes-in-mem/8")
 4024     # reclaim x
 4025     (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")
 4026     #
 4027     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/10")
 4028     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-of-bytes-in-mem/11")
 4029     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/12")
 4030     (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")
 4031     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-of-bytes-in-mem/14")
 4032     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-of-bytes-in-mem/15")
 4033     # . epilogue
 4034     89/<- %esp 5/r32/ebp
 4035     5d/pop-to-ebp
 4036     c3/return
 4037 
 4038 test-convert-address:
 4039     # . prologue
 4040     55/push-ebp
 4041     89/<- %ebp 4/r32/esp
 4042     # setup
 4043     (clear-stream _test-input-stream)
 4044     (clear-stream $_test-input-buffered-file->buffer)
 4045     (clear-stream _test-output-stream)
 4046     (clear-stream $_test-output-buffered-file->buffer)
 4047     #
 4048     (write _test-input-stream "fn foo {\n")
 4049     (write _test-input-stream "  var a: int\n")
 4050     (write _test-input-stream "  var b/eax: (addr int) <- address a\n")
 4051     (write _test-input-stream "}\n")
 4052     # convert
 4053     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4054     (flush _test-output-buffered-file)
 4055 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4061     # check output
 4062     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-address/0")
 4063     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-address/1")
 4064     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-address/2")
 4065     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-address/3")
 4066     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-address/4")
 4067     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-address/5")
 4068     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-address/6")
 4069     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-address/7")
 4070     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000000/r32"  "F - test-convert-address/8")
 4071     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-address/9")
 4072     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-address/10")
 4073     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-address/11")
 4074     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-address/12")
 4075     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-address/13")
 4076     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-address/14")
 4077     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-address/15")
 4078     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-address/16")
 4079     # . epilogue
 4080     89/<- %esp 5/r32/ebp
 4081     5d/pop-to-ebp
 4082     c3/return
 4083 
 4084 test-convert-length-of-array:
 4085     # . prologue
 4086     55/push-ebp
 4087     89/<- %ebp 4/r32/esp
 4088     # setup
 4089     (clear-stream _test-input-stream)
 4090     (clear-stream $_test-input-buffered-file->buffer)
 4091     (clear-stream _test-output-stream)
 4092     (clear-stream $_test-output-buffered-file->buffer)
 4093     #
 4094     (write _test-input-stream "fn foo a: (addr array int) {\n")
 4095     (write _test-input-stream "  var b/eax: (addr array int) <- copy a\n")
 4096     (write _test-input-stream "  var c/eax: int <- length b\n")
 4097     (write _test-input-stream "}\n")
 4098     # convert
 4099     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4100     (flush _test-output-buffered-file)
 4101 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4107     # check output
 4108     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array/0")
 4109     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array/1")
 4110     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array/2")
 4111     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array/3")
 4112     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array/4")
 4113     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array/5")
 4114     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array/6")
 4115     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array/7")
 4116     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array/8")
 4117     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array/9")
 4118     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array/10")
 4119     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array/11")
 4120     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array/12")
 4121     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array/13")
 4122     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array/14")
 4123     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array/15")
 4124     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array/16")
 4125     # . epilogue
 4126     89/<- %esp 5/r32/ebp
 4127     5d/pop-to-ebp
 4128     c3/return
 4129 
 4130 # special-case for size(byte) when computing array length
 4131 test-convert-length-of-array-of-bytes:
 4132     # . prologue
 4133     55/push-ebp
 4134     89/<- %ebp 4/r32/esp
 4135     # setup
 4136     (clear-stream _test-input-stream)
 4137     (clear-stream $_test-input-buffered-file->buffer)
 4138     (clear-stream _test-output-stream)
 4139     (clear-stream $_test-output-buffered-file->buffer)
 4140     #
 4141     (write _test-input-stream "fn foo a: (addr array byte) {\n")
 4142     (write _test-input-stream "  var b/eax: (addr array byte) <- copy a\n")
 4143     (write _test-input-stream "  var c/eax: int <- length b\n")
 4144     (write _test-input-stream "}\n")
 4145     # convert
 4146     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4147     (flush _test-output-buffered-file)
 4148 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4154     # check output
 4155     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-bytes/0")
 4156     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-bytes/1")
 4157     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-bytes/2")
 4158     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-bytes/3")
 4159     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-bytes/4")
 4160     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-bytes/5")
 4161     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-bytes/6")
 4162     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/7")
 4163     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/8")
 4164     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-bytes/9")
 4165     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-bytes/10")
 4166     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-bytes/11")
 4167     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-bytes/12")
 4168     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-bytes/13")
 4169     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-bytes/14")
 4170     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-bytes/15")
 4171     # . epilogue
 4172     89/<- %esp 5/r32/ebp
 4173     5d/pop-to-ebp
 4174     c3/return
 4175 
 4176 test-convert-length-of-array-on-stack:
 4177     # . prologue
 4178     55/push-ebp
 4179     89/<- %ebp 4/r32/esp
 4180     # setup
 4181     (clear-stream _test-input-stream)
 4182     (clear-stream $_test-input-buffered-file->buffer)
 4183     (clear-stream _test-output-stream)
 4184     (clear-stream $_test-output-buffered-file->buffer)
 4185     #
 4186     (write _test-input-stream "fn foo {\n")
 4187     (write _test-input-stream "  var a: (array int 3)\n")
 4188     (write _test-input-stream "  var b/eax: int <- length a\n")
 4189     (write _test-input-stream "}\n")
 4190     # convert
 4191     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4192     (flush _test-output-buffered-file)
 4193 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4199     # check output
 4200     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-on-stack/0")
 4201     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-on-stack/1")
 4202     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-on-stack/2")
 4203     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-on-stack/3")
 4204     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-on-stack/4")
 4205     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-on-stack/5")
 4206     # define x
 4207     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-length-of-array-on-stack/6")
 4208     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-length-of-array-on-stack/7")
 4209     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-on-stack/8")
 4210     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0xfffffff0) 0x00000000/r32"  "F - test-convert-length-of-array-on-stack/9")
 4211     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array-on-stack/10")
 4212     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-on-stack/11")
 4213     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"  "F - test-convert-length-of-array-on-stack/12")
 4214     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-on-stack/13")
 4215     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-on-stack/14")
 4216     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-on-stack/15")
 4217     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-on-stack/16")
 4218     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-on-stack/17")
 4219     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-on-stack/18")
 4220     # . epilogue
 4221     89/<- %esp 5/r32/ebp
 4222     5d/pop-to-ebp
 4223     c3/return
 4224 
 4225 test-reg-var-def-with-read-of-same-register:
 4226     # . prologue
 4227     55/push-ebp
 4228     89/<- %ebp 4/r32/esp
 4229     # setup
 4230     (clear-stream _test-input-stream)
 4231     (clear-stream $_test-input-buffered-file->buffer)
 4232     (clear-stream _test-output-stream)
 4233     (clear-stream $_test-output-buffered-file->buffer)
 4234     (clear-stream _test-error-stream)
 4235     (clear-stream $_test-error-buffered-file->buffer)
 4236     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
 4237     68/push 0/imm32
 4238     68/push 0/imm32
 4239     89/<- %edx 4/r32/esp
 4240     (tailor-exit-descriptor %edx 0x10)
 4241     #
 4242     (write _test-input-stream "fn foo {\n")
 4243     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4244     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4245     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4246     (write _test-input-stream "}\n")
 4247     # convert
 4248     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4249     # registers except esp could be clobbered at this point (though they shouldn't be)
 4250     # restore ed
 4251     89/<- %edx 4/r32/esp
 4252     (flush _test-output-buffered-file)
 4253     (flush _test-error-buffered-file)
 4254 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4260     (check-stream-equal _test-error-stream  ""  "F - test-reg-var-def-with-read-of-same-register: error stream should be empty")
 4261     # check output
 4262     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-reg-var-def-with-read-of-same-register/0")
 4263     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-reg-var-def-with-read-of-same-register/1")
 4264     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-reg-var-def-with-read-of-same-register/2")
 4265     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-reg-var-def-with-read-of-same-register/3")
 4266     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-reg-var-def-with-read-of-same-register/4")
 4267     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-reg-var-def-with-read-of-same-register/5")
 4268     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-reg-var-def-with-read-of-same-register/6")
 4269     (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")
 4270     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-reg-var-def-with-read-of-same-register/8")
 4271     (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")
 4272     (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")
 4273     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-reg-var-def-with-read-of-same-register/13")
 4274     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-reg-var-def-with-read-of-same-register/14")
 4275     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-reg-var-def-with-read-of-same-register/15")
 4276     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-reg-var-def-with-read-of-same-register/16")
 4277     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-reg-var-def-with-read-of-same-register/17")
 4278     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-reg-var-def-with-read-of-same-register/18")
 4279     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-reg-var-def-with-read-of-same-register/19")
 4280     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-reg-var-def-with-read-of-same-register/20")
 4281     # don't restore from ebp
 4282     81 0/subop/add %esp 8/imm32
 4283     # . epilogue
 4284     5d/pop-to-ebp
 4285     c3/return
 4286 
 4287 test-convert-index-into-array:
 4288     # . prologue
 4289     55/push-ebp
 4290     89/<- %ebp 4/r32/esp
 4291     # setup
 4292     (clear-stream _test-input-stream)
 4293     (clear-stream $_test-input-buffered-file->buffer)
 4294     (clear-stream _test-output-stream)
 4295     (clear-stream $_test-output-buffered-file->buffer)
 4296     #
 4297     (write _test-input-stream "fn foo {\n")
 4298     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4299     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4300     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4301     (write _test-input-stream "}\n")
 4302     # convert
 4303     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4304     (flush _test-output-buffered-file)
 4305 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4311     # check output
 4312     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array/0")
 4313     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array/1")
 4314     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array/2")
 4315     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array/3")
 4316     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array/4")
 4317     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array/5")
 4318     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array/6")
 4319     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array/7")
 4320     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array/8")
 4321     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array/9")
 4322     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32"  "F - test-convert-index-into-array/10")
 4323     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array/11")
 4324     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array/12")
 4325     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array/13")
 4326     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array/14")
 4327     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array/15")
 4328     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array/16")
 4329     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array/17")
 4330     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array/18")
 4331     # . epilogue
 4332     89/<- %esp 5/r32/ebp
 4333     5d/pop-to-ebp
 4334     c3/return
 4335 
 4336 test-convert-index-into-array-of-bytes:
 4337     # . prologue
 4338     55/push-ebp
 4339     89/<- %ebp 4/r32/esp
 4340     # setup
 4341     (clear-stream _test-input-stream)
 4342     (clear-stream $_test-input-buffered-file->buffer)
 4343     (clear-stream _test-output-stream)
 4344     (clear-stream $_test-output-buffered-file->buffer)
 4345     #
 4346     (write _test-input-stream "fn foo {\n")
 4347     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4348     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4349     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, idx\n")
 4350     (write _test-input-stream "}\n")
 4351     # convert
 4352     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4353     (flush _test-output-buffered-file)
 4354 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4360     # check output
 4361     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes/0")
 4362     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes/1")
 4363     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes/2")
 4364     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes/3")
 4365     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes/4")
 4366     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes/5")
 4367     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes/6")
 4368     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes/7")
 4369     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes/8")
 4370     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-of-bytes/9")
 4371     (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")
 4372     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes/13")
 4373     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes/14")
 4374     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes/15")
 4375     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes/16")
 4376     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes/17")
 4377     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes/18")
 4378     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes/19")
 4379     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes/20")
 4380     # . epilogue
 4381     89/<- %esp 5/r32/ebp
 4382     5d/pop-to-ebp
 4383     c3/return
 4384 
 4385 test-convert-index-into-array-with-literal:
 4386     # . prologue
 4387     55/push-ebp
 4388     89/<- %ebp 4/r32/esp
 4389     # setup
 4390     (clear-stream _test-input-stream)
 4391     (clear-stream $_test-input-buffered-file->buffer)
 4392     (clear-stream _test-output-stream)
 4393     (clear-stream $_test-output-buffered-file->buffer)
 4394     #
 4395     (write _test-input-stream "fn foo {\n")
 4396     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4397     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\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-with-literal/0")
 4410     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-with-literal/1")
 4411     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-with-literal/2")
 4412     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-with-literal/3")
 4413     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-with-literal/4")
 4414     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-with-literal/5")
 4415     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-with-literal/6")
 4416     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-with-literal/7")
 4417                                                                                  # 2 * 4 bytes/elem + 4 bytes for size = offset 12
 4418     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x0000000c) 0x00000000/r32"  "F - test-convert-index-into-array-with-literal/8")
 4419     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-with-literal/9")
 4420     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-with-literal/10")
 4421     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-with-literal/11")
 4422     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-with-literal/12")
 4423     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-with-literal/13")
 4424     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-with-literal/14")
 4425     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-with-literal/15")
 4426     # . epilogue
 4427     89/<- %esp 5/r32/ebp
 4428     5d/pop-to-ebp
 4429     c3/return
 4430 
 4431 test-convert-index-into-array-of-bytes-with-literal:
 4432     # . prologue
 4433     55/push-ebp
 4434     89/<- %ebp 4/r32/esp
 4435     # setup
 4436     (clear-stream _test-input-stream)
 4437     (clear-stream $_test-input-buffered-file->buffer)
 4438     (clear-stream _test-output-stream)
 4439     (clear-stream $_test-output-buffered-file->buffer)
 4440     #
 4441     (write _test-input-stream "fn foo {\n")
 4442     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4443     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 4444     (write _test-input-stream "}\n")
 4445     # convert
 4446     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4447     (flush _test-output-buffered-file)
 4448 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4454     # check output
 4455     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-with-literal/0")
 4456     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-with-literal/1")
 4457     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-with-literal/2")
 4458     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-with-literal/3")
 4459     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-with-literal/4")
 4460     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-with-literal/5")
 4461     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-with-literal/6")
 4462     (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")
 4463                                                                                  # 2 * 1 byte/elem + 4 bytes for size = offset 6
 4464     (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")
 4465     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-with-literal/9")
 4466     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-with-literal/10")
 4467     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-with-literal/11")
 4468     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-with-literal/12")
 4469     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-with-literal/13")
 4470     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-with-literal/14")
 4471     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-with-literal/15")
 4472     # . epilogue
 4473     89/<- %esp 5/r32/ebp
 4474     5d/pop-to-ebp
 4475     c3/return
 4476 
 4477 test-convert-index-into-array-on-stack:
 4478     # . prologue
 4479     55/push-ebp
 4480     89/<- %ebp 4/r32/esp
 4481     # setup
 4482     (clear-stream _test-input-stream)
 4483     (clear-stream $_test-input-buffered-file->buffer)
 4484     (clear-stream _test-output-stream)
 4485     (clear-stream $_test-output-buffered-file->buffer)
 4486     #
 4487     (write _test-input-stream "fn foo {\n")
 4488     (write _test-input-stream "  var arr: (array int 3)\n")
 4489     (write _test-input-stream "  var idx/eax: int <- copy 2\n")
 4490     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4491     (write _test-input-stream "}\n")
 4492     # convert
 4493     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4494     (flush _test-output-buffered-file)
 4495 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4501     # check output
 4502     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack/0")
 4503     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack/1")
 4504     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack/2")
 4505     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack/3")
 4506     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack/4")
 4507     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack/5")
 4508     # var arr
 4509     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack/6")
 4510     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack/7")
 4511     # var idx
 4512     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack/8")
 4513     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 2/imm32"                  "F - test-convert-index-into-array-on-stack/9")
 4514     # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc
 4515     (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")
 4516     # reclaim idx
 4517     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack/11")
 4518     # reclaim arr
 4519     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"    "F - test-convert-index-into-array-on-stack/12")
 4520     #
 4521     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack/13")
 4522     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack/14")
 4523     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack/15")
 4524     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack/16")
 4525     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack/17")
 4526     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack/18")
 4527     # . epilogue
 4528     89/<- %esp 5/r32/ebp
 4529     5d/pop-to-ebp
 4530     c3/return
 4531 
 4532 test-convert-index-into-array-on-stack-with-literal:
 4533     # . prologue
 4534     55/push-ebp
 4535     89/<- %ebp 4/r32/esp
 4536     # setup
 4537     (clear-stream _test-input-stream)
 4538     (clear-stream $_test-input-buffered-file->buffer)
 4539     (clear-stream _test-output-stream)
 4540     (clear-stream $_test-output-buffered-file->buffer)
 4541     #
 4542     (write _test-input-stream "fn foo {\n")
 4543     (write _test-input-stream "  var arr: (array int 3)\n")
 4544     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 4545     (write _test-input-stream "}\n")
 4546     # convert
 4547     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4548     (flush _test-output-buffered-file)
 4549 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4555     # check output
 4556     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack-with-literal/0")
 4557     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack-with-literal/1")
 4558     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack-with-literal/2")
 4559     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack-with-literal/3")
 4560     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack-with-literal/4")
 4561     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack-with-literal/5")
 4562     # var arr
 4563     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack-with-literal/6")
 4564     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack-with-literal/7")
 4565     # var x
 4566     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack-with-literal/8")
 4567     # x is at (ebp-0x10) + 4 + 2*4 = ebp-4
 4568     (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")
 4569     # reclaim x
 4570     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack-with-literal/10")
 4571     # reclaim arr
 4572     (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")
 4573     #
 4574     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack-with-literal/12")
 4575     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack-with-literal/13")
 4576     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack-with-literal/14")
 4577     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack-with-literal/15")
 4578     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack-with-literal/16")
 4579     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack-with-literal/17")
 4580     # . epilogue
 4581     89/<- %esp 5/r32/ebp
 4582     5d/pop-to-ebp
 4583     c3/return
 4584 
 4585 test-convert-index-into-array-of-bytes-on-stack-with-literal:
 4586     # . prologue
 4587     55/push-ebp
 4588     89/<- %ebp 4/r32/esp
 4589     # setup
 4590     (clear-stream _test-input-stream)
 4591     (clear-stream $_test-input-buffered-file->buffer)
 4592     (clear-stream _test-output-stream)
 4593     (clear-stream $_test-output-buffered-file->buffer)
 4594     #
 4595     (write _test-input-stream "fn foo {\n")
 4596     (write _test-input-stream "  var arr: (array byte 3)\n")
 4597     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 4598     (write _test-input-stream "}\n")
 4599     # convert
 4600     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4601     (flush _test-output-buffered-file)
 4602 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4608     # check output
 4609     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/0")
 4610     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/1")
 4611     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/2")
 4612     (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")
 4613     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/4")
 4614     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/5")
 4615     # var arr
 4616     (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")
 4617     (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")
 4618     # var x
 4619     (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")
 4620     # x is at (ebp-7) + 4 + 2 = ebp-1
 4621     (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")
 4622     # reclaim x
 4623     (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")
 4624     # reclaim arr
 4625     (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")
 4626     #
 4627     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/12")
 4628     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/13")
 4629     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/14")
 4630     (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")
 4631     (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")
 4632     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/17")
 4633     # . epilogue
 4634     89/<- %esp 5/r32/ebp
 4635     5d/pop-to-ebp
 4636     c3/return
 4637 
 4638 test-convert-index-into-array-using-offset:
 4639     # . prologue
 4640     55/push-ebp
 4641     89/<- %ebp 4/r32/esp
 4642     # setup
 4643     (clear-stream _test-input-stream)
 4644     (clear-stream $_test-input-buffered-file->buffer)
 4645     (clear-stream _test-output-stream)
 4646     (clear-stream $_test-output-buffered-file->buffer)
 4647     #
 4648     (write _test-input-stream "fn foo {\n")
 4649     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4650     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4651     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 4652     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 4653     (write _test-input-stream "}\n")
 4654     # convert
 4655     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4656     (flush _test-output-buffered-file)
 4657 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4663     # check output
 4664     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset/0")
 4665     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset/1")
 4666     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset/2")
 4667     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset/3")
 4668     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset/4")
 4669     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset/5")
 4670     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset/6")
 4671     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-using-offset/7")
 4672     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset/8")
 4673     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-using-offset/9")
 4674     (check-next-stream-line-equal _test-output-stream "    69/multiply %ecx 0x00000004/imm32 0x00000001/r32"  "F - test-convert-index-into-array-using-offset/10")
 4675     (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")
 4676     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset/12")
 4677     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset/13")
 4678     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset/14")
 4679     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset/15")
 4680     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset/16")
 4681     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset/17")
 4682     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset/18")
 4683     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset/19")
 4684     # . epilogue
 4685     89/<- %esp 5/r32/ebp
 4686     5d/pop-to-ebp
 4687     c3/return
 4688 
 4689 test-convert-index-into-array-of-bytes-using-offset:
 4690     # . prologue
 4691     55/push-ebp
 4692     89/<- %ebp 4/r32/esp
 4693     # setup
 4694     (clear-stream _test-input-stream)
 4695     (clear-stream $_test-input-buffered-file->buffer)
 4696     (clear-stream _test-output-stream)
 4697     (clear-stream $_test-output-buffered-file->buffer)
 4698     #
 4699     (write _test-input-stream "fn foo {\n")
 4700     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4701     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4702     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 4703     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
 4704     (write _test-input-stream "}\n")
 4705     # convert
 4706     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4707     (flush _test-output-buffered-file)
 4708 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4714     # check output
 4715     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset/0")
 4716     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset/1")
 4717     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset/2")
 4718     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-using-offset/3")
 4719     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset/4")
 4720     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset/5")
 4721     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-using-offset/6")
 4722     (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")
 4723     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes-using-offset/8")
 4724     (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")
 4725     (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")
 4726     (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")
 4727     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes-using-offset/12")
 4728     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-using-offset/13")
 4729     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset/14")
 4730     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset/15")
 4731     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset/16")
 4732     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-using-offset/17")
 4733     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-using-offset/18")
 4734     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset/19")
 4735     # . epilogue
 4736     89/<- %esp 5/r32/ebp
 4737     5d/pop-to-ebp
 4738     c3/return
 4739 
 4740 test-convert-index-into-array-using-offset-on-stack:
 4741     # . prologue
 4742     55/push-ebp
 4743     89/<- %ebp 4/r32/esp
 4744     # setup
 4745     (clear-stream _test-input-stream)
 4746     (clear-stream $_test-input-buffered-file->buffer)
 4747     (clear-stream _test-output-stream)
 4748     (clear-stream $_test-output-buffered-file->buffer)
 4749     #
 4750     (write _test-input-stream "fn foo {\n")
 4751     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4752     (write _test-input-stream "  var idx: int\n")
 4753     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 4754     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 4755     (write _test-input-stream "}\n")
 4756     # convert
 4757     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4758     (flush _test-output-buffered-file)
 4759 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4765     # check output
 4766     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset-on-stack/0")
 4767     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset-on-stack/1")
 4768     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset-on-stack/2")
 4769     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset-on-stack/3")
 4770     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset-on-stack/4")
 4771     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset-on-stack/5")
 4772     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset-on-stack/6")
 4773     (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")
 4774     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                         "F - test-convert-index-into-array-using-offset-on-stack/8")
 4775     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset-on-stack/9")
 4776     (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")
 4777     (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")
 4778     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset-on-stack/12")
 4779     (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")
 4780     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset-on-stack/14")
 4781     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset-on-stack/15")
 4782     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset-on-stack/16")
 4783     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset-on-stack/17")
 4784     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset-on-stack/18")
 4785     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset-on-stack/19")
 4786     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset-on-stack/20")
 4787     # . epilogue
 4788     89/<- %esp 5/r32/ebp
 4789     5d/pop-to-ebp
 4790     c3/return
 4791 
 4792 test-convert-index-into-array-of-bytes-using-offset-on-stack:
 4793     # . prologue
 4794     55/push-ebp
 4795     89/<- %ebp 4/r32/esp
 4796     # setup
 4797     (clear-stream _test-input-stream)
 4798     (clear-stream $_test-input-buffered-file->buffer)
 4799     (clear-stream _test-output-stream)
 4800     (clear-stream $_test-output-buffered-file->buffer)
 4801     #
 4802     (write _test-input-stream "fn foo {\n")
 4803     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4804     (write _test-input-stream "  var idx: int\n")
 4805     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 4806     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
 4807     (write _test-input-stream "}\n")
 4808     # convert
 4809     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4810     (flush _test-output-buffered-file)
 4811 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4817     # check output
 4818     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/0")
 4819     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/1")
 4820     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/2")
 4821     (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")
 4822     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/4")
 4823     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/5")
 4824     (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")
 4825     (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")
 4826     (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")
 4827     (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")
 4828     (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")
 4829     (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")
 4830     (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")
 4831     (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")
 4832     (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")
 4833     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/15")
 4834     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/16")
 4835     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/17")
 4836     (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")
 4837     (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")
 4838     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/20")
 4839     # . epilogue
 4840     89/<- %esp 5/r32/ebp
 4841     5d/pop-to-ebp
 4842     c3/return
 4843 
 4844 test-convert-function-and-type-definition:
 4845     # . prologue
 4846     55/push-ebp
 4847     89/<- %ebp 4/r32/esp
 4848     # setup
 4849     (clear-stream _test-input-stream)
 4850     (clear-stream $_test-input-buffered-file->buffer)
 4851     (clear-stream _test-output-stream)
 4852     (clear-stream $_test-output-buffered-file->buffer)
 4853     #
 4854     (write _test-input-stream "fn foo a: (addr t) {\n")
 4855     (write _test-input-stream "  var _a/eax: (addr t) <- copy a\n")
 4856     (write _test-input-stream "  var b/ecx: (addr int) <- get _a, x\n")
 4857     (write _test-input-stream "  var c/ecx: (addr int) <- get _a, y\n")
 4858     (write _test-input-stream "}\n")
 4859     (write _test-input-stream "type t {\n")
 4860     (write _test-input-stream "  x: int\n")
 4861     (write _test-input-stream "  y: int\n")
 4862     (write _test-input-stream "}\n")
 4863     # convert
 4864     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4865     (flush _test-output-buffered-file)
 4866 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4872     # check output
 4873     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-and-type-definition/0")
 4874     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-and-type-definition/1")
 4875     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-and-type-definition/2")
 4876     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-and-type-definition/3")
 4877     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-and-type-definition/4")
 4878     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-and-type-definition/5")
 4879     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-and-type-definition/6")
 4880     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-and-type-definition/7")
 4881     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-and-type-definition/8")
 4882     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000000) 0x00000001/r32"  "F - test-convert-function-and-type-definition/9")
 4883     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000004) 0x00000001/r32"  "F - test-convert-function-and-type-definition/11")
 4884     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-and-type-definition/13")
 4885     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-and-type-definition/14")
 4886     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-and-type-definition/15")
 4887     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-and-type-definition/16")
 4888     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-and-type-definition/17")
 4889     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-and-type-definition/18")
 4890     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-and-type-definition/19")
 4891     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-and-type-definition/20")
 4892     # . epilogue
 4893     89/<- %esp 5/r32/ebp
 4894     5d/pop-to-ebp
 4895     c3/return
 4896 
 4897 test-type-definition-with-array:
 4898     # . prologue
 4899     55/push-ebp
 4900     89/<- %ebp 4/r32/esp
 4901     # setup
 4902     (clear-stream _test-input-stream)
 4903     (clear-stream $_test-input-buffered-file->buffer)
 4904     (clear-stream _test-output-stream)
 4905     (clear-stream $_test-output-buffered-file->buffer)
 4906     (clear-stream _test-error-stream)
 4907     (clear-stream $_test-error-buffered-file->buffer)
 4908     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 4909     68/push 0/imm32
 4910     68/push 0/imm32
 4911     89/<- %edx 4/r32/esp
 4912     (tailor-exit-descriptor %edx 0x10)
 4913     #
 4914     (write _test-input-stream "type t {\n")
 4915     (write _test-input-stream "  a: (array int 3)\n")
 4916     (write _test-input-stream "}\n")
 4917     # convert
 4918     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4919     # registers except esp clobbered at this point
 4920     # restore ed
 4921     89/<- %edx 4/r32/esp
 4922     (flush _test-output-buffered-file)
 4923     (flush _test-error-buffered-file)
 4924 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 4930     # check output
 4931     (check-stream-equal _test-output-stream  ""  "F - test-type-definition-with-array: output should be empty")
 4932     (check-next-stream-line-equal _test-error-stream  "type t: invalid type 'array'"  "F - test-type-definition-with-array: error message")
 4933     # check that stop(1) was called
 4934     (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-array: exit status")
 4935     # don't restore from ebp
 4936     81 0/subop/add %esp 8/imm32
 4937     # . epilogue
 4938     5d/pop-to-ebp
 4939     c3/return
 4940 
 4941 test-type-definition-with-addr:
 4942     # . prologue
 4943     55/push-ebp
 4944     89/<- %ebp 4/r32/esp
 4945     # setup
 4946     (clear-stream _test-input-stream)
 4947     (clear-stream $_test-input-buffered-file->buffer)
 4948     (clear-stream _test-output-stream)
 4949     (clear-stream $_test-output-buffered-file->buffer)
 4950     (clear-stream _test-error-stream)
 4951     (clear-stream $_test-error-buffered-file->buffer)
 4952     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 4953     68/push 0/imm32
 4954     68/push 0/imm32
 4955     89/<- %edx 4/r32/esp
 4956     (tailor-exit-descriptor %edx 0x10)
 4957     #
 4958     (write _test-input-stream "type t {\n")
 4959     (write _test-input-stream "  a: (addr int)\n")
 4960     (write _test-input-stream "}\n")
 4961     # convert
 4962     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4963     # registers except esp clobbered at this point
 4964     # restore ed
 4965     89/<- %edx 4/r32/esp
 4966     (flush _test-output-buffered-file)
 4967     (flush _test-error-buffered-file)
 4968 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 4974     # check output
 4975     (check-stream-equal _test-output-stream  ""  "F - test-type-definition-with-addr: output should be empty")
 4976     (check-next-stream-line-equal _test-error-stream  "type t: invalid type 'addr'"  "F - test-type-definition-with-addr: error message")
 4977     # check that stop(1) was called
 4978     (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-addr: exit status")
 4979     # don't restore from ebp
 4980     81 0/subop/add %esp 8/imm32
 4981     # . epilogue
 4982     5d/pop-to-ebp
 4983     c3/return
 4984 
 4985 test-convert-function-with-local-var-with-user-defined-type:
 4986     # . prologue
 4987     55/push-ebp
 4988     89/<- %ebp 4/r32/esp
 4989     # setup
 4990     (clear-stream _test-input-stream)
 4991     (clear-stream $_test-input-buffered-file->buffer)
 4992     (clear-stream _test-output-stream)
 4993     (clear-stream $_test-output-buffered-file->buffer)
 4994     #
 4995     (write _test-input-stream "fn foo {\n")
 4996     (write _test-input-stream "  var a: t\n")
 4997     (write _test-input-stream "}\n")
 4998     (write _test-input-stream "type t {\n")
 4999     (write _test-input-stream "  x: int\n")
 5000     (write _test-input-stream "  y: int\n")
 5001     (write _test-input-stream "}\n")
 5002     # convert
 5003     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5004     (flush _test-output-buffered-file)
 5005 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5011     # check output
 5012     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-user-defined-type/0")
 5013     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-user-defined-type/1")
 5014     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-user-defined-type/2")
 5015     (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")
 5016     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type/4")
 5017     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-user-defined-type/5")
 5018     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/6")
 5019     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/7")
 5020     (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")
 5021     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type/9")
 5022     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-user-defined-type/10")
 5023     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-user-defined-type/11")
 5024     (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")
 5025     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-user-defined-type/13")
 5026     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-user-defined-type/14")
 5027     # . epilogue
 5028     89/<- %esp 5/r32/ebp
 5029     5d/pop-to-ebp
 5030     c3/return
 5031 
 5032 test-convert-function-call-with-arg-of-user-defined-type:
 5033     # . prologue
 5034     55/push-ebp
 5035     89/<- %ebp 4/r32/esp
 5036     # setup
 5037     (clear-stream _test-input-stream)
 5038     (clear-stream $_test-input-buffered-file->buffer)
 5039     (clear-stream _test-output-stream)
 5040     (clear-stream $_test-output-buffered-file->buffer)
 5041     #
 5042     (write _test-input-stream "fn f {\n")
 5043     (write _test-input-stream "  var a: t\n")
 5044     (write _test-input-stream "  foo a\n")
 5045     (write _test-input-stream "}\n")
 5046     (write _test-input-stream "fn foo x: t {\n")
 5047     (write _test-input-stream "}\n")
 5048     (write _test-input-stream "type t {\n")
 5049     (write _test-input-stream "  x: int\n")
 5050     (write _test-input-stream "  y: int\n")
 5051     (write _test-input-stream "}\n")
 5052     # convert
 5053     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5054     (flush _test-output-buffered-file)
 5055 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5061     # check output
 5062     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 5063     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 5064     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 5065     (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")
 5066     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 5067     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 5068     # var a: t
 5069     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/6")
 5070     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/7")
 5071     # foo a
 5072     (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")
 5073     #
 5074     (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")
 5075     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 5076     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 5077     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 5078     (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")
 5079     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 5080     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 5081     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 5082     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 5083     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 5084     (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")
 5085     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 5086     (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")
 5087     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 5088     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 5089     # . epilogue
 5090     89/<- %esp 5/r32/ebp
 5091     5d/pop-to-ebp
 5092     c3/return
 5093 
 5094 test-convert-function-call-with-arg-of-user-defined-type-register-indirect:
 5095     # . prologue
 5096     55/push-ebp
 5097     89/<- %ebp 4/r32/esp
 5098     # setup
 5099     (clear-stream _test-input-stream)
 5100     (clear-stream $_test-input-buffered-file->buffer)
 5101     (clear-stream _test-output-stream)
 5102     (clear-stream $_test-output-buffered-file->buffer)
 5103     #
 5104     (write _test-input-stream "fn f {\n")
 5105     (write _test-input-stream "  var a/eax: (addr t) <- copy 0\n")
 5106     (write _test-input-stream "  foo *a\n")
 5107     (write _test-input-stream "}\n")
 5108     (write _test-input-stream "fn foo x: t {\n")
 5109     (write _test-input-stream "}\n")
 5110     (write _test-input-stream "type t {\n")
 5111     (write _test-input-stream "  x: int\n")
 5112     (write _test-input-stream "  y: int\n")
 5113     (write _test-input-stream "}\n")
 5114     # convert
 5115     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5116     (flush _test-output-buffered-file)
 5117 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5123     # check output
 5124     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 5125     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 5126     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 5127     (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")
 5128     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 5129     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 5130     # var a
 5131     (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")
 5132     (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")
 5133     # foo a
 5134     (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")
 5135     #
 5136     (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")
 5137     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 5138     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 5139     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 5140     (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")
 5141     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 5142     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 5143     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 5144     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 5145     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 5146     (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")
 5147     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 5148     (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")
 5149     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 5150     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 5151     # . epilogue
 5152     89/<- %esp 5/r32/ebp
 5153     5d/pop-to-ebp
 5154     c3/return
 5155 
 5156 # we don't have special support for call-by-reference; just explicitly create
 5157 # a new variable with the address of the arg
 5158 test-convert-function-call-with-arg-of-user-defined-type-by-reference:
 5159     # . prologue
 5160     55/push-ebp
 5161     89/<- %ebp 4/r32/esp
 5162     # setup
 5163     (clear-stream _test-input-stream)
 5164     (clear-stream $_test-input-buffered-file->buffer)
 5165     (clear-stream _test-output-stream)
 5166     (clear-stream $_test-output-buffered-file->buffer)
 5167     #
 5168     (write _test-input-stream "fn f {\n")
 5169     (write _test-input-stream "  var a: t\n")
 5170     (write _test-input-stream "  var b/eax: (addr t) <- address a\n")
 5171     (write _test-input-stream "  foo b\n")
 5172     (write _test-input-stream "}\n")
 5173     (write _test-input-stream "fn foo x: (addr t) {\n")
 5174     (write _test-input-stream "  var x/ecx: (addr int) <- copy x\n")
 5175     (write _test-input-stream "  increment *x\n")
 5176     (write _test-input-stream "}\n")
 5177     (write _test-input-stream "type t {\n")
 5178     (write _test-input-stream "  x: int\n")
 5179     (write _test-input-stream "  y: int\n")
 5180     (write _test-input-stream "}\n")
 5181     # convert
 5182     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5183     (flush _test-output-buffered-file)
 5184 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5190     # check output
 5191     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/0")
 5192     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/1")
 5193     (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")
 5194     (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")
 5195     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/4")
 5196     (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")
 5197     # var a: t
 5198     (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")
 5199     (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")
 5200     # var b/eax: (addr t)
 5201     (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")
 5202     (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")
 5203     # foo a
 5204     (check-next-stream-line-equal _test-output-stream "    (foo %eax)"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/10")
 5205     #
 5206     (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")
 5207     (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")
 5208     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/13")
 5209     (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")
 5210     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/15")
 5211     (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")
 5212     (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")
 5213     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/18")
 5214     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/19")
 5215     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/20")
 5216     (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")
 5217     (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")
 5218     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/23")
 5219     (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")
 5220     (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")
 5221     (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")
 5222     (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")
 5223     (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")
 5224     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/29")
 5225     (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")
 5226     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/31")
 5227     (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")
 5228     (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")
 5229     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/34")
 5230     # . epilogue
 5231     89/<- %esp 5/r32/ebp
 5232     5d/pop-to-ebp
 5233     c3/return
 5234 
 5235 test-convert-get-on-local-variable:
 5236     # . prologue
 5237     55/push-ebp
 5238     89/<- %ebp 4/r32/esp
 5239     # setup
 5240     (clear-stream _test-input-stream)
 5241     (clear-stream $_test-input-buffered-file->buffer)
 5242     (clear-stream _test-output-stream)
 5243     (clear-stream $_test-output-buffered-file->buffer)
 5244     #
 5245     (write _test-input-stream "fn foo {\n")
 5246     (write _test-input-stream "  var a: t\n")
 5247     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5248     (write _test-input-stream "}\n")
 5249     (write _test-input-stream "type t {\n")
 5250     (write _test-input-stream "  x: int\n")
 5251     (write _test-input-stream "  y: int\n")
 5252     (write _test-input-stream "}\n")
 5253     # convert
 5254     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5255     (flush _test-output-buffered-file)
 5256 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5262     # check output
 5263     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-local-variable/0")
 5264     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-local-variable/1")
 5265     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-local-variable/2")
 5266     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-local-variable/3")
 5267     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-local-variable/4")
 5268     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-local-variable/5")
 5269     # var a
 5270     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/6")
 5271     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/7")
 5272     # var c
 5273     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-local-variable/8")
 5274     # get
 5275     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32"  "F - test-convert-get-on-local-variable/9")
 5276     # reclaim c
 5277     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-local-variable/10")
 5278     # reclaim a
 5279     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-get-on-local-variable/11")
 5280     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-local-variable/12")
 5281     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-local-variable/13")
 5282     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-local-variable/14")
 5283     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-local-variable/15")
 5284     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-local-variable/16")
 5285     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-local-variable/17")
 5286     # . epilogue
 5287     89/<- %esp 5/r32/ebp
 5288     5d/pop-to-ebp
 5289     c3/return
 5290 
 5291 test-convert-get-on-function-argument:
 5292     # . prologue
 5293     55/push-ebp
 5294     89/<- %ebp 4/r32/esp
 5295     # setup
 5296     (clear-stream _test-input-stream)
 5297     (clear-stream $_test-input-buffered-file->buffer)
 5298     (clear-stream _test-output-stream)
 5299     (clear-stream $_test-output-buffered-file->buffer)
 5300     #
 5301     (write _test-input-stream "fn foo a: t {\n")
 5302     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5303     (write _test-input-stream "}\n")
 5304     (write _test-input-stream "type t {\n")
 5305     (write _test-input-stream "  x: int\n")
 5306     (write _test-input-stream "  y: int\n")
 5307     (write _test-input-stream "}\n")
 5308     # convert
 5309     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5310     (flush _test-output-buffered-file)
 5311 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5317     # check output
 5318     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument/0")
 5319     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument/1")
 5320     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument/2")
 5321     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument/3")
 5322     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument/4")
 5323     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument/5")
 5324     # var c
 5325     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument/6")
 5326     # get
 5327     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0x0000000c) 0x00000001/r32"  "F - test-convert-get-on-function-argument/7")
 5328     # reclaim c
 5329     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument/8")
 5330     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument/9")
 5331     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument/10")
 5332     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument/11")
 5333     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument/12")
 5334     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument/13")
 5335     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument/14")
 5336     # . epilogue
 5337     89/<- %esp 5/r32/ebp
 5338     5d/pop-to-ebp
 5339     c3/return
 5340 
 5341 test-convert-get-on-function-argument-with-known-type:
 5342     # . prologue
 5343     55/push-ebp
 5344     89/<- %ebp 4/r32/esp
 5345     # setup
 5346     (clear-stream _test-input-stream)
 5347     (clear-stream $_test-input-buffered-file->buffer)
 5348     (clear-stream _test-output-stream)
 5349     (clear-stream $_test-output-buffered-file->buffer)
 5350     #
 5351     (write _test-input-stream "type t {\n")
 5352     (write _test-input-stream "  x: int\n")
 5353     (write _test-input-stream "  y: int\n")
 5354     (write _test-input-stream "}\n")
 5355     (write _test-input-stream "fn foo a: t {\n")
 5356     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5357     (write _test-input-stream "}\n")
 5358     # convert
 5359     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5360     (flush _test-output-buffered-file)
 5361 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5367     # check output
 5368     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument-with-known-type/0")
 5369     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument-with-known-type/1")
 5370     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument-with-known-type/2")
 5371     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument-with-known-type/3")
 5372     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument-with-known-type/4")
 5373     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument-with-known-type/5")
 5374     # var c
 5375     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument-with-known-type/6")
 5376     # get
 5377     (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")
 5378     # reclaim c
 5379     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument-with-known-type/8")
 5380     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument-with-known-type/9")
 5381     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument-with-known-type/10")
 5382     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument-with-known-type/11")
 5383     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument-with-known-type/12")
 5384     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument-with-known-type/13")
 5385     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument-with-known-type/14")
 5386     # . epilogue
 5387     89/<- %esp 5/r32/ebp
 5388     5d/pop-to-ebp
 5389     c3/return
 5390 
 5391 test-add-with-too-many-inouts:
 5392     # . prologue
 5393     55/push-ebp
 5394     89/<- %ebp 4/r32/esp
 5395     # setup
 5396     (clear-stream _test-input-stream)
 5397     (clear-stream $_test-input-buffered-file->buffer)
 5398     (clear-stream _test-output-stream)
 5399     (clear-stream $_test-output-buffered-file->buffer)
 5400     (clear-stream _test-error-stream)
 5401     (clear-stream $_test-error-buffered-file->buffer)
 5402     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5403     68/push 0/imm32
 5404     68/push 0/imm32
 5405     89/<- %edx 4/r32/esp
 5406     (tailor-exit-descriptor %edx 0x10)
 5407     #
 5408     (write _test-input-stream "fn foo {\n")
 5409     (write _test-input-stream "  var a: int\n")
 5410     (write _test-input-stream "  var b/ecx: int <- add a, 0\n")
 5411     (write _test-input-stream "}\n")
 5412     # convert
 5413     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5414     # registers except esp clobbered at this point
 5415     # restore ed
 5416     89/<- %edx 4/r32/esp
 5417     (flush _test-output-buffered-file)
 5418     (flush _test-error-buffered-file)
 5419 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5425     # check output
 5426     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts: output should be empty")
 5427     (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")
 5428     # check that stop(1) was called
 5429     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts: exit status")
 5430     # don't restore from ebp
 5431     81 0/subop/add %esp 8/imm32
 5432     # . epilogue
 5433     5d/pop-to-ebp
 5434     c3/return
 5435 
 5436 test-add-with-too-many-inouts-2:
 5437     # . prologue
 5438     55/push-ebp
 5439     89/<- %ebp 4/r32/esp
 5440     # setup
 5441     (clear-stream _test-input-stream)
 5442     (clear-stream $_test-input-buffered-file->buffer)
 5443     (clear-stream _test-output-stream)
 5444     (clear-stream $_test-output-buffered-file->buffer)
 5445     (clear-stream _test-error-stream)
 5446     (clear-stream $_test-error-buffered-file->buffer)
 5447     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5448     68/push 0/imm32
 5449     68/push 0/imm32
 5450     89/<- %edx 4/r32/esp
 5451     (tailor-exit-descriptor %edx 0x10)
 5452     #
 5453     (write _test-input-stream "fn foo {\n")
 5454     (write _test-input-stream "  var a: int\n")
 5455     (write _test-input-stream "  add-to a, 0, 1\n")
 5456     (write _test-input-stream "}\n")
 5457     # convert
 5458     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5459     # registers except esp clobbered at this point
 5460     # restore ed
 5461     89/<- %edx 4/r32/esp
 5462     (flush _test-output-buffered-file)
 5463     (flush _test-error-buffered-file)
 5464 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5470     # check output
 5471     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts-2: output should be empty")
 5472     (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")
 5473     # check that stop(1) was called
 5474     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts-2: exit status")
 5475     # don't restore from ebp
 5476     81 0/subop/add %esp 8/imm32
 5477     # . epilogue
 5478     5d/pop-to-ebp
 5479     c3/return
 5480 
 5481 test-add-with-too-many-outputs:
 5482     # . prologue
 5483     55/push-ebp
 5484     89/<- %ebp 4/r32/esp
 5485     # setup
 5486     (clear-stream _test-input-stream)
 5487     (clear-stream $_test-input-buffered-file->buffer)
 5488     (clear-stream _test-output-stream)
 5489     (clear-stream $_test-output-buffered-file->buffer)
 5490     (clear-stream _test-error-stream)
 5491     (clear-stream $_test-error-buffered-file->buffer)
 5492     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5493     68/push 0/imm32
 5494     68/push 0/imm32
 5495     89/<- %edx 4/r32/esp
 5496     (tailor-exit-descriptor %edx 0x10)
 5497     #
 5498     (write _test-input-stream "fn foo {\n")
 5499     (write _test-input-stream "  var a/eax: int <- copy 0\n")
 5500     (write _test-input-stream "  var b/ebx: int <- copy 0\n")
 5501     (write _test-input-stream "  var c/ecx: int <- copy 0\n")
 5502     (write _test-input-stream "  c, b <- add a\n")
 5503     (write _test-input-stream "}\n")
 5504     # convert
 5505     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5506     # registers except esp clobbered at this point
 5507     # restore ed
 5508     89/<- %edx 4/r32/esp
 5509     (flush _test-output-buffered-file)
 5510     (flush _test-error-buffered-file)
 5511 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5517     # check output
 5518     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-outputs: output should be empty")
 5519     (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")
 5520     # check that stop(1) was called
 5521     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-outputs: exit status")
 5522     # don't restore from ebp
 5523     81 0/subop/add %esp 8/imm32
 5524     # . epilogue
 5525     5d/pop-to-ebp
 5526     c3/return
 5527 
 5528 test-add-with-non-number:
 5529     # . prologue
 5530     55/push-ebp
 5531     89/<- %ebp 4/r32/esp
 5532     # setup
 5533     (clear-stream _test-input-stream)
 5534     (clear-stream $_test-input-buffered-file->buffer)
 5535     (clear-stream _test-output-stream)
 5536     (clear-stream $_test-output-buffered-file->buffer)
 5537     (clear-stream _test-error-stream)
 5538     (clear-stream $_test-error-buffered-file->buffer)
 5539     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5540     68/push 0/imm32
 5541     68/push 0/imm32
 5542     89/<- %edx 4/r32/esp
 5543     (tailor-exit-descriptor %edx 0x10)
 5544     #
 5545     (write _test-input-stream "fn foo {\n")
 5546     (write _test-input-stream "  var a: int\n")
 5547     (write _test-input-stream "  var b/ecx: (addr int) <- add a\n")
 5548     (write _test-input-stream "}\n")
 5549     # convert
 5550     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5551     # registers except esp clobbered at this point
 5552     # restore ed
 5553     89/<- %edx 4/r32/esp
 5554     (flush _test-output-buffered-file)
 5555     (flush _test-error-buffered-file)
 5556 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5562     # check output
 5563     (check-stream-equal _test-output-stream  ""  "F - test-add-with-non-number: output should be empty")
 5564     (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")
 5565     # check that stop(1) was called
 5566     (check-ints-equal *(edx+4) 2 "F - test-add-with-non-number: exit status")
 5567     # don't restore from ebp
 5568     81 0/subop/add %esp 8/imm32
 5569     # . epilogue
 5570     5d/pop-to-ebp
 5571     c3/return
 5572 
 5573 test-add-with-addr-dereferenced:
 5574     # . prologue
 5575     55/push-ebp
 5576     89/<- %ebp 4/r32/esp
 5577     # setup
 5578     (clear-stream _test-input-stream)
 5579     (clear-stream $_test-input-buffered-file->buffer)
 5580     (clear-stream _test-output-stream)
 5581     (clear-stream $_test-output-buffered-file->buffer)
 5582     #
 5583     (write _test-input-stream "fn foo {\n")
 5584     (write _test-input-stream "  var a/eax: (addr int) <- copy 0\n")
 5585     (write _test-input-stream "  add-to *a, 1\n")
 5586     (write _test-input-stream "}\n")
 5587     # convert
 5588     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5589     (flush _test-output-buffered-file)
 5590     # no error
 5591     # . epilogue
 5592     89/<- %esp 5/r32/ebp
 5593     5d/pop-to-ebp
 5594     c3/return
 5595 
 5596 test-get-with-wrong-field:
 5597     # . prologue
 5598     55/push-ebp
 5599     89/<- %ebp 4/r32/esp
 5600     # setup
 5601     (clear-stream _test-input-stream)
 5602     (clear-stream $_test-input-buffered-file->buffer)
 5603     (clear-stream _test-output-stream)
 5604     (clear-stream $_test-output-buffered-file->buffer)
 5605     (clear-stream _test-error-stream)
 5606     (clear-stream $_test-error-buffered-file->buffer)
 5607     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5608     68/push 0/imm32
 5609     68/push 0/imm32
 5610     89/<- %edx 4/r32/esp
 5611     (tailor-exit-descriptor %edx 0x10)
 5612     #
 5613     (write _test-input-stream "fn foo {\n")
 5614     (write _test-input-stream "  var a: t\n")
 5615     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5616     (write _test-input-stream "}\n")
 5617     (write _test-input-stream "type t {\n")
 5618     (write _test-input-stream "  x: int\n")
 5619     (write _test-input-stream "}\n")
 5620     # convert
 5621     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5622     # registers except esp clobbered at this point
 5623     # restore ed
 5624     89/<- %edx 4/r32/esp
 5625     (flush _test-output-buffered-file)
 5626     (flush _test-error-buffered-file)
 5627 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5633     # check output
 5634     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-field: output should be empty")
 5635     (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")
 5636     # check that stop(1) was called
 5637     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-field: exit status")
 5638     # don't restore from ebp
 5639     81 0/subop/add %esp 8/imm32
 5640     # . epilogue
 5641     5d/pop-to-ebp
 5642     c3/return
 5643 
 5644 test-get-with-wrong-base-type:
 5645     # . prologue
 5646     55/push-ebp
 5647     89/<- %ebp 4/r32/esp
 5648     # setup
 5649     (clear-stream _test-input-stream)
 5650     (clear-stream $_test-input-buffered-file->buffer)
 5651     (clear-stream _test-output-stream)
 5652     (clear-stream $_test-output-buffered-file->buffer)
 5653     (clear-stream _test-error-stream)
 5654     (clear-stream $_test-error-buffered-file->buffer)
 5655     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5656     68/push 0/imm32
 5657     68/push 0/imm32
 5658     89/<- %edx 4/r32/esp
 5659     (tailor-exit-descriptor %edx 0x10)
 5660     #
 5661     (write _test-input-stream "fn foo {\n")
 5662     (write _test-input-stream "  var a: int\n")
 5663     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5664     (write _test-input-stream "}\n")
 5665     # convert
 5666     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5667     # registers except esp clobbered at this point
 5668     # restore ed
 5669     89/<- %edx 4/r32/esp
 5670     (flush _test-output-buffered-file)
 5671     (flush _test-error-buffered-file)
 5672 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5678     # check output
 5679     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type: output should be empty")
 5680     (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")
 5681     # check that stop(1) was called
 5682     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type: exit status")
 5683     # don't restore from ebp
 5684     81 0/subop/add %esp 8/imm32
 5685     # . epilogue
 5686     5d/pop-to-ebp
 5687     c3/return
 5688 
 5689 test-get-with-wrong-base-type-2:
 5690     # . prologue
 5691     55/push-ebp
 5692     89/<- %ebp 4/r32/esp
 5693     # setup
 5694     (clear-stream _test-input-stream)
 5695     (clear-stream $_test-input-buffered-file->buffer)
 5696     (clear-stream _test-output-stream)
 5697     (clear-stream $_test-output-buffered-file->buffer)
 5698     (clear-stream _test-error-stream)
 5699     (clear-stream $_test-error-buffered-file->buffer)
 5700     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5701     68/push 0/imm32
 5702     68/push 0/imm32
 5703     89/<- %edx 4/r32/esp
 5704     (tailor-exit-descriptor %edx 0x10)
 5705     #
 5706     (write _test-input-stream "fn foo {\n")
 5707     (write _test-input-stream "  var a: (addr t)\n")
 5708     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5709     (write _test-input-stream "}\n")
 5710     (write _test-input-stream "type t {\n")
 5711     (write _test-input-stream "  x: int\n")
 5712     (write _test-input-stream "}\n")
 5713     # convert
 5714     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5715     # registers except esp clobbered at this point
 5716     # restore ed
 5717     89/<- %edx 4/r32/esp
 5718     (flush _test-output-buffered-file)
 5719     (flush _test-error-buffered-file)
 5720 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5726     # check output
 5727     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type-2: output should be empty")
 5728     (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")
 5729     # check that stop(1) was called
 5730     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type-2: exit status")
 5731     # don't restore from ebp
 5732     81 0/subop/add %esp 8/imm32
 5733     # . epilogue
 5734     5d/pop-to-ebp
 5735     c3/return
 5736 
 5737 test-get-with-wrong-offset-type:
 5738     # . prologue
 5739     55/push-ebp
 5740     89/<- %ebp 4/r32/esp
 5741     # setup
 5742     (clear-stream _test-input-stream)
 5743     (clear-stream $_test-input-buffered-file->buffer)
 5744     (clear-stream _test-output-stream)
 5745     (clear-stream $_test-output-buffered-file->buffer)
 5746     (clear-stream _test-error-stream)
 5747     (clear-stream $_test-error-buffered-file->buffer)
 5748     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5749     68/push 0/imm32
 5750     68/push 0/imm32
 5751     89/<- %edx 4/r32/esp
 5752     (tailor-exit-descriptor %edx 0x10)
 5753     #
 5754     (write _test-input-stream "fn foo {\n")
 5755     (write _test-input-stream "  var a: t\n")
 5756     (write _test-input-stream "  var b: int\n")
 5757     (write _test-input-stream "  var c/ecx: (addr int) <- get a, b\n")
 5758     (write _test-input-stream "}\n")
 5759     (write _test-input-stream "type t {\n")
 5760     (write _test-input-stream "  x: int\n")
 5761     (write _test-input-stream "}\n")
 5762     # convert
 5763     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5764     # registers except esp clobbered at this point
 5765     # restore ed
 5766     89/<- %edx 4/r32/esp
 5767     (flush _test-output-buffered-file)
 5768     (flush _test-error-buffered-file)
 5769 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5775     # check output
 5776     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-offset-type: output should be empty")
 5777     (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")
 5778     # check that stop(1) was called
 5779     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-offset-type: exit status")
 5780     # don't restore from ebp
 5781     81 0/subop/add %esp 8/imm32
 5782     # . epilogue
 5783     5d/pop-to-ebp
 5784     c3/return
 5785 
 5786 test-get-with-wrong-output-type:
 5787     # . prologue
 5788     55/push-ebp
 5789     89/<- %ebp 4/r32/esp
 5790     # setup
 5791     (clear-stream _test-input-stream)
 5792     (clear-stream $_test-input-buffered-file->buffer)
 5793     (clear-stream _test-output-stream)
 5794     (clear-stream $_test-output-buffered-file->buffer)
 5795     (clear-stream _test-error-stream)
 5796     (clear-stream $_test-error-buffered-file->buffer)
 5797     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5798     68/push 0/imm32
 5799     68/push 0/imm32
 5800     89/<- %edx 4/r32/esp
 5801     (tailor-exit-descriptor %edx 0x10)
 5802     #
 5803     (write _test-input-stream "fn foo {\n")
 5804     (write _test-input-stream "  var a: t\n")
 5805     (write _test-input-stream "  var c: (addr int)\n")
 5806     (write _test-input-stream "  c <- get a, x\n")
 5807     (write _test-input-stream "}\n")
 5808     (write _test-input-stream "type t {\n")
 5809     (write _test-input-stream "  x: int\n")
 5810     (write _test-input-stream "}\n")
 5811     # convert
 5812     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5813     # registers except esp clobbered at this point
 5814     # restore ed
 5815     89/<- %edx 4/r32/esp
 5816     (flush _test-output-buffered-file)
 5817     (flush _test-error-buffered-file)
 5818 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5824     # check output
 5825     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type: output should be empty")
 5826     (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")
 5827     # check that stop(1) was called
 5828     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type: exit status")
 5829     # don't restore from ebp
 5830     81 0/subop/add %esp 8/imm32
 5831     # . epilogue
 5832     5d/pop-to-ebp
 5833     c3/return
 5834 
 5835 test-get-with-wrong-output-type-2:
 5836     # . prologue
 5837     55/push-ebp
 5838     89/<- %ebp 4/r32/esp
 5839     # setup
 5840     (clear-stream _test-input-stream)
 5841     (clear-stream $_test-input-buffered-file->buffer)
 5842     (clear-stream _test-output-stream)
 5843     (clear-stream $_test-output-buffered-file->buffer)
 5844     (clear-stream _test-error-stream)
 5845     (clear-stream $_test-error-buffered-file->buffer)
 5846     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5847     68/push 0/imm32
 5848     68/push 0/imm32
 5849     89/<- %edx 4/r32/esp
 5850     (tailor-exit-descriptor %edx 0x10)
 5851     #
 5852     (write _test-input-stream "fn foo {\n")
 5853     (write _test-input-stream "  var a: t\n")
 5854     (write _test-input-stream "  var c/ecx: int <- get a, x\n")
 5855     (write _test-input-stream "}\n")
 5856     (write _test-input-stream "type t {\n")
 5857     (write _test-input-stream "  x: int\n")
 5858     (write _test-input-stream "}\n")
 5859     # convert
 5860     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5861     # registers except esp clobbered at this point
 5862     # restore ed
 5863     89/<- %edx 4/r32/esp
 5864     (flush _test-output-buffered-file)
 5865     (flush _test-error-buffered-file)
 5866 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5872     # check output
 5873     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-2: output should be empty")
 5874     (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")
 5875     # check that stop(1) was called
 5876     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-2: exit status")
 5877     # don't restore from ebp
 5878     81 0/subop/add %esp 8/imm32
 5879     # . epilogue
 5880     5d/pop-to-ebp
 5881     c3/return
 5882 
 5883 test-get-with-wrong-output-type-3:
 5884     # . prologue
 5885     55/push-ebp
 5886     89/<- %ebp 4/r32/esp
 5887     # setup
 5888     (clear-stream _test-input-stream)
 5889     (clear-stream $_test-input-buffered-file->buffer)
 5890     (clear-stream _test-output-stream)
 5891     (clear-stream $_test-output-buffered-file->buffer)
 5892     (clear-stream _test-error-stream)
 5893     (clear-stream $_test-error-buffered-file->buffer)
 5894     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5895     68/push 0/imm32
 5896     68/push 0/imm32
 5897     89/<- %edx 4/r32/esp
 5898     (tailor-exit-descriptor %edx 0x10)
 5899     #
 5900     (write _test-input-stream "fn foo {\n")
 5901     (write _test-input-stream "  var a: t\n")
 5902     (write _test-input-stream "  var c/ecx: (array int) <- 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-3: output should be empty")
 5922     (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")
 5923     # check that stop(1) was called
 5924     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-3: 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-4:
 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: (addr boolean) <- 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-4: output should be empty")
 5970     (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")
 5971     # check that stop(1) was called
 5972     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-4: 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-5:
 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     #
 5989     (write _test-input-stream "fn foo {\n")
 5990     (write _test-input-stream "  var a: t\n")
 5991     (write _test-input-stream "  var c/ecx: (addr handle int) <- get a, x\n")
 5992     (write _test-input-stream "}\n")
 5993     (write _test-input-stream "type t {\n")
 5994     (write _test-input-stream "  x: (handle int)\n")
 5995     (write _test-input-stream "}\n")
 5996     # convert
 5997     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5998     (flush _test-output-buffered-file)
 5999     # no errors
 6000     # . epilogue
 6001     89/<- %esp 5/r32/ebp
 6002     5d/pop-to-ebp
 6003     c3/return
 6004 
 6005 test-get-with-too-few-inouts:
 6006     # . prologue
 6007     55/push-ebp
 6008     89/<- %ebp 4/r32/esp
 6009     # setup
 6010     (clear-stream _test-input-stream)
 6011     (clear-stream $_test-input-buffered-file->buffer)
 6012     (clear-stream _test-output-stream)
 6013     (clear-stream $_test-output-buffered-file->buffer)
 6014     (clear-stream _test-error-stream)
 6015     (clear-stream $_test-error-buffered-file->buffer)
 6016     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6017     68/push 0/imm32
 6018     68/push 0/imm32
 6019     89/<- %edx 4/r32/esp
 6020     (tailor-exit-descriptor %edx 0x10)
 6021     #
 6022     (write _test-input-stream "fn foo {\n")
 6023     (write _test-input-stream "  var a: t\n")
 6024     (write _test-input-stream "  var c/ecx: (addr int) <- get a\n")
 6025     (write _test-input-stream "}\n")
 6026     (write _test-input-stream "type t {\n")
 6027     (write _test-input-stream "  x: int\n")
 6028     (write _test-input-stream "}\n")
 6029     # convert
 6030     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6031     # registers except esp clobbered at this point
 6032     # restore ed
 6033     89/<- %edx 4/r32/esp
 6034     (flush _test-output-buffered-file)
 6035     (flush _test-error-buffered-file)
 6036 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6042     # check output
 6043     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-few-inouts: output should be empty")
 6044     (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")
 6045     # check that stop(1) was called
 6046     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-few-inouts: exit status")
 6047     # don't restore from ebp
 6048     81 0/subop/add %esp 8/imm32
 6049     # . epilogue
 6050     5d/pop-to-ebp
 6051     c3/return
 6052 
 6053 test-get-with-too-many-inouts:
 6054     # . prologue
 6055     55/push-ebp
 6056     89/<- %ebp 4/r32/esp
 6057     # setup
 6058     (clear-stream _test-input-stream)
 6059     (clear-stream $_test-input-buffered-file->buffer)
 6060     (clear-stream _test-output-stream)
 6061     (clear-stream $_test-output-buffered-file->buffer)
 6062     (clear-stream _test-error-stream)
 6063     (clear-stream $_test-error-buffered-file->buffer)
 6064     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6065     68/push 0/imm32
 6066     68/push 0/imm32
 6067     89/<- %edx 4/r32/esp
 6068     (tailor-exit-descriptor %edx 0x10)
 6069     #
 6070     (write _test-input-stream "fn foo {\n")
 6071     (write _test-input-stream "  var a: t\n")
 6072     (write _test-input-stream "  var c/ecx: (addr int) <- get a, x, 0\n")
 6073     (write _test-input-stream "}\n")
 6074     (write _test-input-stream "type t {\n")
 6075     (write _test-input-stream "  x: int\n")
 6076     (write _test-input-stream "}\n")
 6077     # convert
 6078     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6079     # registers except esp clobbered at this point
 6080     # restore ed
 6081     89/<- %edx 4/r32/esp
 6082     (flush _test-output-buffered-file)
 6083     (flush _test-error-buffered-file)
 6084 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6090     # check output
 6091     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-inouts: output should be empty")
 6092     (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")
 6093     # check that stop(1) was called
 6094     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-inouts: exit status")
 6095     # don't restore from ebp
 6096     81 0/subop/add %esp 8/imm32
 6097     # . epilogue
 6098     5d/pop-to-ebp
 6099     c3/return
 6100 
 6101 test-get-with-no-output:
 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 "  get a, x\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-no-output: output should be empty")
 6140     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: must have an output"  "F - test-get-with-no-output: error message")
 6141     # check that stop(1) was called
 6142     (check-ints-equal *(edx+4) 2 "F - test-get-with-no-output: 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-outputs:
 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 b: int\n")
 6169     (write _test-input-stream "  var c/eax: (addr int) <- copy 0\n")
 6170     (write _test-input-stream "  c, b <- get a, x\n")
 6171     (write _test-input-stream "}\n")
 6172     (write _test-input-stream "type t {\n")
 6173     (write _test-input-stream "  x: int\n")
 6174     (write _test-input-stream "}\n")
 6175     # convert
 6176     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6177     # registers except esp clobbered at this point
 6178     # restore ed
 6179     89/<- %edx 4/r32/esp
 6180     (flush _test-output-buffered-file)
 6181     (flush _test-error-buffered-file)
 6182 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6188     # check output
 6189     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-outputs: output should be empty")
 6190     (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")
 6191     # check that stop(1) was called
 6192     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-outputs: exit status")
 6193     # don't restore from ebp
 6194     81 0/subop/add %esp 8/imm32
 6195     # . epilogue
 6196     5d/pop-to-ebp
 6197     c3/return
 6198 
 6199 test-convert-array-of-user-defined-types:
 6200     # . prologue
 6201     55/push-ebp
 6202     89/<- %ebp 4/r32/esp
 6203     # setup
 6204     (clear-stream _test-input-stream)
 6205     (clear-stream $_test-input-buffered-file->buffer)
 6206     (clear-stream _test-output-stream)
 6207     (clear-stream $_test-output-buffered-file->buffer)
 6208     #
 6209     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 6210     (write _test-input-stream "  x: int\n")
 6211     (write _test-input-stream "  y: int\n")
 6212     (write _test-input-stream "}\n")
 6213     (write _test-input-stream "fn foo {\n")
 6214     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6215     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 6216     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 6217     (write _test-input-stream "}\n")
 6218     # convert
 6219     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6220     (flush _test-output-buffered-file)
 6221 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6227     # check output
 6228     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-array-of-user-defined-types/0")
 6229     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-array-of-user-defined-types/1")
 6230     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-array-of-user-defined-types/2")
 6231     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-array-of-user-defined-types/3")
 6232     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-array-of-user-defined-types/4")
 6233     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-array-of-user-defined-types/5")
 6234     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-array-of-user-defined-types/6")
 6235     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-array-of-user-defined-types/7")
 6236     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-array-of-user-defined-types/8")
 6237     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-array-of-user-defined-types/9")
 6238     (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")
 6239     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-array-of-user-defined-types/13")
 6240     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-array-of-user-defined-types/14")
 6241     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-array-of-user-defined-types/15")
 6242     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-array-of-user-defined-types/16")
 6243     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-array-of-user-defined-types/17")
 6244     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-array-of-user-defined-types/18")
 6245     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-array-of-user-defined-types/19")
 6246     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-array-of-user-defined-types/20")
 6247     # . epilogue
 6248     89/<- %esp 5/r32/ebp
 6249     5d/pop-to-ebp
 6250     c3/return
 6251 
 6252 test-convert-length-of-array-of-user-defined-types-to-eax:
 6253     # . prologue
 6254     55/push-ebp
 6255     89/<- %ebp 4/r32/esp
 6256     # setup
 6257     (clear-stream _test-input-stream)
 6258     (clear-stream $_test-input-buffered-file->buffer)
 6259     (clear-stream _test-output-stream)
 6260     (clear-stream $_test-output-buffered-file->buffer)
 6261     #
 6262     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6263     (write _test-input-stream "  x: int\n")
 6264     (write _test-input-stream "  y: int\n")
 6265     (write _test-input-stream "  z: int\n")
 6266     (write _test-input-stream "}\n")
 6267     (write _test-input-stream "fn foo {\n")
 6268     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6269     (write _test-input-stream "  var x/eax: (addr t) <- length arr\n")
 6270     (write _test-input-stream "}\n")
 6271     # convert
 6272     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6273     (flush _test-output-buffered-file)
 6274 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6280     # check output
 6281     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-eax/0")
 6282     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/1")
 6283     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-eax/2")
 6284     (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")
 6285     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/4")
 6286     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-eax/5")
 6287     # var arr
 6288     (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")
 6289     (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")
 6290     # length instruction
 6291     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/8")
 6292     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/9")
 6293     (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")
 6294     (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")
 6295     (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")
 6296     (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")
 6297     (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")
 6298     (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")
 6299     # reclaim arr
 6300     (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")
 6301     #
 6302     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/17")
 6303     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/18")
 6304     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/19")
 6305     (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")
 6306     (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")
 6307     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-eax/22")
 6308     # . epilogue
 6309     89/<- %esp 5/r32/ebp
 6310     5d/pop-to-ebp
 6311     c3/return
 6312 
 6313 test-convert-length-of-array-of-user-defined-types-to-ecx:
 6314     # . prologue
 6315     55/push-ebp
 6316     89/<- %ebp 4/r32/esp
 6317     # setup
 6318     (clear-stream _test-input-stream)
 6319     (clear-stream $_test-input-buffered-file->buffer)
 6320     (clear-stream _test-output-stream)
 6321     (clear-stream $_test-output-buffered-file->buffer)
 6322     #
 6323     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6324     (write _test-input-stream "  x: int\n")
 6325     (write _test-input-stream "  y: int\n")
 6326     (write _test-input-stream "  z: int\n")
 6327     (write _test-input-stream "}\n")
 6328     (write _test-input-stream "fn foo {\n")
 6329     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6330     (write _test-input-stream "  var x/ecx: (addr t) <- length arr\n")
 6331     (write _test-input-stream "}\n")
 6332     # convert
 6333     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6334     (flush _test-output-buffered-file)
 6335 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6341     # check output
 6342     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-ecx/0")
 6343     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/1")
 6344     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-ecx/2")
 6345     (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")
 6346     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/4")
 6347     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-ecx/5")
 6348     # var a
 6349     (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")
 6350     (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")
 6351     # var x
 6352     (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")
 6353     # length instruction
 6354     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/9")
 6355     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/10")
 6356     (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")
 6357     (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")
 6358     (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")
 6359     (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")
 6360     (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")
 6361     (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")
 6362     (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")
 6363     # reclaim x
 6364     (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")
 6365     # reclaim a
 6366     (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")
 6367     #
 6368     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/20")
 6369     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/21")
 6370     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/22")
 6371     (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")
 6372     (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")
 6373     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-ecx/25")
 6374     # . epilogue
 6375     89/<- %esp 5/r32/ebp
 6376     5d/pop-to-ebp
 6377     c3/return
 6378 
 6379 test-convert-length-of-array-of-user-defined-types-to-edx:
 6380     # . prologue
 6381     55/push-ebp
 6382     89/<- %ebp 4/r32/esp
 6383     # setup
 6384     (clear-stream _test-input-stream)
 6385     (clear-stream $_test-input-buffered-file->buffer)
 6386     (clear-stream _test-output-stream)
 6387     (clear-stream $_test-output-buffered-file->buffer)
 6388     #
 6389     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6390     (write _test-input-stream "  x: int\n")
 6391     (write _test-input-stream "  y: int\n")
 6392     (write _test-input-stream "  z: int\n")
 6393     (write _test-input-stream "}\n")
 6394     (write _test-input-stream "fn foo {\n")
 6395     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6396     (write _test-input-stream "  var x/edx: (addr t) <- length arr\n")
 6397     (write _test-input-stream "}\n")
 6398     # convert
 6399     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6400     (flush _test-output-buffered-file)
 6401 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6407     # check output
 6408     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-edx/0")
 6409     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/1")
 6410     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-edx/2")
 6411     (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")
 6412     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/4")
 6413     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-edx/5")
 6414     # var a
 6415     (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")
 6416     (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")
 6417     # var x
 6418     (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")
 6419     # length instruction
 6420     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/9")
 6421     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/10")
 6422     (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")
 6423     (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")
 6424     (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")
 6425     (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")
 6426     (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")
 6427     (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")
 6428     (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")
 6429     # reclaim x
 6430     (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")
 6431     # reclaim a
 6432     (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")
 6433     #
 6434     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/20")
 6435     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/21")
 6436     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/22")
 6437     (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")
 6438     (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")
 6439     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-edx/25")
 6440     # . epilogue
 6441     89/<- %esp 5/r32/ebp
 6442     5d/pop-to-ebp
 6443     c3/return
 6444 
 6445 test-convert-length-of-array-of-user-defined-types:
 6446     # . prologue
 6447     55/push-ebp
 6448     89/<- %ebp 4/r32/esp
 6449     # setup
 6450     (clear-stream _test-input-stream)
 6451     (clear-stream $_test-input-buffered-file->buffer)
 6452     (clear-stream _test-output-stream)
 6453     (clear-stream $_test-output-buffered-file->buffer)
 6454     #
 6455     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 6456     (write _test-input-stream "  x: int\n")
 6457     (write _test-input-stream "  y: int\n")
 6458     (write _test-input-stream "  z: int\n")
 6459     (write _test-input-stream "}\n")
 6460     (write _test-input-stream "fn foo {\n")
 6461     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6462     (write _test-input-stream "  var x/ebx: (addr t) <- length arr\n")
 6463     (write _test-input-stream "}\n")
 6464     # convert
 6465     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6466     (flush _test-output-buffered-file)
 6467 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6473     # check output
 6474     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types/0")
 6475     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types/1")
 6476     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types/2")
 6477     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types/3")
 6478     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types/4")
 6479     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types/5")
 6480     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types/6")
 6481     (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")
 6482     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ebx"  "F - test-convert-length-of-array-of-user-defined-types/8")
 6483     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types/9")
 6484     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types/10")
 6485     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types/11")
 6486     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types/12")
 6487     (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")
 6488     (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")
 6489     (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")
 6490     (check-next-stream-line-equal _test-output-stream "    89/<- %ebx 0/r32/eax"  "F - test-convert-length-of-array-of-user-defined-types/16")
 6491     (check-next-stream-line-equal _test-output-stream "    5a/pop-to-edx"       "F - test-convert-length-of-array-of-user-defined-types/17")
 6492     (check-next-stream-line-equal _test-output-stream "    59/pop-to-ecx"       "F - test-convert-length-of-array-of-user-defined-types/18")
 6493     (check-next-stream-line-equal _test-output-stream "    58/pop-to-eax"       "F - test-convert-length-of-array-of-user-defined-types/19")
 6494     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ebx"  "F - test-convert-length-of-array-of-user-defined-types/20")
 6495     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types/21")
 6496     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types/22")
 6497     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types/23")
 6498     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types/24")
 6499     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types/25")
 6500     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types/26")
 6501     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types/27")
 6502     # . epilogue
 6503     89/<- %esp 5/r32/ebp
 6504     5d/pop-to-ebp
 6505     c3/return
 6506 
 6507 #######################################################
 6508 # Parsing
 6509 #######################################################
 6510 
 6511 == data
 6512 
 6513 # Global state added to each var record when parsing a function
 6514 Next-block-index:  # (addr int)
 6515     1/imm32
 6516 
 6517 Curr-block-depth:  # (addr int)
 6518     1/imm32
 6519 
 6520 == code
 6521 
 6522 parse-mu:  # in: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
 6523     # pseudocode
 6524     #   var curr-function: (addr handle function) = Program->functions
 6525     #   var curr-signature: (addr handle function) = Program->signatures
 6526     #   var curr-type: (addr handle typeinfo) = Program->types
 6527     #   var line: (stream byte 512)
 6528     #   var word-slice: slice
 6529     #   while true                                  # line loop
 6530     #     clear-stream(line)
 6531     #     read-line-buffered(in, line)
 6532     #     if (line->write == 0) break               # end of file
 6533     #     word-slice = next-mu-token(line)
 6534     #     if slice-empty?(word-slice)               # end of line
 6535     #       continue
 6536     #     else if slice-starts-with?(word-slice, "#")  # comment
 6537     #       continue                                # end of line
 6538     #     else if slice-equal?(word-slice, "fn")
 6539     #       var new-function: (handle function) = allocate(function)
 6540     #       var vars: (stack live-var 256)
 6541     #       populate-mu-function-header(line, new-function, vars)
 6542     #       populate-mu-function-body(in, new-function, vars)
 6543     #       assert(vars->top == 0)
 6544     #       *curr-function = new-function
 6545     #       curr-function = &new-function->next
 6546     #     else if slice-equal?(word-slice, "sig")
 6547     #       var new-function: (handle function) = allocate(function)
 6548     #       populate-mu-function-signature(line, new-function)
 6549     #       *curr-signature = new-function
 6550     #       curr-signature = &new-function->next
 6551     #     else if slice-equal?(word-slice, "type")
 6552     #       word-slice = next-mu-token(line)
 6553     #       type-id = pos-or-insert-slice(Type-id, word-slice)
 6554     #       var new-type: (handle typeinfo) = find-or-create-typeinfo(type-id)
 6555     #       assert(next-word(line) == "{")
 6556     #       populate-mu-type(in, new-type)
 6557     #     else
 6558     #       abort()
 6559     #
 6560     # . prologue
 6561     55/push-ebp
 6562     89/<- %ebp 4/r32/esp
 6563     # var curr-signature: (addr handle function) at *(ebp-4)
 6564     68/push _Program-signatures/imm32
 6565     # . save registers
 6566     50/push-eax
 6567     51/push-ecx
 6568     52/push-edx
 6569     53/push-ebx
 6570     56/push-esi
 6571     57/push-edi
 6572     # var line/ecx: (stream byte 512)
 6573     81 5/subop/subtract %esp 0x200/imm32
 6574     68/push 0x200/imm32/size
 6575     68/push 0/imm32/read
 6576     68/push 0/imm32/write
 6577     89/<- %ecx 4/r32/esp
 6578     # var word-slice/edx: slice
 6579     68/push 0/imm32/end
 6580     68/push 0/imm32/start
 6581     89/<- %edx 4/r32/esp
 6582     # var curr-function/edi: (addr handle function)
 6583     bf/copy-to-edi _Program-functions/imm32
 6584     # var vars/ebx: (stack live-var 256)
 6585     81 5/subop/subtract %esp 0xc00/imm32
 6586     68/push 0xc00/imm32/size
 6587     68/push 0/imm32/top
 6588     89/<- %ebx 4/r32/esp
 6589     {
 6590 $parse-mu:line-loop:
 6591       (clear-stream %ecx)
 6592       (read-line-buffered *(ebp+8) %ecx)
 6593       # if (line->write == 0) break
 6594       81 7/subop/compare *ecx 0/imm32
 6595       0f 84/jump-if-= break/disp32
 6596 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
 6602       (next-mu-token %ecx %edx)
 6603       # if slice-empty?(word-slice) continue
 6604       (slice-empty? %edx)  # => eax
 6605       3d/compare-eax-and 0/imm32/false
 6606       0f 85/jump-if-!= loop/disp32
 6607       # if (*word-slice->start == "#") continue
 6608       # . eax = *word-slice->start
 6609       8b/-> *edx 0/r32/eax
 6610       8a/copy-byte *eax 0/r32/AL
 6611       81 4/subop/and %eax 0xff/imm32
 6612       # . if (eax == '#') continue
 6613       3d/compare-eax-and 0x23/imm32/hash
 6614       0f 84/jump-if-= loop/disp32
 6615       # if (slice-equal?(word-slice, "fn")) parse a function
 6616       {
 6617 $parse-mu:fn:
 6618         (slice-equal? %edx "fn")  # => eax
 6619         3d/compare-eax-and 0/imm32/false
 6620         0f 84/jump-if-= break/disp32
 6621         # var new-function/esi: (handle function)
 6622         68/push 0/imm32
 6623         68/push 0/imm32
 6624         89/<- %esi 4/r32/esp
 6625         # populate-mu-function(line, in, vars, new-function)
 6626         (allocate Heap *Function-size %esi)
 6627         # var new-function-addr/eax: (addr function)
 6628         (lookup *esi *(esi+4))  # => eax
 6629         # initialize vars
 6630         (clear-stack %ebx)
 6631         #
 6632         (populate-mu-function-header %ecx %eax %ebx *(ebp+0xc) *(ebp+0x10))
 6633         (populate-mu-function-body *(ebp+8) %eax %ebx *(ebp+0xc) *(ebp+0x10))
 6634         # *curr-function = new-function
 6635         8b/-> *esi 0/r32/eax
 6636         89/<- *edi 0/r32/eax
 6637         8b/-> *(esi+4) 0/r32/eax
 6638         89/<- *(edi+4) 0/r32/eax
 6639         # curr-function = &new-function->next
 6640         # . var tmp/eax: (addr function) = lookup(new-function)
 6641         (lookup *esi *(esi+4))  # => eax
 6642         # . curr-function = &tmp->next
 6643         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 6644         # reclaim new-function
 6645         81 0/subop/add %esp 8/imm32
 6646         #
 6647         e9/jump $parse-mu:line-loop/disp32
 6648       }
 6649       # if (slice-equal?(word-slice, "sig")) parse a function signature
 6650       # Function signatures are for providing types to SubX functions.
 6651       {
 6652 $parse-mu:sig:
 6653         (slice-equal? %edx "sig")  # => eax
 6654         3d/compare-eax-and 0/imm32/false
 6655         0f 84/jump-if-= break/disp32
 6656         # edi = curr-function
 6657         57/push-edi
 6658         8b/-> *(ebp-4) 7/r32/edi
 6659         # var new-function/esi: (handle function)
 6660         68/push 0/imm32
 6661         68/push 0/imm32
 6662         89/<- %esi 4/r32/esp
 6663         # populate-mu-function(line, in, vars, new-function)
 6664         (allocate Heap *Function-size %esi)
 6665         # var new-function-addr/eax: (addr function)
 6666         (lookup *esi *(esi+4))  # => eax
 6667         #
 6668         (populate-mu-function-signature %ecx %eax *(ebp+0xc) *(ebp+0x10))
 6669         # *curr-signature = new-function
 6670         8b/-> *esi 0/r32/eax
 6671         89/<- *edi 0/r32/eax
 6672         8b/-> *(esi+4) 0/r32/eax
 6673         89/<- *(edi+4) 0/r32/eax
 6674         # curr-signature = &new-function->next
 6675         # . var tmp/eax: (addr function) = lookup(new-function)
 6676         (lookup *esi *(esi+4))  # => eax
 6677         # . curr-function = &tmp->next
 6678         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 6679         # reclaim new-function
 6680         81 0/subop/add %esp 8/imm32
 6681         # save curr-function
 6682         89/<- *(ebp-4) 7/r32/edi
 6683         # restore edi
 6684         5f/pop-to-edi
 6685         #
 6686         e9/jump $parse-mu:line-loop/disp32
 6687       }
 6688       # if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition
 6689       {
 6690 $parse-mu:type:
 6691         (slice-equal? %edx "type")  # => eax
 6692         3d/compare-eax-and 0/imm32
 6693         0f 84/jump-if-= break/disp32
 6694         (next-mu-token %ecx %edx)
 6695         # var type-id/eax: int
 6696         (pos-or-insert-slice Type-id %edx)  # => eax
 6697         # spill
 6698         51/push-ecx
 6699         # var new-type/ecx: (handle typeinfo)
 6700         68/push 0/imm32
 6701         68/push 0/imm32
 6702         89/<- %ecx 4/r32/esp
 6703         (find-or-create-typeinfo %eax %ecx)
 6704         #
 6705         (lookup *ecx *(ecx+4))  # => eax
 6706         # TODO: ensure that 'line' has nothing else but '{'
 6707 #? (dump-typeinfos "=== aaa\n")
 6708         (populate-mu-type *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))  # => eax
 6709 #? (dump-typeinfos "=== zzz\n")
 6710         # reclaim new-type
 6711         81 0/subop/add %esp 8/imm32
 6712         # restore
 6713         59/pop-to-ecx
 6714         e9/jump $parse-mu:line-loop/disp32
 6715       }
 6716       # otherwise abort
 6717       e9/jump $parse-mu:error1/disp32
 6718     } # end line loop
 6719 $parse-mu:end:
 6720     # . reclaim locals
 6721     81 0/subop/add %esp 0x20c/imm32  # line
 6722     81 0/subop/add %esp 0xc08/imm32  # vars
 6723     81 0/subop/add %esp 8/imm32
 6724     # . restore registers
 6725     5f/pop-to-edi
 6726     5e/pop-to-esi
 6727     5b/pop-to-ebx
 6728     5a/pop-to-edx
 6729     59/pop-to-ecx
 6730     58/pop-to-eax
 6731     # . reclaim local
 6732     81 0/subop/add %esp 4/imm32
 6733     # . epilogue
 6734     89/<- %esp 5/r32/ebp
 6735     5d/pop-to-ebp
 6736     c3/return
 6737 
 6738 $parse-mu:error1:
 6739     # error("unexpected top-level command: " word-slice "\n")
 6740     (write-buffered *(ebp+0xc) "unexpected top-level command: ")
 6741     (write-slice-buffered *(ebp+0xc) %edx)
 6742     (write-buffered *(ebp+0xc) "\n")
 6743     (flush *(ebp+0xc))
 6744     (stop *(ebp+0x10) 1)
 6745     # never gets here
 6746 
 6747 $parse-mu:error2:
 6748     # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n")
 6749     (write-int32-hex-buffered *(ebp+0xc) *ebx)
 6750     (write-buffered *(ebp+0xc) " vars not reclaimed after fn '")
 6751     (write-slice-buffered *(ebp+0xc) *eax)  # Function-name
 6752     (write-buffered *(ebp+0xc) "'\n")
 6753     (flush *(ebp+0xc))
 6754     (stop *(ebp+0x10) 1)
 6755     # never gets here
 6756 
 6757 # scenarios considered:
 6758 # ✗ fn foo  # no block
 6759 # ✓ fn foo {
 6760 # ✗ fn foo { {
 6761 # ✗ fn foo { }
 6762 # ✗ fn foo { } {
 6763 # ✗ fn foo x {
 6764 # ✗ fn foo x: {
 6765 # ✓ fn foo x: int {
 6766 # ✓ fn foo x: int {
 6767 # ✓ fn foo x: int -> y/eax: int {
 6768 # TODO:
 6769 #   disallow outputs of type `(... addr ...)`
 6770 #   disallow inputs of type `(... addr ... addr ...)`
 6771 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)
 6772     # pseudocode:
 6773     #   var word-slice: slice
 6774     #   next-mu-token(first-line, word-slice)
 6775     #   assert(word-slice not in '{' '}' '->')
 6776     #   out->name = slice-to-string(word-slice)
 6777     #   ## inouts
 6778     #   while true
 6779     #     word-slice = next-mu-token(first-line)
 6780     #     if (word-slice == '{') goto done
 6781     #     if (word-slice == '->') break
 6782     #     assert(word-slice != '}')
 6783     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 6784     #     assert(v->register == null)
 6785     #     # v->block-depth is implicitly 0
 6786     #     out->inouts = append(v, out->inouts)
 6787     #     push(vars, {v, false})
 6788     #   ## outputs
 6789     #   while true
 6790     #     word-slice = next-mu-token(first-line)
 6791     #     if (word-slice == '{') break
 6792     #     assert(word-slice not in '}' '->')
 6793     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 6794     #     assert(v->register != null)
 6795     #     out->outputs = append(v, out->outputs)
 6796     #   done:
 6797     #
 6798     # . prologue
 6799     55/push-ebp
 6800     89/<- %ebp 4/r32/esp
 6801     # . save registers
 6802     50/push-eax
 6803     51/push-ecx
 6804     52/push-edx
 6805     53/push-ebx
 6806     57/push-edi
 6807     # edi = out
 6808     8b/-> *(ebp+0xc) 7/r32/edi
 6809     # var word-slice/ecx: slice
 6810     68/push 0/imm32/end
 6811     68/push 0/imm32/start
 6812     89/<- %ecx 4/r32/esp
 6813     # var v/ebx: (handle var)
 6814     68/push 0/imm32
 6815     68/push 0/imm32
 6816     89/<- %ebx 4/r32/esp
 6817     # read function name
 6818     (next-mu-token *(ebp+8) %ecx)
 6819     # error checking
 6820     # if (word-slice == '{') abort
 6821     (slice-equal? %ecx "{")   # => eax
 6822     3d/compare-eax-and 0/imm32/false
 6823     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6824     # if (word-slice == '->') abort
 6825     (slice-equal? %ecx "->")   # => eax
 6826     3d/compare-eax-and 0/imm32/false
 6827     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6828     # if (word-slice == '}') abort
 6829     (slice-equal? %ecx "}")   # => eax
 6830     3d/compare-eax-and 0/imm32/false
 6831     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6832     # save function name
 6833     (slice-to-string Heap %ecx %edi)  # Function-name
 6834     # save function inouts
 6835     {
 6836 $populate-mu-function-header:check-for-inout:
 6837       (next-mu-token *(ebp+8) %ecx)
 6838       # if (word-slice == '{') goto done
 6839       (slice-equal? %ecx "{")   # => eax
 6840       3d/compare-eax-and 0/imm32/false
 6841       0f 85/jump-if-!= $populate-mu-function-header:done/disp32
 6842       # if (word-slice == '->') break
 6843       (slice-equal? %ecx "->")   # => eax
 6844       3d/compare-eax-and 0/imm32/false
 6845       0f 85/jump-if-!= break/disp32
 6846       # if (word-slice == '}') abort
 6847       (slice-equal? %ecx "}")   # => eax
 6848       3d/compare-eax-and 0/imm32/false
 6849       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6850       # v = parse-var-with-type(word-slice, first-line)
 6851       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 6852       # assert(v->register == null)
 6853       # . eax: (addr var) = lookup(v)
 6854       (lookup *ebx *(ebx+4))  # => eax
 6855       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 6856       0f 85/jump-if-!= $populate-mu-function-header:error2/disp32
 6857       # v->block-depth is implicitly 0
 6858       #
 6859       # out->inouts = append(v, out->inouts)
 6860       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 6861       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 6862       # push(vars, {v, false})
 6863       (push *(ebp+0x10) *ebx)
 6864       (push *(ebp+0x10) *(ebx+4))
 6865       (push *(ebp+0x10) 0)  # false
 6866       #
 6867       e9/jump loop/disp32
 6868     }
 6869     # save function outputs
 6870     {
 6871 $populate-mu-function-header:check-for-out:
 6872       (next-mu-token *(ebp+8) %ecx)
 6873       # if (word-slice == '{') break
 6874       (slice-equal? %ecx "{")   # => eax
 6875       3d/compare-eax-and 0/imm32/false
 6876       0f 85/jump-if-!= break/disp32
 6877       # if (word-slice == '->') abort
 6878       (slice-equal? %ecx "->")   # => eax
 6879       3d/compare-eax-and 0/imm32/false
 6880       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6881       # if (word-slice == '}') abort
 6882       (slice-equal? %ecx "}")   # => eax
 6883       3d/compare-eax-and 0/imm32/false
 6884       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6885       # v = parse-var-with-type(word-slice, first-line)
 6886       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 6887       # assert(var->register != null)
 6888       # . eax: (addr var) = lookup(v)
 6889       (lookup *ebx *(ebx+4))  # => eax
 6890       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 6891       0f 84/jump-if-= $populate-mu-function-header:error3/disp32
 6892       # out->outputs = append(v, out->outputs)
 6893       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 6894       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 6895       #
 6896       e9/jump loop/disp32
 6897     }
 6898 $populate-mu-function-header:done:
 6899     (check-no-tokens-left *(ebp+8))
 6900 $populate-mu-function-header:end:
 6901     # . reclaim locals
 6902     81 0/subop/add %esp 0x10/imm32
 6903     # . restore registers
 6904     5f/pop-to-edi
 6905     5b/pop-to-ebx
 6906     5a/pop-to-edx
 6907     59/pop-to-ecx
 6908     58/pop-to-eax
 6909     # . epilogue
 6910     89/<- %esp 5/r32/ebp
 6911     5d/pop-to-ebp
 6912     c3/return
 6913 
 6914 $populate-mu-function-header:error1:
 6915     # error("function header not in form 'fn <name> {'")
 6916     (write-buffered *(ebp+0x14) "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 6917     (flush *(ebp+0x14))
 6918     (rewind-stream *(ebp+8))
 6919     (write-stream-data *(ebp+0x14) *(ebp+8))
 6920     (write-buffered *(ebp+0x14) "'\n")
 6921     (flush *(ebp+0x14))
 6922     (stop *(ebp+0x18) 1)
 6923     # never gets here
 6924 
 6925 $populate-mu-function-header:error2:
 6926     # error("fn " fn ": function inout '" var "' cannot be in a register")
 6927     (write-buffered *(ebp+0x14) "fn ")
 6928     50/push-eax
 6929     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 6930     (write-buffered *(ebp+0x14) %eax)
 6931     58/pop-to-eax
 6932     (write-buffered *(ebp+0x14) ": function inout '")
 6933     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 6934     (write-buffered *(ebp+0x10) %eax)
 6935     (write-buffered *(ebp+0x14) "' cannot be in a register")
 6936     (flush *(ebp+0x14))
 6937     (stop *(ebp+0x18) 1)
 6938     # never gets here
 6939 
 6940 $populate-mu-function-header:error3:
 6941     # error("fn " fn ": function output '" var "' must be in a register")
 6942     (write-buffered *(ebp+0x14) "fn ")
 6943     50/push-eax
 6944     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 6945     (write-buffered *(ebp+0x14) %eax)
 6946     58/pop-to-eax
 6947     (write-buffered *(ebp+0x14) ": function output '")
 6948     (lookup *ebx *(ebx+4))  # => eax
 6949     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 6950     (write-buffered *(ebp+0x14) %eax)
 6951     (write-buffered *(ebp+0x14) "' must be in a register, in instruction '")
 6952     (rewind-stream *(ebp+8))
 6953     (write-stream-data *(ebp+0x14) *(ebp+8))
 6954     (write-buffered *(ebp+0x14) "'\n")
 6955     (flush *(ebp+0x14))
 6956     (stop *(ebp+0x18) 1)
 6957     # never gets here
 6958 
 6959 # scenarios considered:
 6960 # ✓ fn foo
 6961 # ✗ fn foo {
 6962 # ✓ fn foo x
 6963 # ✓ fn foo x: int
 6964 # ✓ fn foo x: int -> y/eax: int
 6965 # TODO:
 6966 #   disallow outputs of type `(... addr ...)`
 6967 #   disallow inputs of type `(... addr ... addr ...)`
 6968 populate-mu-function-signature:  # first-line: (addr stream byte), out: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 6969     # pseudocode:
 6970     #   var word-slice: slice
 6971     #   next-mu-token(first-line, word-slice)
 6972     #   assert(word-slice not in '{' '}' '->')
 6973     #   out->name = slice-to-string(word-slice)
 6974     #   ## inouts
 6975     #   while true
 6976     #     word-slice = next-mu-token(first-line)
 6977     #     if slice-empty?(word-slice) break
 6978     #     if (word-slice == '->') break
 6979     #     assert(word-slice not in '{' '}')
 6980     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 6981     #     assert(v->register == null)
 6982     #     # v->block-depth is implicitly 0
 6983     #     out->inouts = append(v, out->inouts)
 6984     #   ## outputs
 6985     #   while true
 6986     #     word-slice = next-mu-token(first-line)
 6987     #     if slice-empty?(word-slice) break
 6988     #     assert(word-slice not in '{' '}' '->')
 6989     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 6990     #     assert(v->register != null)
 6991     #     out->outputs = append(v, out->outputs)
 6992     #
 6993     # . prologue
 6994     55/push-ebp
 6995     89/<- %ebp 4/r32/esp
 6996     # . save registers
 6997     50/push-eax
 6998     51/push-ecx
 6999     52/push-edx
 7000     53/push-ebx
 7001     57/push-edi
 7002     # edi = out
 7003     8b/-> *(ebp+0xc) 7/r32/edi
 7004     # var word-slice/ecx: slice
 7005     68/push 0/imm32/end
 7006     68/push 0/imm32/start
 7007     89/<- %ecx 4/r32/esp
 7008     # var v/ebx: (handle var)
 7009     68/push 0/imm32
 7010     68/push 0/imm32
 7011     89/<- %ebx 4/r32/esp
 7012     # read function name
 7013     (next-mu-token *(ebp+8) %ecx)
 7014     # error checking
 7015     # if (word-slice == '{') abort
 7016     (slice-equal? %ecx "{")   # => eax
 7017     3d/compare-eax-and 0/imm32/false
 7018     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7019     # if (word-slice == '->') abort
 7020     (slice-equal? %ecx "->")   # => eax
 7021     3d/compare-eax-and 0/imm32/false
 7022     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7023     # if (word-slice == '}') abort
 7024     (slice-equal? %ecx "}")   # => eax
 7025     3d/compare-eax-and 0/imm32/false
 7026     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7027     # save function name
 7028     (slice-to-string Heap %ecx %edi)  # Function-name
 7029     # save function inouts
 7030     {
 7031 $populate-mu-function-signature:check-for-inout:
 7032       (next-mu-token *(ebp+8) %ecx)
 7033       (slice-empty? %ecx)  # => eax
 7034       3d/compare-eax-and 0/imm32/false
 7035       0f 85/jump-if-!= break/disp32
 7036       # if (word-slice == '->') break
 7037       (slice-equal? %ecx "->")   # => eax
 7038       3d/compare-eax-and 0/imm32/false
 7039       0f 85/jump-if-!= break/disp32
 7040       # if (word-slice == '{') abort
 7041       (slice-equal? %ecx "{")   # => eax
 7042       3d/compare-eax-and 0/imm32/false
 7043       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7044       # if (word-slice == '}') abort
 7045       (slice-equal? %ecx "}")   # => eax
 7046       3d/compare-eax-and 0/imm32/false
 7047       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7048       # v = parse-var-with-type(word-slice, first-line)
 7049       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
 7050       # assert(v->register == null)
 7051       # . eax: (addr var) = lookup(v)
 7052       (lookup *ebx *(ebx+4))  # => eax
 7053       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 7054       0f 85/jump-if-!= $populate-mu-function-signature:error2/disp32
 7055       # v->block-depth is implicitly 0
 7056       #
 7057       # out->inouts = append(v, out->inouts)
 7058       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 7059       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 7060       #
 7061       e9/jump loop/disp32
 7062     }
 7063     # save function outputs
 7064     {
 7065 $populate-mu-function-signature:check-for-out:
 7066       (next-mu-token *(ebp+8) %ecx)
 7067       (slice-empty? %ecx)  # => eax
 7068       3d/compare-eax-and 0/imm32/false
 7069       0f 85/jump-if-!= break/disp32
 7070       # if (word-slice == '{') abort
 7071       (slice-equal? %ecx "{")   # => eax
 7072       3d/compare-eax-and 0/imm32/false
 7073       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7074       # if (word-slice == '->') abort
 7075       (slice-equal? %ecx "->")   # => eax
 7076       3d/compare-eax-and 0/imm32/false
 7077       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7078       # if (word-slice == '}') abort
 7079       (slice-equal? %ecx "}")   # => eax
 7080       3d/compare-eax-and 0/imm32/false
 7081       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7082       # v = parse-var-with-type(word-slice, first-line)
 7083       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
 7084       # assert(var->register != null)
 7085       # . eax: (addr var) = lookup(v)
 7086       (lookup *ebx *(ebx+4))  # => eax
 7087       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 7088       0f 84/jump-if-= $populate-mu-function-signature:error3/disp32
 7089       # out->outputs = append(v, out->outputs)
 7090       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 7091       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 7092       #
 7093       e9/jump loop/disp32
 7094     }
 7095 $populate-mu-function-signature:done:
 7096     (check-no-tokens-left *(ebp+8))
 7097 $populate-mu-function-signature:end:
 7098     # . reclaim locals
 7099     81 0/subop/add %esp 0x10/imm32
 7100     # . restore registers
 7101     5f/pop-to-edi
 7102     5b/pop-to-ebx
 7103     5a/pop-to-edx
 7104     59/pop-to-ecx
 7105     58/pop-to-eax
 7106     # . epilogue
 7107     89/<- %esp 5/r32/ebp
 7108     5d/pop-to-ebp
 7109     c3/return
 7110 
 7111 $populate-mu-function-signature:error1:
 7112     # error("function signature not in form 'fn <name> {'")
 7113     (write-buffered *(ebp+0x10) "function signature not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 7114     (flush *(ebp+0x10))
 7115     (rewind-stream *(ebp+8))
 7116     (write-stream-data *(ebp+0x10) *(ebp+8))
 7117     (write-buffered *(ebp+0x10) "'\n")
 7118     (flush *(ebp+0x10))
 7119     (stop *(ebp+0x14) 1)
 7120     # never gets here
 7121 
 7122 $populate-mu-function-signature:error2:
 7123     # error("fn " fn ": function inout '" var "' cannot be in a register")
 7124     (write-buffered *(ebp+0x10) "fn ")
 7125     50/push-eax
 7126     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 7127     (write-buffered *(ebp+0x10) %eax)
 7128     58/pop-to-eax
 7129     (write-buffered *(ebp+0x10) ": function inout '")
 7130     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 7131     (write-buffered *(ebp+0x10) %eax)
 7132     (write-buffered *(ebp+0x10) "' cannot be in a register")
 7133     (flush *(ebp+0x10))
 7134     (stop *(ebp+0x14) 1)
 7135     # never gets here
 7136 
 7137 $populate-mu-function-signature:error3:
 7138     # error("fn " fn ": function output '" var "' must be in a register")
 7139     (write-buffered *(ebp+0x10) "fn ")
 7140     50/push-eax
 7141     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 7142     (write-buffered *(ebp+0x10) %eax)
 7143     58/pop-to-eax
 7144     (write-buffered *(ebp+0x10) ": function output '")
 7145     (lookup *ebx *(ebx+4))  # => eax
 7146     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 7147     (write-buffered *(ebp+0x10) %eax)
 7148     (write-buffered *(ebp+0x10) "' must be in a register, in instruction '")
 7149     (rewind-stream *(ebp+8))
 7150     (write-stream-data *(ebp+0x10) *(ebp+8))
 7151     (write-buffered *(ebp+0x10) "'\n")
 7152     (flush *(ebp+0x10))
 7153     (stop *(ebp+0x14) 1)
 7154     # never gets here
 7155 
 7156 test-function-header-with-arg:
 7157     # . prologue
 7158     55/push-ebp
 7159     89/<- %ebp 4/r32/esp
 7160     # setup
 7161     (clear-stream _test-input-stream)
 7162     (write _test-input-stream "foo n: int {\n")
 7163     # var result/ecx: function
 7164     2b/subtract *Function-size 4/r32/esp
 7165     89/<- %ecx 4/r32/esp
 7166     (zero-out %ecx *Function-size)
 7167     # var vars/ebx: (stack live-var 16)
 7168     81 5/subop/subtract %esp 0xc0/imm32
 7169     68/push 0xc0/imm32/size
 7170     68/push 0/imm32/top
 7171     89/<- %ebx 4/r32/esp
 7172     # convert
 7173     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 7174     # check result->name
 7175     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 7176     (check-strings-equal %eax "foo" "F - test-function-header-with-arg/name")
 7177     # var v/edx: (addr var) = result->inouts->value
 7178     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 7179     (lookup *eax *(eax+4))  # List-value List-value => eax
 7180     89/<- %edx 0/r32/eax
 7181     # check v->name
 7182     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 7183     (check-strings-equal %eax "n" "F - test-function-header-with-arg/inout:0")
 7184     # check v->type
 7185     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 7186     (check-ints-equal *eax 1 "F - test-function-header-with-arg/inout:0/type:0")  # Type-tree-is-atom
 7187     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-arg/inout:0/type:1")  # Type-tree-value
 7188     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-arg/inout:0/type:2")  # Type-tree-right
 7189     # . epilogue
 7190     89/<- %esp 5/r32/ebp
 7191     5d/pop-to-ebp
 7192     c3/return
 7193 
 7194 test-function-header-with-multiple-args:
 7195     # . prologue
 7196     55/push-ebp
 7197     89/<- %ebp 4/r32/esp
 7198     # setup
 7199     (clear-stream _test-input-stream)
 7200     (write _test-input-stream "foo a: int, b: int c: int {\n")
 7201     # result/ecx: function
 7202     2b/subtract *Function-size 4/r32/esp
 7203     89/<- %ecx 4/r32/esp
 7204     (zero-out %ecx *Function-size)
 7205     # var vars/ebx: (stack live-var 16)
 7206     81 5/subop/subtract %esp 0xc0/imm32
 7207     68/push 0xc0/imm32/size
 7208     68/push 0/imm32/top
 7209     89/<- %ebx 4/r32/esp
 7210     # convert
 7211     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 7212     # check result->name
 7213     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 7214     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args/name")
 7215     # var inouts/edx: (addr list var) = lookup(result->inouts)
 7216     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 7217     89/<- %edx 0/r32/eax
 7218 $test-function-header-with-multiple-args:inout0:
 7219     # var v/ebx: (addr var) = lookup(inouts->value)
 7220     (lookup *edx *(edx+4))  # List-value List-value => eax
 7221     89/<- %ebx 0/r32/eax
 7222     # check v->name
 7223     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7224     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args/inout:0")  # Var-name
 7225     # check v->type
 7226     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7227     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:0/type:0")  # Type-tree-is-atom
 7228     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:0/type:1")  # Type-tree-value
 7229     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:0/type:2")  # Type-tree-right
 7230 $test-function-header-with-multiple-args:inout1:
 7231     # inouts = lookup(inouts->next)
 7232     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 7233     89/<- %edx 0/r32/eax
 7234     # v = lookup(inouts->value)
 7235     (lookup *edx *(edx+4))  # List-value List-value => eax
 7236     89/<- %ebx 0/r32/eax
 7237     # check v->name
 7238     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7239     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args/inout:1")  # Var-name
 7240     # check v->type
 7241     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7242     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:1/type:0")  # Type-tree-is-atom
 7243     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:1/type:1")  # Type-tree-value
 7244     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:1/type:2")  # Type-tree-right
 7245 $test-function-header-with-multiple-args:inout2:
 7246     # inouts = lookup(inouts->next)
 7247     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 7248     89/<- %edx 0/r32/eax
 7249     # v = lookup(inouts->value)
 7250     (lookup *edx *(edx+4))  # List-value List-value => eax
 7251     89/<- %ebx 0/r32/eax
 7252     # check v->name
 7253     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7254     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args/inout:2")  # Var-name
 7255     # check v->type
 7256     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7257     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:2/type:0")  # Type-tree-is-atom
 7258     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:2/type:1")  # Type-tree-value
 7259     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:2/type:2")  # Type-tree-right
 7260     # . epilogue
 7261     89/<- %esp 5/r32/ebp
 7262     5d/pop-to-ebp
 7263     c3/return
 7264 
 7265 test-function-header-with-multiple-args-and-outputs:
 7266     # . prologue
 7267     55/push-ebp
 7268     89/<- %ebp 4/r32/esp
 7269     # setup
 7270     (clear-stream _test-input-stream)
 7271     (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n")
 7272     # result/ecx: function
 7273     2b/subtract *Function-size 4/r32/esp
 7274     89/<- %ecx 4/r32/esp
 7275     (zero-out %ecx *Function-size)
 7276     # var vars/ebx: (stack live-var 16)
 7277     81 5/subop/subtract %esp 0xc0/imm32
 7278     68/push 0xc0/imm32/size
 7279     68/push 0/imm32/top
 7280     89/<- %ebx 4/r32/esp
 7281     # convert
 7282     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 7283     # check result->name
 7284     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 7285     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args-and-outputs/name")
 7286     # var inouts/edx: (addr list var) = lookup(result->inouts)
 7287     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 7288     89/<- %edx 0/r32/eax
 7289 $test-function-header-with-multiple-args-and-outputs:inout0:
 7290     # var v/ebx: (addr var) = lookup(inouts->value)
 7291     (lookup *edx *(edx+4))  # List-value List-value => eax
 7292     89/<- %ebx 0/r32/eax
 7293     # check v->name
 7294     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7295     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0")
 7296     # check v->type
 7297     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7298     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0")  # Type-tree-is-atom
 7299     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1")  # Type-tree-value
 7300     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:2")  # Type-tree-right
 7301 $test-function-header-with-multiple-args-and-outputs:inout1:
 7302     # inouts = lookup(inouts->next)
 7303     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 7304     89/<- %edx 0/r32/eax
 7305     # v = lookup(inouts->value)
 7306     (lookup *edx *(edx+4))  # List-value List-value => eax
 7307     89/<- %ebx 0/r32/eax
 7308     # check v->name
 7309     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7310     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1")
 7311     # check v->type
 7312     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7313     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0")  # Type-tree-is-atom
 7314     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1")  # Type-tree-value
 7315     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:2")  # Type-tree-right
 7316 $test-function-header-with-multiple-args-and-outputs:inout2:
 7317     # inouts = lookup(inouts->next)
 7318     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 7319     89/<- %edx 0/r32/eax
 7320     # v = lookup(inouts->value)
 7321     (lookup *edx *(edx+4))  # List-value List-value => eax
 7322     89/<- %ebx 0/r32/eax
 7323     # check v->name
 7324     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7325     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2")
 7326     # check v->type
 7327     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7328     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0")  # Type-tree-is-atom
 7329     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1")  # Type-tree-value
 7330     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:2")  # Type-tree-right
 7331 $test-function-header-with-multiple-args-and-outputs:out0:
 7332     # var outputs/edx: (addr list var) = lookup(result->outputs)
 7333     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 7334     89/<- %edx 0/r32/eax
 7335     # v = lookup(outputs->value)
 7336     (lookup *edx *(edx+4))  # List-value List-value => eax
 7337     89/<- %ebx 0/r32/eax
 7338     # check v->name
 7339     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7340     (check-strings-equal %eax "x" "F - test-function-header-with-multiple-args-and-outputs/output:0")
 7341     # check v->register
 7342     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 7343     (check-strings-equal %eax "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register")
 7344     # check v->type
 7345     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7346     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:0")  # Type-tree-is-atom
 7347     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1")  # Type-tree-value
 7348     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:2")  # Type-tree-right
 7349 $test-function-header-with-multiple-args-and-outputs:out1:
 7350     # outputs = lookup(outputs->next)
 7351     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 7352     89/<- %edx 0/r32/eax
 7353     # v = lookup(inouts->value)
 7354     (lookup *edx *(edx+4))  # List-value List-value => eax
 7355     89/<- %ebx 0/r32/eax
 7356     # check v->name
 7357     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7358     (check-strings-equal %eax "y" "F - test-function-header-with-multiple-args-and-outputs/output:1")
 7359     # check v->register
 7360     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 7361     (check-strings-equal %eax "edx" "F - test-function-header-with-multiple-args-and-outputs/output:1/register")
 7362     # check v->type
 7363     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7364     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:0")  # Type-tree-is-atom
 7365     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1")  # Type-tree-value
 7366     (check-ints-equal *(eax+0c) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:2")  # Type-tree-right
 7367     # . epilogue
 7368     89/<- %esp 5/r32/ebp
 7369     5d/pop-to-ebp
 7370     c3/return
 7371 
 7372 # format for variables with types
 7373 #   x: int
 7374 #   x: int,
 7375 #   x/eax: int
 7376 #   x/eax: int,
 7377 # ignores at most one trailing comma
 7378 # WARNING: modifies name
 7379 parse-var-with-type:  # name: (addr slice), first-line: (addr stream byte), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 7380     # pseudocode:
 7381     #   var s: slice
 7382     #   if (!slice-ends-with(name, ":"))
 7383     #     abort
 7384     #   --name->end to skip ':'
 7385     #   next-token-from-slice(name->start, name->end, '/', s)
 7386     #   new-var-from-slice(s, out)
 7387     #   ## register
 7388     #   next-token-from-slice(s->end, name->end, '/', s)
 7389     #   if (!slice-empty?(s))
 7390     #     out->register = slice-to-string(s)
 7391     #   ## type
 7392     #   var type: (handle type-tree) = parse-type(first-line)
 7393     #   out->type = type
 7394     #
 7395     # . prologue
 7396     55/push-ebp
 7397     89/<- %ebp 4/r32/esp
 7398     # . save registers
 7399     50/push-eax
 7400     51/push-ecx
 7401     52/push-edx
 7402     53/push-ebx
 7403     56/push-esi
 7404     57/push-edi
 7405     # esi = name
 7406     8b/-> *(ebp+8) 6/r32/esi
 7407     # if (!slice-ends-with?(name, ":")) abort
 7408     8b/-> *(esi+4) 1/r32/ecx  # Slice-end
 7409     49/decrement-ecx
 7410     8a/copy-byte *ecx 1/r32/CL
 7411     81 4/subop/and %ecx 0xff/imm32
 7412     81 7/subop/compare %ecx 0x3a/imm32/colon
 7413     0f 85/jump-if-!= $parse-var-with-type:abort/disp32
 7414     # --name->end to skip ':'
 7415     ff 1/subop/decrement *(esi+4)
 7416     # var s/ecx: slice
 7417     68/push 0/imm32/end
 7418     68/push 0/imm32/start
 7419     89/<- %ecx 4/r32/esp
 7420 $parse-var-with-type:parse-name:
 7421     (next-token-from-slice *esi *(esi+4) 0x2f %ecx)  # Slice-start, Slice-end, '/'
 7422 $parse-var-with-type:create-var:
 7423     # new-var-from-slice(s, out)
 7424     (new-var-from-slice Heap %ecx *(ebp+0x10))
 7425     # save out->register
 7426 $parse-var-with-type:save-register:
 7427     # . var out-addr/edi: (addr var) = lookup(*out)
 7428     8b/-> *(ebp+0x10) 7/r32/edi
 7429     (lookup *edi *(edi+4))  # => eax
 7430     89/<- %edi 0/r32/eax
 7431     # . s = next-token(...)
 7432     (next-token-from-slice *(ecx+4) *(esi+4) 0x2f %ecx)  # s->end, name->end, '/'
 7433     # . if (!slice-empty?(s)) out->register = slice-to-string(s)
 7434     {
 7435 $parse-var-with-type:write-register:
 7436       (slice-empty? %ecx)  # => eax
 7437       3d/compare-eax-and 0/imm32/false
 7438       75/jump-if-!= break/disp8
 7439       # out->register = slice-to-string(s)
 7440       8d/copy-address *(edi+0x18) 0/r32/eax  # Var-register
 7441       (slice-to-string Heap %ecx %eax)
 7442     }
 7443 $parse-var-with-type:save-type:
 7444     8d/copy-address *(edi+8) 0/r32/eax  # Var-type
 7445     (parse-type Heap *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 7446 $parse-var-with-type:end:
 7447     # . reclaim locals
 7448     81 0/subop/add %esp 8/imm32
 7449     # . restore registers
 7450     5f/pop-to-edi
 7451     5e/pop-to-esi
 7452     5b/pop-to-ebx
 7453     5a/pop-to-edx
 7454     59/pop-to-ecx
 7455     58/pop-to-eax
 7456     # . epilogue
 7457     89/<- %esp 5/r32/ebp
 7458     5d/pop-to-ebp
 7459     c3/return
 7460 
 7461 $parse-var-with-type:abort:
 7462     # error("var should have form 'name: type' in '" line "'\n")
 7463     (write-buffered *(ebp+0x14) "var should have form 'name: type' in '")
 7464     (flush *(ebp+0x14))
 7465     (rewind-stream *(ebp+0xc))
 7466     (write-stream-data *(ebp+0x14) *(ebp+0xc))
 7467     (write-buffered *(ebp+0x14) "'\n")
 7468     (flush *(ebp+0x14))
 7469     (stop *(ebp+0x18) 1)
 7470     # never gets here
 7471 
 7472 parse-type:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
 7473     # pseudocode:
 7474     #   var s: slice = next-mu-token(in)
 7475     #   assert s != ""
 7476     #   assert s != "->"
 7477     #   assert s != "{"
 7478     #   assert s != "}"
 7479     #   if s == ")"
 7480     #     return
 7481     #   out = allocate(Type-tree)
 7482     #   if s != "("
 7483     #     HACK: if s is an int, parse and return it
 7484     #     out->is-atom? = true
 7485     #     if (s[0] == "_")
 7486     #       out->value = type-parameter
 7487     #       out->parameter-name = slice-to-string(ad, s)
 7488     #     else
 7489     #       out->value = pos-or-insert-slice(Type-id, s)
 7490     #     return
 7491     #   out->left = parse-type(ad, in)
 7492     #   out->right = parse-type-tree(ad, in)
 7493     #
 7494     # . prologue
 7495     55/push-ebp
 7496     89/<- %ebp 4/r32/esp
 7497     # . save registers
 7498     50/push-eax
 7499     51/push-ecx
 7500     52/push-edx
 7501     # clear out
 7502     (zero-out *(ebp+0x10) *Handle-size)
 7503     # var s/ecx: slice
 7504     68/push 0/imm32
 7505     68/push 0/imm32
 7506     89/<- %ecx 4/r32/esp
 7507     # s = next-mu-token(in)
 7508     (next-mu-token *(ebp+0xc) %ecx)
 7509 #?     (write-buffered Stderr "tok: ")
 7510 #?     (write-slice-buffered Stderr %ecx)
 7511 #?     (write-buffered Stderr "$\n")
 7512 #?     (flush Stderr)
 7513     # assert s != ""
 7514     (slice-equal? %ecx "")  # => eax
 7515     3d/compare-eax-and 0/imm32/false
 7516     0f 85/jump-if-!= $parse-type:abort/disp32
 7517     # assert s != "{"
 7518     (slice-equal? %ecx "{")  # => eax
 7519     3d/compare-eax-and 0/imm32/false
 7520     0f 85/jump-if-!= $parse-type:abort/disp32
 7521     # assert s != "}"
 7522     (slice-equal? %ecx "}")  # => eax
 7523     3d/compare-eax-and 0/imm32/false
 7524     0f 85/jump-if-!= $parse-type:abort/disp32
 7525     # assert s != "->"
 7526     (slice-equal? %ecx "->")  # => eax
 7527     3d/compare-eax-and 0/imm32/false
 7528     0f 85/jump-if-!= $parse-type:abort/disp32
 7529     # if (s == ")") return
 7530     (slice-equal? %ecx ")")  # => eax
 7531     3d/compare-eax-and 0/imm32/false
 7532     0f 85/jump-if-!= $parse-type:end/disp32
 7533     # out = new tree
 7534     (allocate *(ebp+8) *Type-tree-size *(ebp+0x10))
 7535     # var out-addr/edx: (addr type-tree) = lookup(*out)
 7536     8b/-> *(ebp+0x10) 2/r32/edx
 7537     (lookup *edx *(edx+4))  # => eax
 7538     89/<- %edx 0/r32/eax
 7539     {
 7540       # if (s != "(") break
 7541       (slice-equal? %ecx "(")  # => eax
 7542       3d/compare-eax-and 0/imm32/false
 7543       0f 85/jump-if-!= break/disp32
 7544       # if s is a number, store it in the type's size field
 7545       {
 7546 $parse-type:check-for-int:
 7547         # var tmp/eax: byte = *s->slice
 7548         8b/-> *ecx 0/r32/eax
 7549         8a/copy-byte *eax 0/r32/AL
 7550         81 4/subop/and %eax 0xff/imm32
 7551         # TODO: raise an error on `var x: (array int a)`
 7552         (is-decimal-digit? %eax)  # => eax
 7553         3d/compare-eax-and 0/imm32/false
 7554         74/jump-if-= break/disp8
 7555         #
 7556         (is-hex-int? %ecx)  # => eax
 7557         3d/compare-eax-and 0/imm32/false
 7558         74/jump-if-= break/disp8
 7559 $parse-type:int:
 7560         (check-mu-hex-int %ecx *(ebp+0x14) *(ebp+0x18))
 7561         (parse-hex-int-from-slice %ecx)  # => eax
 7562         c7 0/subop/copy *(edx+4) 9/imm32/type-id-array-capacity  # Type-tree-value
 7563         89/<- *(edx+8) 0/r32/eax  # Type-tree-value-size
 7564         e9/jump $parse-type:end/disp32
 7565       }
 7566 $parse-type:atom:
 7567       # out->is-atom? = true
 7568       c7 0/subop/copy *edx 1/imm32/true  # Type-tree-is-atom
 7569       {
 7570 $parse-type:check-for-type-parameter:
 7571         # var tmp/eax: byte = *s->slice
 7572         8b/-> *ecx 0/r32/eax
 7573         8a/copy-byte *eax 0/r32/AL
 7574         81 4/subop/and %eax 0xff/imm32
 7575         # if (tmp != '_') break
 7576         3d/compare-eax-and 0x5f/imm32/_
 7577         75/jump-if-!= break/disp8
 7578 $parse-type:type-parameter:
 7579         # out->value = type-parameter
 7580         c7 0/subop/copy *(edx+4) 0xa/imm32/type-parameter  # Type-tree-value
 7581         # out->parameter-name = slice-to-string(ad, s)
 7582         8d/copy-address *(edx+8) 0/r32/eax  # Type-tree-parameter-name
 7583         (slice-to-string *(ebp+8) %ecx %eax)
 7584         e9/jump $parse-type:end/disp32
 7585       }
 7586 $parse-type:non-type-parameter:
 7587       # out->value = pos-or-insert-slice(Type-id, s)
 7588       (pos-or-insert-slice Type-id %ecx)  # => eax
 7589       89/<- *(edx+4) 0/r32/eax  # Type-tree-value
 7590       e9/jump $parse-type:end/disp32
 7591     }
 7592 $parse-type:non-atom:
 7593     # otherwise s == "("
 7594     # out->left = parse-type(ad, in)
 7595     8d/copy-address *(edx+4) 0/r32/eax  # Type-tree-left
 7596     (parse-type *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 7597     # out->right = parse-type-tree(ad, in)
 7598     8d/copy-address *(edx+0xc) 0/r32/eax  # Type-tree-right
 7599     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 7600 $parse-type:end:
 7601     # . reclaim locals
 7602     81 0/subop/add %esp 8/imm32
 7603     # . restore registers
 7604     5a/pop-to-edx
 7605     59/pop-to-ecx
 7606     58/pop-to-eax
 7607     # . epilogue
 7608     89/<- %esp 5/r32/ebp
 7609     5d/pop-to-ebp
 7610     c3/return
 7611 
 7612 $parse-type:abort:
 7613     # error("unexpected token when parsing type: '" s "'\n")
 7614     (write-buffered *(ebp+0x14) "unexpected token when parsing type: '")
 7615     (write-slice-buffered *(ebp+0x14) %ecx)
 7616     (write-buffered *(ebp+0x14) "'\n")
 7617     (flush *(ebp+0x14))
 7618     (stop *(ebp+0x18) 1)
 7619     # never gets here
 7620 
 7621 parse-type-tree:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
 7622     # pseudocode:
 7623     #   var tmp: (handle type-tree) = parse-type(ad, in)
 7624     #   if tmp == 0
 7625     #     return 0
 7626     #   out = allocate(Type-tree)
 7627     #   out->left = tmp
 7628     #   out->right = parse-type-tree(ad, in)
 7629     #
 7630     # . prologue
 7631     55/push-ebp
 7632     89/<- %ebp 4/r32/esp
 7633     # . save registers
 7634     50/push-eax
 7635     51/push-ecx
 7636     52/push-edx
 7637     #
 7638     (zero-out *(ebp+0x10) *Handle-size)
 7639     # var tmp/ecx: (handle type-tree)
 7640     68/push 0/imm32
 7641     68/push 0/imm32
 7642     89/<- %ecx 4/r32/esp
 7643     # tmp = parse-type(ad, in)
 7644     (parse-type *(ebp+8) *(ebp+0xc) %ecx *(ebp+0x14) *(ebp+0x18))
 7645     # if (tmp == 0) return
 7646     81 7/subop/compare *ecx 0/imm32
 7647     74/jump-if-= $parse-type-tree:end/disp8
 7648     # out = new tree
 7649     (allocate *(ebp+8) *Type-tree-size *(ebp+0x10))
 7650     # var out-addr/edx: (addr tree) = lookup(*out)
 7651     8b/-> *(ebp+0x10) 2/r32/edx
 7652     (lookup *edx *(edx+4))  # => eax
 7653     89/<- %edx 0/r32/eax
 7654     # out->left = tmp
 7655     8b/-> *ecx 0/r32/eax
 7656     89/<- *(edx+4) 0/r32/eax  # Type-tree-left
 7657     8b/-> *(ecx+4) 0/r32/eax
 7658     89/<- *(edx+8) 0/r32/eax  # Type-tree-left
 7659     # out->right = parse-type-tree(ad, in)
 7660     8d/copy-address *(edx+0xc) 0/r32/eax  # Type-tree-right
 7661     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 7662 $parse-type-tree:end:
 7663     # . reclaim locals
 7664     81 0/subop/add %esp 8/imm32
 7665     # . restore registers
 7666     5a/pop-to-edx
 7667     59/pop-to-ecx
 7668     58/pop-to-eax
 7669     # . epilogue
 7670     89/<- %esp 5/r32/ebp
 7671     5d/pop-to-ebp
 7672     c3/return
 7673 
 7674 next-mu-token:  # in: (addr stream byte), out: (addr slice)
 7675     # pseudocode:
 7676     # start:
 7677     #   skip-chars-matching-whitespace(in)
 7678     #   if in->read >= in->write              # end of in
 7679     #     out = {0, 0}
 7680     #     return
 7681     #   out->start = &in->data[in->read]
 7682     #   var curr-byte/eax: byte = in->data[in->read]
 7683     #   if curr->byte == ','                  # comment token
 7684     #     ++in->read
 7685     #     goto start
 7686     #   if curr-byte == '#'                   # comment
 7687     #     goto done                             # treat as eof
 7688     #   if curr-byte == '"'                   # string literal
 7689     #     skip-string(in)
 7690     #     goto done                           # no metadata
 7691     #   if curr-byte == '('
 7692     #     ++in->read
 7693     #     goto done
 7694     #   if curr-byte == ')'
 7695     #     ++in->read
 7696     #     goto done
 7697     #   # read a word
 7698     #   while true
 7699     #     if in->read >= in->write
 7700     #       break
 7701     #     curr-byte = in->data[in->read]
 7702     #     if curr-byte == ' '
 7703     #       break
 7704     #     if curr-byte == '\r'
 7705     #       break
 7706     #     if curr-byte == '\n'
 7707     #       break
 7708     #     if curr-byte == '('
 7709     #       break
 7710     #     if curr-byte == ')'
 7711     #       break
 7712     #     if curr-byte == ','
 7713     #       break
 7714     #     ++in->read
 7715     # done:
 7716     #   out->end = &in->data[in->read]
 7717     #
 7718     # . prologue
 7719     55/push-ebp
 7720     89/<- %ebp 4/r32/esp
 7721     # . save registers
 7722     50/push-eax
 7723     51/push-ecx
 7724     56/push-esi
 7725     57/push-edi
 7726     # esi = in
 7727     8b/-> *(ebp+8) 6/r32/esi
 7728     # edi = out
 7729     8b/-> *(ebp+0xc) 7/r32/edi
 7730 $next-mu-token:start:
 7731     (skip-chars-matching-whitespace %esi)
 7732 $next-mu-token:check0:
 7733     # if (in->read >= in->write) return out = {0, 0}
 7734     # . ecx = in->read
 7735     8b/-> *(esi+4) 1/r32/ecx
 7736     # . if (ecx >= in->write) return out = {0, 0}
 7737     3b/compare<- *esi 1/r32/ecx
 7738     c7 0/subop/copy *edi 0/imm32
 7739     c7 0/subop/copy *(edi+4) 0/imm32
 7740     0f 8d/jump-if->= $next-mu-token:end/disp32
 7741     # out->start = &in->data[in->read]
 7742     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 7743     89/<- *edi 0/r32/eax
 7744     # var curr-byte/eax: byte = in->data[in->read]
 7745     31/xor-with %eax 0/r32/eax
 7746     8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 7747     {
 7748 $next-mu-token:check-for-comma:
 7749       # if (curr-byte != ',') break
 7750       3d/compare-eax-and 0x2c/imm32/comma
 7751       75/jump-if-!= break/disp8
 7752       # ++in->read
 7753       ff 0/subop/increment *(esi+4)
 7754       # restart
 7755       e9/jump $next-mu-token:start/disp32
 7756     }
 7757     {
 7758 $next-mu-token:check-for-comment:
 7759       # if (curr-byte != '#') break
 7760       3d/compare-eax-and 0x23/imm32/pound
 7761       75/jump-if-!= break/disp8
 7762       # return eof
 7763       e9/jump $next-mu-token:done/disp32
 7764     }
 7765     {
 7766 $next-mu-token:check-for-string-literal:
 7767       # if (curr-byte != '"') break
 7768       3d/compare-eax-and 0x22/imm32/dquote
 7769       75/jump-if-!= break/disp8
 7770       (skip-string %esi)
 7771       # return
 7772       e9/jump $next-mu-token:done/disp32
 7773     }
 7774     {
 7775 $next-mu-token:check-for-open-paren:
 7776       # if (curr-byte != '(') break
 7777       3d/compare-eax-and 0x28/imm32/open-paren
 7778       75/jump-if-!= break/disp8
 7779       # ++in->read
 7780       ff 0/subop/increment *(esi+4)
 7781       # return
 7782       e9/jump $next-mu-token:done/disp32
 7783     }
 7784     {
 7785 $next-mu-token:check-for-close-paren:
 7786       # if (curr-byte != ')') break
 7787       3d/compare-eax-and 0x29/imm32/close-paren
 7788       75/jump-if-!= break/disp8
 7789       # ++in->read
 7790       ff 0/subop/increment *(esi+4)
 7791       # return
 7792       e9/jump $next-mu-token:done/disp32
 7793     }
 7794     {
 7795 $next-mu-token:regular-word-without-metadata:
 7796       # if (in->read >= in->write) break
 7797       # . ecx = in->read
 7798       8b/-> *(esi+4) 1/r32/ecx
 7799       # . if (ecx >= in->write) break
 7800       3b/compare<- *esi 1/r32/ecx
 7801       7d/jump-if->= break/disp8
 7802       # var c/eax: byte = in->data[in->read]
 7803       31/xor-with %eax 0/r32/eax
 7804       8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 7805       # if (c == ' ') break
 7806       3d/compare-eax-and 0x20/imm32/space
 7807       74/jump-if-= break/disp8
 7808       # if (c == '\r') break
 7809       3d/compare-eax-and 0xd/imm32/carriage-return
 7810       74/jump-if-= break/disp8
 7811       # if (c == '\n') break
 7812       3d/compare-eax-and 0xa/imm32/newline
 7813       74/jump-if-= break/disp8
 7814       # if (c == '(') break
 7815       3d/compare-eax-and 0x28/imm32/open-paren
 7816       0f 84/jump-if-= break/disp32
 7817       # if (c == ')') break
 7818       3d/compare-eax-and 0x29/imm32/close-paren
 7819       0f 84/jump-if-= break/disp32
 7820       # if (c == ',') break
 7821       3d/compare-eax-and 0x2c/imm32/comma
 7822       0f 84/jump-if-= break/disp32
 7823       # ++in->read
 7824       ff 0/subop/increment *(esi+4)
 7825       #
 7826       e9/jump loop/disp32
 7827     }
 7828 $next-mu-token:done:
 7829     # out->end = &in->data[in->read]
 7830     8b/-> *(esi+4) 1/r32/ecx
 7831     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 7832     89/<- *(edi+4) 0/r32/eax
 7833 $next-mu-token:end:
 7834     # . restore registers
 7835     5f/pop-to-edi
 7836     5e/pop-to-esi
 7837     59/pop-to-ecx
 7838     58/pop-to-eax
 7839     # . epilogue
 7840     89/<- %esp 5/r32/ebp
 7841     5d/pop-to-ebp
 7842     c3/return
 7843 
 7844 pos-or-insert-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 7845     # . prologue
 7846     55/push-ebp
 7847     89/<- %ebp 4/r32/esp
 7848     # if (pos-slice(arr, s) != -1) return it
 7849     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 7850     3d/compare-eax-and -1/imm32
 7851     75/jump-if-!= $pos-or-insert-slice:end/disp8
 7852 $pos-or-insert-slice:insert:
 7853     # var s2/eax: (handle array byte)
 7854     68/push 0/imm32
 7855     68/push 0/imm32
 7856     89/<- %eax 4/r32/esp
 7857     (slice-to-string Heap *(ebp+0xc) %eax)
 7858     # throw away alloc-id
 7859     (lookup *eax *(eax+4))  # => eax
 7860     (write-int *(ebp+8) %eax)
 7861     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 7862 $pos-or-insert-slice:end:
 7863     # . reclaim locals
 7864     81 0/subop/add %esp 8/imm32
 7865     # . epilogue
 7866     89/<- %esp 5/r32/ebp
 7867     5d/pop-to-ebp
 7868     c3/return
 7869 
 7870 # return the index in an array of strings matching 's', -1 if not found
 7871 # index is denominated in elements, not bytes
 7872 pos-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 7873     # . prologue
 7874     55/push-ebp
 7875     89/<- %ebp 4/r32/esp
 7876     # . save registers
 7877     51/push-ecx
 7878     52/push-edx
 7879     53/push-ebx
 7880     56/push-esi
 7881 #?     (write-buffered Stderr "pos-slice: ")
 7882 #?     (write-slice-buffered Stderr *(ebp+0xc))
 7883 #?     (write-buffered Stderr "\n")
 7884 #?     (flush Stderr)
 7885     # esi = arr
 7886     8b/-> *(ebp+8) 6/r32/esi
 7887     # var index/ecx: int = 0
 7888     b9/copy-to-ecx 0/imm32
 7889     # var curr/edx: (addr (addr array byte)) = arr->data
 7890     8d/copy-address *(esi+0xc) 2/r32/edx
 7891     # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write]
 7892     8b/-> *esi 3/r32/ebx
 7893     8d/copy-address *(esi+ebx+0xc) 3/r32/ebx
 7894     {
 7895 #?       (write-buffered Stderr "  ")
 7896 #?       (write-int32-hex-buffered Stderr %ecx)
 7897 #?       (write-buffered Stderr "\n")
 7898 #?       (flush Stderr)
 7899       # if (curr >= max) return -1
 7900       39/compare %edx 3/r32/ebx
 7901       b8/copy-to-eax -1/imm32
 7902       73/jump-if-addr>= $pos-slice:end/disp8
 7903       # if (slice-equal?(s, *curr)) break
 7904       (slice-equal? *(ebp+0xc) *edx)  # => eax
 7905       3d/compare-eax-and 0/imm32/false
 7906       75/jump-if-!= break/disp8
 7907       # ++index
 7908       41/increment-ecx
 7909       # curr += 4
 7910       81 0/subop/add %edx 4/imm32
 7911       #
 7912       eb/jump loop/disp8
 7913     }
 7914     # return index
 7915     89/<- %eax 1/r32/ecx
 7916 $pos-slice:end:
 7917 #?     (write-buffered Stderr "=> ")
 7918 #?     (write-int32-hex-buffered Stderr %eax)
 7919 #?     (write-buffered Stderr "\n")
 7920     # . restore registers
 7921     5e/pop-to-esi
 7922     5b/pop-to-ebx
 7923     5a/pop-to-edx
 7924     59/pop-to-ecx
 7925     # . epilogue
 7926     89/<- %esp 5/r32/ebp
 7927     5d/pop-to-ebp
 7928     c3/return
 7929 
 7930 test-parse-var-with-type:
 7931     # . prologue
 7932     55/push-ebp
 7933     89/<- %ebp 4/r32/esp
 7934     # (eax..ecx) = "x:"
 7935     b8/copy-to-eax "x:"/imm32
 7936     8b/-> *eax 1/r32/ecx
 7937     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7938     05/add-to-eax 4/imm32
 7939     # var slice/ecx: slice = {eax, ecx}
 7940     51/push-ecx
 7941     50/push-eax
 7942     89/<- %ecx 4/r32/esp
 7943     # _test-input-stream contains "int"
 7944     (clear-stream _test-input-stream)
 7945     (write _test-input-stream "int")
 7946     # var v/edx: (handle var)
 7947     68/push 0/imm32
 7948     68/push 0/imm32
 7949     89/<- %edx 4/r32/esp
 7950     #
 7951     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 7952     # var v-addr/edx: (addr var) = lookup(v)
 7953     (lookup *edx *(edx+4))  # => eax
 7954     89/<- %edx 0/r32/eax
 7955     # check v-addr->name
 7956     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 7957     (check-strings-equal %eax "x" "F - test-parse-var-with-type/name")
 7958     # check v-addr->type
 7959     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 7960     (check-ints-equal *eax 1 "F - test-parse-var-with-type/type:0")  # Type-tree-is-atom
 7961     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type/type:1")  # Type-tree-value
 7962     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type/type:2")  # Type-tree-right
 7963     # . epilogue
 7964     89/<- %esp 5/r32/ebp
 7965     5d/pop-to-ebp
 7966     c3/return
 7967 
 7968 test-parse-var-with-type-and-register:
 7969     # . prologue
 7970     55/push-ebp
 7971     89/<- %ebp 4/r32/esp
 7972     # (eax..ecx) = "x/eax:"
 7973     b8/copy-to-eax "x/eax:"/imm32
 7974     8b/-> *eax 1/r32/ecx
 7975     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7976     05/add-to-eax 4/imm32
 7977     # var slice/ecx: slice = {eax, ecx}
 7978     51/push-ecx
 7979     50/push-eax
 7980     89/<- %ecx 4/r32/esp
 7981     # _test-input-stream contains "int"
 7982     (clear-stream _test-input-stream)
 7983     (write _test-input-stream "int")
 7984     # var v/edx: (handle var)
 7985     68/push 0/imm32
 7986     68/push 0/imm32
 7987     89/<- %edx 4/r32/esp
 7988     #
 7989     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 7990     # var v-addr/edx: (addr var) = lookup(v)
 7991     (lookup *edx *(edx+4))  # => eax
 7992     89/<- %edx 0/r32/eax
 7993     # check v-addr->name
 7994     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 7995     (check-strings-equal %eax "x" "F - test-parse-var-with-type-and-register/name")
 7996     # check v-addr->register
 7997     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 7998     (check-strings-equal %eax "eax" "F - test-parse-var-with-type-and-register/register")
 7999     # check v-addr->type
 8000     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8001     (check-ints-equal *eax 1 "F - test-parse-var-with-type-and-register/type:0")  # Type-tree-is-atom
 8002     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type-and-register/type:1")  # Type-tree-left
 8003     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type-and-register/type:2")  # Type-tree-right
 8004     # . epilogue
 8005     89/<- %esp 5/r32/ebp
 8006     5d/pop-to-ebp
 8007     c3/return
 8008 
 8009 test-parse-var-with-trailing-characters:
 8010     # . prologue
 8011     55/push-ebp
 8012     89/<- %ebp 4/r32/esp
 8013     # (eax..ecx) = "x:"
 8014     b8/copy-to-eax "x:"/imm32
 8015     8b/-> *eax 1/r32/ecx
 8016     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8017     05/add-to-eax 4/imm32
 8018     # var slice/ecx: slice = {eax, ecx}
 8019     51/push-ecx
 8020     50/push-eax
 8021     89/<- %ecx 4/r32/esp
 8022     # _test-input-stream contains "int,"
 8023     (clear-stream _test-input-stream)
 8024     (write _test-input-stream "int,")
 8025     # var v/edx: (handle var)
 8026     68/push 0/imm32
 8027     68/push 0/imm32
 8028     89/<- %edx 4/r32/esp
 8029     #
 8030     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 8031     # var v-addr/edx: (addr var) = lookup(v)
 8032     (lookup *edx *(edx+4))  # => eax
 8033     89/<- %edx 0/r32/eax
 8034     # check v-addr->name
 8035     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8036     (check-strings-equal %eax "x" "F - test-parse-var-with-trailing-characters/name")
 8037     # check v-addr->register
 8038     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-trailing-characters/register")  # Var-register
 8039     # check v-addr->type
 8040     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8041     (check-ints-equal *eax 1 "F - test-parse-var-with-trailing-characters/type:0")  # Type-tree-is-atom
 8042     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-trailing-characters/type:1")  # Type-tree-left
 8043     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-trailing-characters/type:1")  # Type-tree-right
 8044     # . epilogue
 8045     89/<- %esp 5/r32/ebp
 8046     5d/pop-to-ebp
 8047     c3/return
 8048 
 8049 test-parse-var-with-register-and-trailing-characters:
 8050     # . prologue
 8051     55/push-ebp
 8052     89/<- %ebp 4/r32/esp
 8053     # (eax..ecx) = "x/eax:"
 8054     b8/copy-to-eax "x/eax:"/imm32
 8055     8b/-> *eax 1/r32/ecx
 8056     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8057     05/add-to-eax 4/imm32
 8058     # var slice/ecx: slice = {eax, ecx}
 8059     51/push-ecx
 8060     50/push-eax
 8061     89/<- %ecx 4/r32/esp
 8062     # _test-input-stream contains "int,"
 8063     (clear-stream _test-input-stream)
 8064     (write _test-input-stream "int,")
 8065     # var v/edx: (handle var)
 8066     68/push 0/imm32
 8067     68/push 0/imm32
 8068     89/<- %edx 4/r32/esp
 8069     #
 8070     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 8071     # var v-addr/edx: (addr var) = lookup(v)
 8072     (lookup *edx *(edx+4))  # => eax
 8073     89/<- %edx 0/r32/eax
 8074     # check v-addr->name
 8075     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8076     (check-strings-equal %eax "x" "F - test-parse-var-with-register-and-trailing-characters/name")
 8077     # check v-addr->register
 8078     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 8079     (check-strings-equal %eax "eax" "F - test-parse-var-with-register-and-trailing-characters/register")
 8080     # check v-addr->type
 8081     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8082     (check-ints-equal *eax 1 "F - test-parse-var-with-register-and-trailing-characters/type:0")  # Type-tree-is-atom
 8083     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-register-and-trailing-characters/type:1")  # Type-tree-left
 8084     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-register-and-trailing-characters/type:2")  # Type-tree-right
 8085     # . epilogue
 8086     89/<- %esp 5/r32/ebp
 8087     5d/pop-to-ebp
 8088     c3/return
 8089 
 8090 test-parse-var-with-compound-type:
 8091     # . prologue
 8092     55/push-ebp
 8093     89/<- %ebp 4/r32/esp
 8094     # (eax..ecx) = "x:"
 8095     b8/copy-to-eax "x:"/imm32
 8096     8b/-> *eax 1/r32/ecx
 8097     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8098     05/add-to-eax 4/imm32
 8099     # var slice/ecx: slice = {eax, ecx}
 8100     51/push-ecx
 8101     50/push-eax
 8102     89/<- %ecx 4/r32/esp
 8103     # _test-input-stream contains "(addr int)"
 8104     (clear-stream _test-input-stream)
 8105     (write _test-input-stream "(addr int)")
 8106     # var v/edx: (handle var)
 8107     68/push 0/imm32
 8108     68/push 0/imm32
 8109     89/<- %edx 4/r32/esp
 8110     #
 8111     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 8112     # var v-addr/edx: (addr var) = lookup(v)
 8113     (lookup *edx *(edx+4))  # => eax
 8114     89/<- %edx 0/r32/eax
 8115     # check v-addr->name
 8116     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8117     (check-strings-equal %eax "x" "F - test-parse-var-with-compound-type/name")
 8118     # check v-addr->register
 8119     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-compound-type/register")  # Var-register
 8120     # - check v-addr->type
 8121     # var type/edx: (addr type-tree) = var->type
 8122     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8123     89/<- %edx 0/r32/eax
 8124     # type is a non-atom
 8125     (check-ints-equal *edx 0 "F - test-parse-var-with-compound-type/type:0")  # Type-tree-is-atom
 8126     # type->left == atom(addr)
 8127     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
 8128     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:1")  # Type-tree-is-atom
 8129     (check-ints-equal *(eax+4) 2 "F - test-parse-var-with-compound-type/type:2")  # Type-tree-value
 8130     # type->right->left == atom(int)
 8131     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
 8132     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
 8133     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:3")  # Type-tree-is-atom
 8134     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-compound-type/type:4")  # Type-tree-value
 8135     # type->right->right == null
 8136     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-compound-type/type:5")  # Type-tree-right
 8137     # . epilogue
 8138     89/<- %esp 5/r32/ebp
 8139     5d/pop-to-ebp
 8140     c3/return
 8141 
 8142 # identifier starts with a letter or '$' or '_'
 8143 # no constraints at the moment on later letters
 8144 # all we really want to do so far is exclude '{', '}' and '->'
 8145 is-identifier?:  # in: (addr slice) -> result/eax: boolean
 8146     # . prologue
 8147     55/push-ebp
 8148     89/<- %ebp 4/r32/esp
 8149     # if (slice-empty?(in)) return false
 8150     (slice-empty? *(ebp+8))  # => eax
 8151     3d/compare-eax-and 0/imm32/false
 8152     75/jump-if-!= $is-identifier?:false/disp8
 8153     # var c/eax: byte = *in->start
 8154     8b/-> *(ebp+8) 0/r32/eax
 8155     8b/-> *eax 0/r32/eax
 8156     8a/copy-byte *eax 0/r32/AL
 8157     81 4/subop/and %eax 0xff/imm32
 8158     # if (c == '$') return true
 8159     3d/compare-eax-and 0x24/imm32/$
 8160     74/jump-if-= $is-identifier?:true/disp8
 8161     # if (c == '_') return true
 8162     3d/compare-eax-and 0x5f/imm32/_
 8163     74/jump-if-= $is-identifier?:true/disp8
 8164     # drop case
 8165     25/and-eax-with 0x5f/imm32
 8166     # if (c < 'A') return false
 8167     3d/compare-eax-and 0x41/imm32/A
 8168     7c/jump-if-< $is-identifier?:false/disp8
 8169     # if (c > 'Z') return false
 8170     3d/compare-eax-and 0x5a/imm32/Z
 8171     7f/jump-if-> $is-identifier?:false/disp8
 8172     # otherwise return true
 8173 $is-identifier?:true:
 8174     b8/copy-to-eax 1/imm32/true
 8175     eb/jump $is-identifier?:end/disp8
 8176 $is-identifier?:false:
 8177     b8/copy-to-eax 0/imm32/false
 8178 $is-identifier?:end:
 8179     # . epilogue
 8180     89/<- %esp 5/r32/ebp
 8181     5d/pop-to-ebp
 8182     c3/return
 8183 
 8184 test-is-identifier-dollar:
 8185     # . prologue
 8186     55/push-ebp
 8187     89/<- %ebp 4/r32/esp
 8188     # (eax..ecx) = "$a"
 8189     b8/copy-to-eax "$a"/imm32
 8190     8b/-> *eax 1/r32/ecx
 8191     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8192     05/add-to-eax 4/imm32
 8193     # var slice/ecx: slice = {eax, ecx}
 8194     51/push-ecx
 8195     50/push-eax
 8196     89/<- %ecx 4/r32/esp
 8197     #
 8198     (is-identifier? %ecx)
 8199     (check-ints-equal %eax 1 "F - test-is-identifier-dollar")
 8200     # . epilogue
 8201     89/<- %esp 5/r32/ebp
 8202     5d/pop-to-ebp
 8203     c3/return
 8204 
 8205 test-is-identifier-underscore:
 8206     # . prologue
 8207     55/push-ebp
 8208     89/<- %ebp 4/r32/esp
 8209     # (eax..ecx) = "_a"
 8210     b8/copy-to-eax "_a"/imm32
 8211     8b/-> *eax 1/r32/ecx
 8212     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8213     05/add-to-eax 4/imm32
 8214     # var slice/ecx: slice = {eax, ecx}
 8215     51/push-ecx
 8216     50/push-eax
 8217     89/<- %ecx 4/r32/esp
 8218     #
 8219     (is-identifier? %ecx)
 8220     (check-ints-equal %eax 1 "F - test-is-identifier-underscore")
 8221     # . epilogue
 8222     89/<- %esp 5/r32/ebp
 8223     5d/pop-to-ebp
 8224     c3/return
 8225 
 8226 test-is-identifier-a:
 8227     # . prologue
 8228     55/push-ebp
 8229     89/<- %ebp 4/r32/esp
 8230     # (eax..ecx) = "a$"
 8231     b8/copy-to-eax "a$"/imm32
 8232     8b/-> *eax 1/r32/ecx
 8233     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8234     05/add-to-eax 4/imm32
 8235     # var slice/ecx: slice = {eax, ecx}
 8236     51/push-ecx
 8237     50/push-eax
 8238     89/<- %ecx 4/r32/esp
 8239     #
 8240     (is-identifier? %ecx)
 8241     (check-ints-equal %eax 1 "F - test-is-identifier-a")
 8242     # . epilogue
 8243     89/<- %esp 5/r32/ebp
 8244     5d/pop-to-ebp
 8245     c3/return
 8246 
 8247 test-is-identifier-z:
 8248     # . prologue
 8249     55/push-ebp
 8250     89/<- %ebp 4/r32/esp
 8251     # (eax..ecx) = "z$"
 8252     b8/copy-to-eax "z$"/imm32
 8253     8b/-> *eax 1/r32/ecx
 8254     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8255     05/add-to-eax 4/imm32
 8256     # var slice/ecx: slice = {eax, ecx}
 8257     51/push-ecx
 8258     50/push-eax
 8259     89/<- %ecx 4/r32/esp
 8260     #
 8261     (is-identifier? %ecx)
 8262     (check-ints-equal %eax 1 "F - test-is-identifier-z")
 8263     # . epilogue
 8264     89/<- %esp 5/r32/ebp
 8265     5d/pop-to-ebp
 8266     c3/return
 8267 
 8268 test-is-identifier-A:
 8269     # . prologue
 8270     55/push-ebp
 8271     89/<- %ebp 4/r32/esp
 8272     # (eax..ecx) = "A$"
 8273     b8/copy-to-eax "A$"/imm32
 8274     8b/-> *eax 1/r32/ecx
 8275     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8276     05/add-to-eax 4/imm32
 8277     # var slice/ecx: slice = {eax, ecx}
 8278     51/push-ecx
 8279     50/push-eax
 8280     89/<- %ecx 4/r32/esp
 8281     #
 8282     (is-identifier? %ecx)
 8283     (check-ints-equal %eax 1 "F - test-is-identifier-A")
 8284     # . epilogue
 8285     89/<- %esp 5/r32/ebp
 8286     5d/pop-to-ebp
 8287     c3/return
 8288 
 8289 test-is-identifier-Z:
 8290     # . prologue
 8291     55/push-ebp
 8292     89/<- %ebp 4/r32/esp
 8293     # (eax..ecx) = "Z$"
 8294     b8/copy-to-eax "Z$"/imm32
 8295     8b/-> *eax 1/r32/ecx
 8296     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8297     05/add-to-eax 4/imm32
 8298     # var slice/ecx: slice = {eax, ecx}
 8299     51/push-ecx
 8300     50/push-eax
 8301     89/<- %ecx 4/r32/esp
 8302     #
 8303     (is-identifier? %ecx)
 8304     (check-ints-equal %eax 1 "F - test-is-identifier-Z")
 8305     # . epilogue
 8306     89/<- %esp 5/r32/ebp
 8307     5d/pop-to-ebp
 8308     c3/return
 8309 
 8310 test-is-identifier-at:
 8311     # character before 'A' is invalid
 8312     # . prologue
 8313     55/push-ebp
 8314     89/<- %ebp 4/r32/esp
 8315     # (eax..ecx) = "@a"
 8316     b8/copy-to-eax "@a"/imm32
 8317     8b/-> *eax 1/r32/ecx
 8318     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8319     05/add-to-eax 4/imm32
 8320     # var slice/ecx: slice = {eax, ecx}
 8321     51/push-ecx
 8322     50/push-eax
 8323     89/<- %ecx 4/r32/esp
 8324     #
 8325     (is-identifier? %ecx)
 8326     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 8327     # . epilogue
 8328     89/<- %esp 5/r32/ebp
 8329     5d/pop-to-ebp
 8330     c3/return
 8331 
 8332 test-is-identifier-square-bracket:
 8333     # character after 'Z' is invalid
 8334     # . prologue
 8335     55/push-ebp
 8336     89/<- %ebp 4/r32/esp
 8337     # (eax..ecx) = "[a"
 8338     b8/copy-to-eax "[a"/imm32
 8339     8b/-> *eax 1/r32/ecx
 8340     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8341     05/add-to-eax 4/imm32
 8342     # var slice/ecx: slice = {eax, ecx}
 8343     51/push-ecx
 8344     50/push-eax
 8345     89/<- %ecx 4/r32/esp
 8346     #
 8347     (is-identifier? %ecx)
 8348     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 8349     # . epilogue
 8350     89/<- %esp 5/r32/ebp
 8351     5d/pop-to-ebp
 8352     c3/return
 8353 
 8354 test-is-identifier-backtick:
 8355     # character before 'a' is invalid
 8356     # . prologue
 8357     55/push-ebp
 8358     89/<- %ebp 4/r32/esp
 8359     # (eax..ecx) = "`a"
 8360     b8/copy-to-eax "`a"/imm32
 8361     8b/-> *eax 1/r32/ecx
 8362     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8363     05/add-to-eax 4/imm32
 8364     # var slice/ecx: slice = {eax, ecx}
 8365     51/push-ecx
 8366     50/push-eax
 8367     89/<- %ecx 4/r32/esp
 8368     #
 8369     (is-identifier? %ecx)
 8370     (check-ints-equal %eax 0 "F - test-is-identifier-backtick")
 8371     # . epilogue
 8372     89/<- %esp 5/r32/ebp
 8373     5d/pop-to-ebp
 8374     c3/return
 8375 
 8376 test-is-identifier-curly-brace-open:
 8377     # character after 'z' is invalid; also used for blocks
 8378     # . prologue
 8379     55/push-ebp
 8380     89/<- %ebp 4/r32/esp
 8381     # (eax..ecx) = "{a"
 8382     b8/copy-to-eax "{a"/imm32
 8383     8b/-> *eax 1/r32/ecx
 8384     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8385     05/add-to-eax 4/imm32
 8386     # var slice/ecx: slice = {eax, ecx}
 8387     51/push-ecx
 8388     50/push-eax
 8389     89/<- %ecx 4/r32/esp
 8390     #
 8391     (is-identifier? %ecx)
 8392     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open")
 8393     # . epilogue
 8394     89/<- %esp 5/r32/ebp
 8395     5d/pop-to-ebp
 8396     c3/return
 8397 
 8398 test-is-identifier-curly-brace-close:
 8399     # . prologue
 8400     55/push-ebp
 8401     89/<- %ebp 4/r32/esp
 8402     # (eax..ecx) = "}a"
 8403     b8/copy-to-eax "}a"/imm32
 8404     8b/-> *eax 1/r32/ecx
 8405     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8406     05/add-to-eax 4/imm32
 8407     # var slice/ecx: slice = {eax, ecx}
 8408     51/push-ecx
 8409     50/push-eax
 8410     89/<- %ecx 4/r32/esp
 8411     #
 8412     (is-identifier? %ecx)
 8413     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close")
 8414     # . epilogue
 8415     89/<- %esp 5/r32/ebp
 8416     5d/pop-to-ebp
 8417     c3/return
 8418 
 8419 test-is-identifier-hyphen:
 8420     # disallow leading '-' since '->' has special meaning
 8421     # . prologue
 8422     55/push-ebp
 8423     89/<- %ebp 4/r32/esp
 8424     # (eax..ecx) = "-a"
 8425     b8/copy-to-eax "-a"/imm32
 8426     8b/-> *eax 1/r32/ecx
 8427     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8428     05/add-to-eax 4/imm32
 8429     # var slice/ecx: slice = {eax, ecx}
 8430     51/push-ecx
 8431     50/push-eax
 8432     89/<- %ecx 4/r32/esp
 8433     #
 8434     (is-identifier? %ecx)
 8435     (check-ints-equal %eax 0 "F - test-is-identifier-hyphen")
 8436     # . epilogue
 8437     89/<- %esp 5/r32/ebp
 8438     5d/pop-to-ebp
 8439     c3/return
 8440 
 8441 populate-mu-function-body:  # in: (addr buffered-file), out: (addr function), vars: (addr stack live-var), err: (addr buffered-file), ed: (addr exit-descriptor)
 8442     # . prologue
 8443     55/push-ebp
 8444     89/<- %ebp 4/r32/esp
 8445     # . save registers
 8446     50/push-eax
 8447     56/push-esi
 8448     57/push-edi
 8449     # esi = in
 8450     8b/-> *(ebp+8) 6/r32/esi
 8451     # edi = out
 8452     8b/-> *(ebp+0xc) 7/r32/edi
 8453     # initialize some global state
 8454     c7 0/subop/copy *Curr-block-depth 1/imm32
 8455     # parse-mu-block(in, vars, out, out->body)
 8456     8d/copy-address *(edi+0x18) 0/r32/eax  # Function-body
 8457     (parse-mu-block %esi *(ebp+0x10) %edi %eax *(ebp+0x14) *(ebp+0x18))
 8458 $populate-mu-function-body:end:
 8459     # . restore registers
 8460     5f/pop-to-edi
 8461     5e/pop-to-esi
 8462     58/pop-to-eax
 8463     # . epilogue
 8464     89/<- %esp 5/r32/ebp
 8465     5d/pop-to-ebp
 8466     c3/return
 8467 
 8468 # parses a block, assuming that the leading '{' has already been read by the caller
 8469 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)
 8470     # pseudocode:
 8471     #   var line: (stream byte 512)
 8472     #   var word-slice: slice
 8473     #   allocate(Heap, Stmt-size, out)
 8474     #   var out-addr: (addr block) = lookup(*out)
 8475     #   out-addr->tag = 0/block
 8476     #   out-addr->var = some unique name
 8477     #   push(vars, {out-addr->var, false})
 8478     #   while true                                  # line loop
 8479     #     clear-stream(line)
 8480     #     read-line-buffered(in, line)
 8481     #     if (line->write == 0) break               # end of file
 8482     #     word-slice = next-mu-token(line)
 8483     #     if slice-empty?(word-slice)               # end of line
 8484     #       continue
 8485     #     else if slice-starts-with?(word-slice, "#")
 8486     #       continue
 8487     #     else if slice-equal?(word-slice, "{")
 8488     #       assert(no-tokens-in(line))
 8489     #       block = parse-mu-block(in, vars, fn)
 8490     #       append-to-block(out-addr, block)
 8491     #     else if slice-equal?(word-slice, "}")
 8492     #       break
 8493     #     else if slice-ends-with?(word-slice, ":")
 8494     #       # TODO: error-check the rest of 'line'
 8495     #       --word-slice->end to skip ':'
 8496     #       named-block = parse-mu-named-block(word-slice, in, vars, fn)
 8497     #       append-to-block(out-addr, named-block)
 8498     #     else if slice-equal?(word-slice, "var")
 8499     #       var-def = parse-mu-var-def(line, vars, fn)
 8500     #       append-to-block(out-addr, var-def)
 8501     #     else
 8502     #       stmt = parse-mu-stmt(line, vars, fn)
 8503     #       append-to-block(out-addr, stmt)
 8504     #   pop(vars)
 8505     #
 8506     # . prologue
 8507     55/push-ebp
 8508     89/<- %ebp 4/r32/esp
 8509     # . save registers
 8510     50/push-eax
 8511     51/push-ecx
 8512     52/push-edx
 8513     53/push-ebx
 8514     57/push-edi
 8515     # var line/ecx: (stream byte 512)
 8516     81 5/subop/subtract %esp 0x200/imm32
 8517     68/push 0x200/imm32/size
 8518     68/push 0/imm32/read
 8519     68/push 0/imm32/write
 8520     89/<- %ecx 4/r32/esp
 8521     # var word-slice/edx: slice
 8522     68/push 0/imm32/end
 8523     68/push 0/imm32/start
 8524     89/<- %edx 4/r32/esp
 8525     # allocate into out
 8526     (allocate Heap *Stmt-size *(ebp+0x14))
 8527     # var out-addr/edi: (addr block) = lookup(*out)
 8528     8b/-> *(ebp+0x14) 7/r32/edi
 8529     (lookup *edi *(edi+4))  # => eax
 8530     89/<- %edi 0/r32/eax
 8531     # out-addr->tag is 0 (block) by default
 8532     # set out-addr->var
 8533     8d/copy-address *(edi+0xc) 0/r32/eax  # Block-var
 8534     (new-block-name *(ebp+0x10) %eax)
 8535     # push(vars, out-addr->var)
 8536     (push *(ebp+0xc) *(edi+0xc))  # Block-var
 8537     (push *(ebp+0xc) *(edi+0x10))  # Block-var
 8538     (push *(ebp+0xc) 0)  # false
 8539     # increment *Curr-block-depth
 8540     ff 0/subop/increment *Curr-block-depth
 8541     {
 8542 $parse-mu-block:line-loop:
 8543       # line = read-line-buffered(in)
 8544       (clear-stream %ecx)
 8545       (read-line-buffered *(ebp+8) %ecx)
 8546 #?       (write-buffered Stderr "line: ")
 8547 #?       (write-stream-data Stderr %ecx)
 8548 #? #?       (write-buffered Stderr Newline)  # line has its own newline
 8549 #?       (flush Stderr)
 8550 #?       (rewind-stream %ecx)
 8551       # if (line->write == 0) break
 8552       81 7/subop/compare *ecx 0/imm32
 8553       0f 84/jump-if-= break/disp32
 8554 #?       (write-buffered Stderr "vars:\n")
 8555 #?       (dump-vars *(ebp+0xc))
 8556       # word-slice = next-mu-token(line)
 8557       (next-mu-token %ecx %edx)
 8558 #?       (write-buffered Stderr "word: ")
 8559 #?       (write-slice-buffered Stderr %edx)
 8560 #?       (write-buffered Stderr Newline)
 8561 #?       (flush Stderr)
 8562       # if slice-empty?(word-slice) continue
 8563       (slice-empty? %edx)
 8564       3d/compare-eax-and 0/imm32/false
 8565       0f 85/jump-if-!= loop/disp32
 8566       # if (slice-starts-with?(word-slice, '#') continue
 8567       # . eax = *word-slice->start
 8568       8b/-> *edx 0/r32/eax
 8569       8a/copy-byte *eax 0/r32/AL
 8570       81 4/subop/and %eax 0xff/imm32
 8571       # . if (eax == '#') continue
 8572       3d/compare-eax-and 0x23/imm32/hash
 8573       0f 84/jump-if-= loop/disp32
 8574       # if slice-equal?(word-slice, "{")
 8575       {
 8576 $parse-mu-block:check-for-block:
 8577         (slice-equal? %edx "{")
 8578         3d/compare-eax-and 0/imm32/false
 8579         74/jump-if-= break/disp8
 8580         (check-no-tokens-left %ecx)
 8581         # parse new block and append
 8582         # . var tmp/eax: (handle block)
 8583         68/push 0/imm32
 8584         68/push 0/imm32
 8585         89/<- %eax 4/r32/esp
 8586         # .
 8587         (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 8588         (append-to-block Heap %edi  *eax *(eax+4))
 8589         # . reclaim tmp
 8590         81 0/subop/add %esp 8/imm32
 8591         # .
 8592         e9/jump $parse-mu-block:line-loop/disp32
 8593       }
 8594       # if slice-equal?(word-slice, "}") break
 8595 $parse-mu-block:check-for-end:
 8596       (slice-equal? %edx "}")
 8597       3d/compare-eax-and 0/imm32/false
 8598       0f 85/jump-if-!= break/disp32
 8599       # if slice-ends-with?(word-slice, ":") parse named block and append
 8600       {
 8601 $parse-mu-block:check-for-named-block:
 8602         # . eax = *(word-slice->end-1)
 8603         8b/-> *(edx+4) 0/r32/eax
 8604         48/decrement-eax
 8605         8a/copy-byte *eax 0/r32/AL
 8606         81 4/subop/and %eax 0xff/imm32
 8607         # . if (eax != ':') break
 8608         3d/compare-eax-and 0x3a/imm32/colon
 8609         0f 85/jump-if-!= break/disp32
 8610         # TODO: error-check the rest of 'line'
 8611         #
 8612         # skip ':'
 8613         ff 1/subop/decrement *(edx+4)  # Slice-end
 8614         # var tmp/eax: (handle block)
 8615         68/push 0/imm32
 8616         68/push 0/imm32
 8617         89/<- %eax 4/r32/esp
 8618         #
 8619         (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 8620         (append-to-block Heap %edi  *eax *(eax+4))
 8621         # reclaim tmp
 8622         81 0/subop/add %esp 8/imm32
 8623         #
 8624         e9/jump $parse-mu-block:line-loop/disp32
 8625       }
 8626       # if slice-equal?(word-slice, "var")
 8627       {
 8628 $parse-mu-block:check-for-var:
 8629         (slice-equal? %edx "var")
 8630         3d/compare-eax-and 0/imm32/false
 8631         74/jump-if-= break/disp8
 8632         # var tmp/eax: (handle block)
 8633         68/push 0/imm32
 8634         68/push 0/imm32
 8635         89/<- %eax 4/r32/esp
 8636         #
 8637         (parse-mu-var-def %ecx *(ebp+0xc) %eax *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 8638         (append-to-block Heap %edi  *eax *(eax+4))
 8639         # reclaim tmp
 8640         81 0/subop/add %esp 8/imm32
 8641         #
 8642         e9/jump $parse-mu-block:line-loop/disp32
 8643       }
 8644 $parse-mu-block:regular-stmt:
 8645       # otherwise
 8646       # var tmp/eax: (handle block)
 8647       68/push 0/imm32
 8648       68/push 0/imm32
 8649       89/<- %eax 4/r32/esp
 8650       #
 8651       (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 8652       (append-to-block Heap %edi  *eax *(eax+4))
 8653       # reclaim tmp
 8654       81 0/subop/add %esp 8/imm32
 8655       #
 8656       e9/jump loop/disp32
 8657     } # end line loop
 8658     (clean-up-blocks *(ebp+0xc) *Curr-block-depth *(ebp+0x10))
 8659     # decrement *Curr-block-depth
 8660     ff 1/subop/decrement *Curr-block-depth
 8661     # pop(vars)
 8662     (pop *(ebp+0xc))  # => eax
 8663     (pop *(ebp+0xc))  # => eax
 8664     (pop *(ebp+0xc))  # => eax
 8665 $parse-mu-block:end:
 8666     # . reclaim locals
 8667     81 0/subop/add %esp 0x214/imm32
 8668     # . restore registers
 8669     5f/pop-to-edi
 8670     5b/pop-to-ebx
 8671     5a/pop-to-edx
 8672     59/pop-to-ecx
 8673     58/pop-to-eax
 8674     # . epilogue
 8675     89/<- %esp 5/r32/ebp
 8676     5d/pop-to-ebp
 8677     c3/return
 8678 
 8679 $parse-mu-block:abort:
 8680     # error("'{' or '}' should be on its own line, but got '")
 8681     (write-buffered *(ebp+0x18) "'{' or '}' should be on its own line, but got '")
 8682     (rewind-stream %ecx)
 8683     (write-stream-data *(ebp+0x18) %ecx)
 8684     (write-buffered *(ebp+0x18) "'\n")
 8685     (flush *(ebp+0x18))
 8686     (stop *(ebp+0x1c) 1)
 8687     # never gets here
 8688 
 8689 new-block-name:  # fn: (addr function), out: (addr handle var)
 8690     # . prologue
 8691     55/push-ebp
 8692     89/<- %ebp 4/r32/esp
 8693     # . save registers
 8694     50/push-eax
 8695     51/push-ecx
 8696     52/push-edx
 8697     # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:'
 8698     8b/-> *(ebp+8) 0/r32/eax
 8699     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8700     8b/-> *eax 0/r32/eax  # String-size
 8701     05/add-to-eax 0xd/imm32  # 10 + 2 for '$:'
 8702     89/<- %ecx 0/r32/eax
 8703     # var name/edx: (stream byte n)
 8704     29/subtract-from %esp 1/r32/ecx
 8705     ff 6/subop/push %ecx
 8706     68/push 0/imm32/read
 8707     68/push 0/imm32/write
 8708     89/<- %edx 4/r32/esp
 8709     (clear-stream %edx)
 8710     # eax = fn->name
 8711     8b/-> *(ebp+8) 0/r32/eax
 8712     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8713     # construct result using Next-block-index (and increment it)
 8714     (write %edx "$")
 8715     (write %edx %eax)
 8716     (write %edx ":")
 8717     (write-int32-hex %edx *Next-block-index)
 8718     ff 0/subop/increment *Next-block-index
 8719     # var s/eax: slice = {name->data, name->data + name->write}  (clobbering edx)
 8720     # . eax = name->write
 8721     8b/-> *edx 0/r32/eax
 8722     # . edx = name->data
 8723     8d/copy-address *(edx+0xc) 2/r32/edx
 8724     # . eax = name->write + name->data
 8725     01/add-to %eax 2/r32/edx
 8726     # . push {edx, eax}
 8727     ff 6/subop/push %eax
 8728     ff 6/subop/push %edx
 8729     89/<- %eax 4/r32/esp
 8730     # out = new literal(s)
 8731     (new-literal Heap %eax *(ebp+0xc))
 8732 #?     8b/-> *(ebp+0xc) 0/r32/eax
 8733 #?     (write-buffered Stderr "type allocid in caller after new-literal: ")
 8734 #?     (write-int32-hex-buffered Stderr *(eax+8))
 8735 #?     (write-buffered Stderr " for var ")
 8736 #?     (write-int32-hex-buffered Stderr %eax)
 8737 #?     (write-buffered Stderr Newline)
 8738 #?     (flush Stderr)
 8739 $new-block-name:end:
 8740     # . reclaim locals
 8741     81 0/subop/add %ecx 0xc/imm32  # name.{read/write/len}
 8742     81 0/subop/add %ecx 8/imm32  # slice
 8743     01/add-to %esp 1/r32/ecx
 8744     # . restore registers
 8745     5a/pop-to-edx
 8746     59/pop-to-ecx
 8747     58/pop-to-eax
 8748     # . epilogue
 8749     89/<- %esp 5/r32/ebp
 8750     5d/pop-to-ebp
 8751     c3/return
 8752 
 8753 check-no-tokens-left:  # line: (addr stream byte)
 8754     # . prologue
 8755     55/push-ebp
 8756     89/<- %ebp 4/r32/esp
 8757     # . save registers
 8758     50/push-eax
 8759     51/push-ecx
 8760     # var s/ecx: slice
 8761     68/push 0/imm32/end
 8762     68/push 0/imm32/start
 8763     89/<- %ecx 4/r32/esp
 8764     #
 8765     (next-mu-token *(ebp+8) %ecx)
 8766     # if slice-empty?(s) return
 8767     (slice-empty? %ecx)
 8768     3d/compare-eax-and 0/imm32/false
 8769     75/jump-if-!= $check-no-tokens-left:end/disp8
 8770     # if (slice-starts-with?(s, '#') return
 8771     # . eax = *s->start
 8772     8b/-> *edx 0/r32/eax
 8773     8a/copy-byte *eax 0/r32/AL
 8774     81 4/subop/and %eax 0xff/imm32
 8775     # . if (eax == '#') continue
 8776     3d/compare-eax-and 0x23/imm32/hash
 8777     74/jump-if-= $check-no-tokens-left:end/disp8
 8778     # abort
 8779     (write-buffered Stderr "'{' or '}' should be on its own line, but got '")
 8780     (rewind-stream %ecx)
 8781     (write-stream 2 %ecx)
 8782     (write-buffered Stderr "'\n")
 8783     (flush Stderr)
 8784     # . syscall(exit, 1)
 8785     bb/copy-to-ebx  1/imm32
 8786     e8/call syscall_exit/disp32
 8787     # never gets here
 8788 $check-no-tokens-left:end:
 8789     # . reclaim locals
 8790     81 0/subop/add %esp 8/imm32
 8791     # . restore registers
 8792     59/pop-to-ecx
 8793     58/pop-to-eax
 8794     # . epilogue
 8795     89/<- %esp 5/r32/ebp
 8796     5d/pop-to-ebp
 8797     c3/return
 8798 
 8799 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)
 8800     # pseudocode:
 8801     #   var v: (handle var)
 8802     #   new-literal(name, v)
 8803     #   push(vars, {v, false})
 8804     #   parse-mu-block(in, vars, fn, out)
 8805     #   pop(vars)
 8806     #   out->tag = block
 8807     #   out->var = v
 8808     #
 8809     # . prologue
 8810     55/push-ebp
 8811     89/<- %ebp 4/r32/esp
 8812     # . save registers
 8813     50/push-eax
 8814     51/push-ecx
 8815     57/push-edi
 8816     # var v/ecx: (handle var)
 8817     68/push 0/imm32
 8818     68/push 0/imm32
 8819     89/<- %ecx 4/r32/esp
 8820     #
 8821     (new-literal Heap *(ebp+8) %ecx)
 8822     # push(vars, v)
 8823     (push *(ebp+0x10) *ecx)
 8824     (push *(ebp+0x10) *(ecx+4))
 8825     (push *(ebp+0x10) 0)  # false
 8826     #
 8827     (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20))
 8828     # pop v off vars
 8829     (pop *(ebp+0x10))  # => eax
 8830     (pop *(ebp+0x10))  # => eax
 8831     (pop *(ebp+0x10))  # => eax
 8832     # var out-addr/edi: (addr stmt) = lookup(*out)
 8833     8b/-> *(ebp+0x18) 7/r32/edi
 8834     (lookup *edi *(edi+4))  # => eax
 8835     89/<- %edi 0/r32/eax
 8836     # out-addr->tag = named-block
 8837     c7 0/subop/copy *edi 0/imm32/block  # Stmt-tag
 8838     # out-addr->var = v
 8839     8b/-> *ecx 0/r32/eax
 8840     89/<- *(edi+0xc) 0/r32/eax  # Block-var
 8841     8b/-> *(ecx+4) 0/r32/eax
 8842     89/<- *(edi+0x10) 0/r32/eax  # Block-var
 8843 $parse-mu-named-block:end:
 8844     # . reclaim locals
 8845     81 0/subop/add %esp 8/imm32
 8846     # . restore registers
 8847     5f/pop-to-edi
 8848     59/pop-to-ecx
 8849     58/pop-to-eax
 8850     # . epilogue
 8851     89/<- %esp 5/r32/ebp
 8852     5d/pop-to-ebp
 8853     c3/return
 8854 
 8855 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)
 8856     # . prologue
 8857     55/push-ebp
 8858     89/<- %ebp 4/r32/esp
 8859     # . save registers
 8860     50/push-eax
 8861     51/push-ecx
 8862     52/push-edx
 8863     53/push-ebx
 8864     57/push-edi
 8865     # edi = out
 8866     8b/-> *(ebp+0x10) 7/r32/edi
 8867     # var word-slice/ecx: slice
 8868     68/push 0/imm32/end
 8869     68/push 0/imm32/start
 8870     89/<- %ecx 4/r32/esp
 8871     # var v/edx: (handle var)
 8872     68/push 0/imm32
 8873     68/push 0/imm32
 8874     89/<- %edx 4/r32/esp
 8875     # v = parse-var-with-type(next-mu-token(line))
 8876     (next-mu-token *(ebp+8) %ecx)
 8877     (parse-var-with-type %ecx *(ebp+8) %edx *(ebp+0x18) *(ebp+0x1c))
 8878     # var v-addr/eax: (addr var)
 8879     (lookup *edx *(edx+4))  # => eax
 8880     # v->block-depth = *Curr-block-depth
 8881     8b/-> *Curr-block-depth 3/r32/ebx
 8882     89/<- *(eax+0x10) 3/r32/ebx  # Var-block-depth
 8883     # either v has no register and there's no more to this line
 8884     8b/-> *(eax+0x18) 0/r32/eax  # Var-register
 8885     3d/compare-eax-and 0/imm32
 8886     {
 8887       75/jump-if-!= break/disp8
 8888       # TODO: disallow vars of type 'byte' on the stack
 8889       # ensure that there's nothing else on this line
 8890       (next-mu-token *(ebp+8) %ecx)
 8891       (slice-empty? %ecx)  # => eax
 8892       3d/compare-eax-and 0/imm32/false
 8893       0f 84/jump-if-= $parse-mu-var-def:error2/disp32
 8894       #
 8895       (new-var-def Heap  *edx *(edx+4)  %edi)
 8896       e9/jump $parse-mu-var-def:update-vars/disp32
 8897     }
 8898     # or v has a register and there's more to this line
 8899     {
 8900       0f 84/jump-if-= break/disp32
 8901       # TODO: disallow vars of type 'byte' in registers 'esi' or 'edi'
 8902       # TODO: vars of type 'byte' should only be initialized by clearing to 0
 8903       # ensure that the next word is '<-'
 8904       (next-mu-token *(ebp+8) %ecx)
 8905       (slice-equal? %ecx "<-")  # => eax
 8906       3d/compare-eax-and 0/imm32/false
 8907       0f 84/jump-if-= $parse-mu-var-def:error1/disp32
 8908       #
 8909       (new-reg-var-def Heap  *edx *(edx+4)  %edi)
 8910       (lookup *edi *(edi+4))  # => eax
 8911       (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 8912     }
 8913 $parse-mu-var-def:update-vars:
 8914     # push 'v' at end of function
 8915     (push *(ebp+0xc) *edx)
 8916     (push *(ebp+0xc) *(edx+4))
 8917     (push *(ebp+0xc) 0)  # Live-var-register-spilled is unused during parsing
 8918 $parse-mu-var-def:end:
 8919     # . reclaim locals
 8920     81 0/subop/add %esp 0x10/imm32
 8921     # . restore registers
 8922     5f/pop-to-edi
 8923     5b/pop-to-ebx
 8924     5a/pop-to-edx
 8925     59/pop-to-ecx
 8926     58/pop-to-eax
 8927     # . epilogue
 8928     89/<- %esp 5/r32/ebp
 8929     5d/pop-to-ebp
 8930     c3/return
 8931 
 8932 $parse-mu-var-def:error1:
 8933     (rewind-stream *(ebp+8))
 8934     # error("register variable requires a valid instruction to initialize but got '" line "'\n")
 8935     (write-buffered *(ebp+0x18) "register variable requires a valid instruction to initialize but got '")
 8936     (flush *(ebp+0x18))
 8937     (write-stream-data *(ebp+0x18) *(ebp+8))
 8938     (write-buffered *(ebp+0x18) "'\n")
 8939     (flush *(ebp+0x18))
 8940     (stop *(ebp+0x1c) 1)
 8941     # never gets here
 8942 
 8943 $parse-mu-var-def:error2:
 8944     (rewind-stream *(ebp+8))
 8945     # error("fn " fn ": var " var ": variables on the stack can't take an initializer\n")
 8946     (write-buffered *(ebp+0x18) "fn ")
 8947     8b/-> *(ebp+0x14) 0/r32/eax
 8948     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8949     (write-buffered *(ebp+0x18) %eax)
 8950     (write-buffered *(ebp+0x18) ": var ")
 8951     # var v-addr/eax: (addr var) = lookup(v)
 8952     (lookup *edx *(edx+4))  # => eax
 8953     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8954     (write-buffered *(ebp+0x18) %eax)
 8955     (write-buffered *(ebp+0x18) ": variables on the stack can't take an initializer\n")
 8956     (flush *(ebp+0x18))
 8957     (stop *(ebp+0x1c) 1)
 8958     # never gets here
 8959 
 8960 test-parse-mu-var-def:
 8961     # 'var n: int'
 8962     # . prologue
 8963     55/push-ebp
 8964     89/<- %ebp 4/r32/esp
 8965     # setup
 8966     (clear-stream _test-input-stream)
 8967     (write _test-input-stream "n: int\n")  # caller has consumed the 'var'
 8968     c7 0/subop/copy *Curr-block-depth 1/imm32
 8969     # var out/esi: (handle stmt)
 8970     68/push 0/imm32
 8971     68/push 0/imm32
 8972     89/<- %esi 4/r32/esp
 8973     # var vars/ecx: (stack (addr var) 16)
 8974     81 5/subop/subtract %esp 0xc0/imm32
 8975     68/push 0xc0/imm32/size
 8976     68/push 0/imm32/top
 8977     89/<- %ecx 4/r32/esp
 8978     (clear-stack %ecx)
 8979     # convert
 8980     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
 8981     # var out-addr/esi: (addr stmt)
 8982     (lookup *esi *(esi+4))  # => eax
 8983     89/<- %esi 0/r32/eax
 8984     #
 8985     (check-ints-equal *esi 2 "F - test-parse-mu-var-def/tag")  # Stmt-tag is var-def
 8986     # var v/ecx: (addr var) = lookup(out->var)
 8987     (lookup *(esi+4) *(esi+8))  # Vardef-var Vardef-var => eax
 8988     89/<- %ecx 0/r32/eax
 8989     # v->name
 8990     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 8991     (check-strings-equal %eax "n" "F - test-parse-mu-var-def/var-name")
 8992     # v->register
 8993     (check-ints-equal *(ecx+0x18) 0 "F - test-parse-mu-var-def/var-register")  # Var-register
 8994     # v->block-depth
 8995     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-var-def/output-block-depth")  # Var-block-depth
 8996     # v->type == int
 8997     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 8998     (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0")  # Type-tree-is-atom
 8999     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-var-def/var-type:1")  # Type-tree-value
 9000     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-var-def/var-type:2")  # Type-tree-right
 9001     # . epilogue
 9002     89/<- %esp 5/r32/ebp
 9003     5d/pop-to-ebp
 9004     c3/return
 9005 
 9006 test-parse-mu-reg-var-def:
 9007     # 'var n/eax: int <- copy 0'
 9008     # . prologue
 9009     55/push-ebp
 9010     89/<- %ebp 4/r32/esp
 9011     # setup
 9012     (clear-stream _test-input-stream)
 9013     (write _test-input-stream "n/eax: int <- copy 0\n")  # caller has consumed the 'var'
 9014     c7 0/subop/copy *Curr-block-depth 1/imm32
 9015     # var out/esi: (handle stmt)
 9016     68/push 0/imm32
 9017     68/push 0/imm32
 9018     89/<- %esi 4/r32/esp
 9019     # var vars/ecx: (stack (addr var) 16)
 9020     81 5/subop/subtract %esp 0xc0/imm32
 9021     68/push 0xc0/imm32/size
 9022     68/push 0/imm32/top
 9023     89/<- %ecx 4/r32/esp
 9024     (clear-stack %ecx)
 9025     # convert
 9026     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
 9027     # var out-addr/esi: (addr stmt)
 9028     (lookup *esi *(esi+4))  # => eax
 9029     89/<- %esi 0/r32/eax
 9030     #
 9031     (check-ints-equal *esi 3 "F - test-parse-mu-reg-var-def/tag")  # Stmt-tag is reg-var-def
 9032     # var v/ecx: (addr var) = lookup(out->outputs->value)
 9033     # . eax: (addr stmt-var) = lookup(out->outputs)
 9034     (lookup *(esi+0x14) *(esi+0x18))  # Regvardef-outputs Regvardef-outputs => eax
 9035     # .
 9036     (check-ints-equal *(eax+8) 0 "F - test-parse-mu-reg-var-def/single-output")  # Stmt-var-next
 9037     # . eax: (addr var) = lookup(eax->value)
 9038     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9039     # . ecx = eax
 9040     89/<- %ecx 0/r32/eax
 9041     # v->name
 9042     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 9043     (check-strings-equal %eax "n" "F - test-parse-mu-reg-var-def/output-name")  # Var-name
 9044     # v->register
 9045     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 9046     (check-strings-equal %eax "eax" "F - test-parse-mu-reg-var-def/output-register")
 9047     # v->block-depth
 9048     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-reg-var-def/output-block-depth")  # Var-block-depth
 9049     # v->type == int
 9050     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 9051     (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0")  # Type-tree-is-atom
 9052     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-reg-var-def/output-type:1")  # Type-tree-value
 9053     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-type:2")  # Type-tree-right
 9054     # . epilogue
 9055     89/<- %esp 5/r32/ebp
 9056     5d/pop-to-ebp
 9057     c3/return
 9058 
 9059 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)
 9060     # Carefully push any outputs on the vars stack _after_ reading the inputs
 9061     # that may conflict with them.
 9062     #
 9063     # The only situation in which outputs are pushed here (when it's not a
 9064     # 'var' vardef stmt), and so can possibly conflict with inputs, is if the
 9065     # output is a function output.
 9066     #
 9067     # pseudocode:
 9068     #   var name: slice
 9069     #   allocate(Heap, Stmt-size, out)
 9070     #   var out-addr: (addr stmt) = lookup(*out)
 9071     #   out-addr->tag = stmt
 9072     #   if stmt-has-outputs?(line)
 9073     #     while true
 9074     #       name = next-mu-token(line)
 9075     #       if (name == '<-') break
 9076     #       assert(is-identifier?(name))
 9077     #       var v: (handle var) = lookup-var-or-find-in-fn-outputs(name, vars, fn)
 9078     #       out-addr->outputs = append(v, out-addr->outputs)
 9079     #   add-operation-and-inputs-to-stmt(out-addr, line, vars)
 9080     #   for output in stmt->outputs:
 9081     #     maybe-define-var(output, vars)
 9082     #
 9083     # . prologue
 9084     55/push-ebp
 9085     89/<- %ebp 4/r32/esp
 9086     # . save registers
 9087     50/push-eax
 9088     51/push-ecx
 9089     52/push-edx
 9090     53/push-ebx
 9091     57/push-edi
 9092     # var name/ecx: slice
 9093     68/push 0/imm32/end
 9094     68/push 0/imm32/start
 9095     89/<- %ecx 4/r32/esp
 9096     # var is-deref?/edx: boolean = false
 9097     ba/copy-to-edx 0/imm32/false
 9098     # var v: (handle var)
 9099     68/push 0/imm32
 9100     68/push 0/imm32
 9101     89/<- %ebx 4/r32/esp
 9102     #
 9103     (allocate Heap *Stmt-size *(ebp+0x14))
 9104     # var out-addr/edi: (addr stmt) = lookup(*out)
 9105     8b/-> *(ebp+0x14) 7/r32/edi
 9106     (lookup *edi *(edi+4))  # => eax
 9107     89/<- %edi 0/r32/eax
 9108     # out-addr->tag = 1/stmt
 9109     c7 0/subop/copy *edi 1/imm32/stmt1  # Stmt-tag
 9110     {
 9111       (stmt-has-outputs? *(ebp+8))
 9112       3d/compare-eax-and 0/imm32/false
 9113       0f 84/jump-if-= break/disp32
 9114       {
 9115 $parse-mu-stmt:read-outputs:
 9116         # name = next-mu-token(line)
 9117         (next-mu-token *(ebp+8) %ecx)
 9118         # if slice-empty?(word-slice) break
 9119         (slice-empty? %ecx)  # => eax
 9120         3d/compare-eax-and 0/imm32/false
 9121         0f 85/jump-if-!= break/disp32
 9122         # if (name == "<-") break
 9123         (slice-equal? %ecx "<-")  # => eax
 9124         3d/compare-eax-and 0/imm32/false
 9125         0f 85/jump-if-!= break/disp32
 9126         # is-deref? = false
 9127         ba/copy-to-edx 0/imm32/false
 9128         # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 9129         8b/-> *ecx 0/r32/eax  # Slice-start
 9130         8a/copy-byte *eax 0/r32/AL
 9131         81 4/subop/and %eax 0xff/imm32
 9132         3d/compare-eax-and 0x2a/imm32/asterisk
 9133         {
 9134           75/jump-if-!= break/disp8
 9135           ff 0/subop/increment *ecx
 9136           ba/copy-to-edx 1/imm32/true
 9137         }
 9138         # assert(is-identifier?(name))
 9139         (is-identifier? %ecx)  # => eax
 9140         3d/compare-eax-and 0/imm32/false
 9141         0f 84/jump-if-= $parse-mu-stmt:abort/disp32
 9142         #
 9143         (lookup-var-or-find-in-fn-outputs %ecx *(ebp+0xc) *(ebp+0x10) %ebx *(ebp+0x18) *(ebp+0x1c))
 9144         8d/copy-address *(edi+0x14) 0/r32/eax  # Stmt1-outputs
 9145         (append-stmt-var Heap  *ebx *(ebx+4)  *(edi+0x14) *(edi+0x18)  %edx  %eax)  # Stmt1-outputs
 9146         #
 9147         e9/jump loop/disp32
 9148       }
 9149     }
 9150     (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 9151 $parse-mu-stmt:define-outputs:
 9152     # var output/edi: (addr stmt-var) = lookup(out-addr->outputs)
 9153     (lookup *(edi+0x14) *(edi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
 9154     89/<- %edi 0/r32/eax
 9155     {
 9156 $parse-mu-stmt:define-outputs-loop:
 9157       # if (output == null) break
 9158       81 7/subop/compare %edi 0/imm32
 9159       74/jump-if-= break/disp8
 9160       #
 9161       (maybe-define-var *edi *(edi+4)  *(ebp+0xc))  # if output is a deref, then it's already been defined,
 9162                                                     # and must be in vars. This call will be a no-op, but safe.
 9163       # output = output->next
 9164       (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
 9165       89/<- %edi 0/r32/eax
 9166       #
 9167       eb/jump loop/disp8
 9168     }
 9169 $parse-mu-stmt:end:
 9170     # . reclaim locals
 9171     81 0/subop/add %esp 0x10/imm32
 9172     # . restore registers
 9173     5f/pop-to-edi
 9174     5b/pop-to-ebx
 9175     5a/pop-to-edx
 9176     59/pop-to-ecx
 9177     58/pop-to-eax
 9178     # . epilogue
 9179     89/<- %esp 5/r32/ebp
 9180     5d/pop-to-ebp
 9181     c3/return
 9182 
 9183 $parse-mu-stmt:abort:
 9184     # error("invalid identifier '" name "'\n")
 9185     (write-buffered *(ebp+0x18) "invalid identifier '")
 9186     (write-slice-buffered *(ebp+0x18) %ecx)
 9187     (write-buffered *(ebp+0x18) "'\n")
 9188     (flush *(ebp+0x18))
 9189     (stop *(ebp+0x1c) 1)
 9190     # never gets here
 9191 
 9192 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)
 9193     # pseudocode:
 9194     #   stmt->name = slice-to-string(next-mu-token(line))
 9195     #   while true
 9196     #     name = next-mu-token(line)
 9197     #     v = lookup-var-or-literal(name)
 9198     #     stmt->inouts = append(v, stmt->inouts)
 9199     #
 9200     # . prologue
 9201     55/push-ebp
 9202     89/<- %ebp 4/r32/esp
 9203     # . save registers
 9204     50/push-eax
 9205     51/push-ecx
 9206     52/push-edx
 9207     53/push-ebx
 9208     56/push-esi
 9209     57/push-edi
 9210     # edi = stmt
 9211     8b/-> *(ebp+8) 7/r32/edi
 9212     # var name/ecx: slice
 9213     68/push 0/imm32/end
 9214     68/push 0/imm32/start
 9215     89/<- %ecx 4/r32/esp
 9216     # var is-deref?/edx: boolean = false
 9217     ba/copy-to-edx 0/imm32/false
 9218     # var v/esi: (handle var)
 9219     68/push 0/imm32
 9220     68/push 0/imm32
 9221     89/<- %esi 4/r32/esp
 9222 $add-operation-and-inputs-to-stmt:read-operation:
 9223     (next-mu-token *(ebp+0xc) %ecx)
 9224     8d/copy-address *(edi+4) 0/r32/eax  # Stmt1-operation or Regvardef-operationStmt1-operation or Regvardef-operation
 9225     (slice-to-string Heap %ecx %eax)
 9226     # var is-get?/ebx: boolean = (name == "get")
 9227     (slice-equal? %ecx "get")  # => eax
 9228     89/<- %ebx 0/r32/eax
 9229     {
 9230 $add-operation-and-inputs-to-stmt:read-inouts:
 9231       # name = next-mu-token(line)
 9232       (next-mu-token *(ebp+0xc) %ecx)
 9233       # if slice-empty?(word-slice) break
 9234       (slice-empty? %ecx)  # => eax
 9235       3d/compare-eax-and 0/imm32/false
 9236       0f 85/jump-if-!= break/disp32
 9237       # if (name == "<-") abort
 9238       (slice-equal? %ecx "<-")
 9239       3d/compare-eax-and 0/imm32/false
 9240       0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32
 9241       # if (is-get? && second operand) lookup or create offset
 9242       {
 9243         81 7/subop/compare %ebx 0/imm32/false
 9244         74/jump-if-= break/disp8
 9245         (lookup *(edi+0xc) *(edi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9246         3d/compare-eax-and 0/imm32
 9247         74/jump-if-= break/disp8
 9248         (lookup-or-create-constant %eax %ecx %esi)
 9249 #?         (lookup *esi *(esi+4))
 9250 #?         (write-buffered Stderr "creating new output var ")
 9251 #?         (write-int32-hex-buffered Stderr %eax)
 9252 #?         (write-buffered Stderr " for field called ")
 9253 #?         (write-slice-buffered Stderr %ecx)
 9254 #?         (write-buffered Stderr "; var name ")
 9255 #?         (lookup *eax *(eax+4))  # Var-name
 9256 #?         (write-buffered Stderr %eax)
 9257 #?         (write-buffered Stderr Newline)
 9258 #?         (flush Stderr)
 9259         e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32
 9260       }
 9261       # is-deref? = false
 9262       ba/copy-to-edx 0/imm32/false
 9263       # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 9264       8b/-> *ecx 0/r32/eax  # Slice-start
 9265       8a/copy-byte *eax 0/r32/AL
 9266       81 4/subop/and %eax 0xff/imm32
 9267       3d/compare-eax-and 0x2a/imm32/asterisk
 9268       {
 9269         75/jump-if-!= break/disp8
 9270 $add-operation-and-inputs-to-stmt:inout-is-deref:
 9271         ff 0/subop/increment *ecx
 9272         ba/copy-to-edx 1/imm32/true
 9273       }
 9274       (lookup-var-or-literal %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9275 $add-operation-and-inputs-to-stmt:save-var:
 9276       8d/copy-address *(edi+0xc) 0/r32/eax
 9277       (append-stmt-var Heap  *esi *(esi+4)  *(edi+0xc) *(edi+0x10)  %edx  %eax)  # Stmt1-inouts or Regvardef-inouts
 9278       #
 9279       e9/jump loop/disp32
 9280     }
 9281 $add-operation-and-inputs-to-stmt:end:
 9282     # . reclaim locals
 9283     81 0/subop/add %esp 0x10/imm32
 9284     # . restore registers
 9285     5f/pop-to-edi
 9286     5e/pop-to-esi
 9287     5b/pop-to-ebx
 9288     5a/pop-to-edx
 9289     59/pop-to-ecx
 9290     58/pop-to-eax
 9291     # . epilogue
 9292     89/<- %esp 5/r32/ebp
 9293     5d/pop-to-ebp
 9294     c3/return
 9295 
 9296 $add-operation-and-inputs-to-stmt:abort:
 9297     # error("fn ___: invalid identifier in '" line "'\n")
 9298     (write-buffered *(ebp+0x18) "fn ")
 9299     8b/-> *(ebp+0x14) 0/r32/eax
 9300     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9301     (write-buffered *(ebp+0x18) %eax)
 9302     (rewind-stream *(ebp+0xc))
 9303     (write-buffered *(ebp+0x18) ": invalid identifier in '")
 9304     (write-stream-data *(ebp+0x18) *(ebp+0xc))
 9305     (write-buffered *(ebp+0x18) "'\n")
 9306     (flush *(ebp+0x18))
 9307     (stop *(ebp+0x1c) 1)
 9308     # never gets here
 9309 
 9310 stmt-has-outputs?:  # line: (addr stream byte) -> result/eax: boolean
 9311     # . prologue
 9312     55/push-ebp
 9313     89/<- %ebp 4/r32/esp
 9314     # . save registers
 9315     51/push-ecx
 9316     # var word-slice/ecx: slice
 9317     68/push 0/imm32/end
 9318     68/push 0/imm32/start
 9319     89/<- %ecx 4/r32/esp
 9320     # result = false
 9321     b8/copy-to-eax 0/imm32/false
 9322     (rewind-stream *(ebp+8))
 9323     {
 9324       (next-mu-token *(ebp+8) %ecx)
 9325       # if slice-empty?(word-slice) break
 9326       (slice-empty? %ecx)
 9327       3d/compare-eax-and 0/imm32/false
 9328       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 9329       0f 85/jump-if-!= break/disp32
 9330       # if slice-starts-with?(word-slice, '#') break
 9331       # . eax = *word-slice->start
 9332       8b/-> *ecx 0/r32/eax
 9333       8a/copy-byte *eax 0/r32/AL
 9334       81 4/subop/and %eax 0xff/imm32
 9335       # . if (eax == '#') break
 9336       3d/compare-eax-and 0x23/imm32/hash
 9337       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 9338       0f 84/jump-if-= break/disp32
 9339       # if slice-equal?(word-slice, '<-') return true
 9340       (slice-equal? %ecx "<-")
 9341       3d/compare-eax-and 0/imm32/false
 9342       74/jump-if-= loop/disp8
 9343       b8/copy-to-eax 1/imm32/true
 9344     }
 9345 $stmt-has-outputs:end:
 9346     (rewind-stream *(ebp+8))
 9347     # . reclaim locals
 9348     81 0/subop/add %esp 8/imm32
 9349     # . restore registers
 9350     59/pop-to-ecx
 9351     # . epilogue
 9352     89/<- %esp 5/r32/ebp
 9353     5d/pop-to-ebp
 9354     c3/return
 9355 
 9356 # if 'name' starts with a digit, create a new literal var for it
 9357 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found
 9358 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)
 9359     # . prologue
 9360     55/push-ebp
 9361     89/<- %ebp 4/r32/esp
 9362     # . save registers
 9363     50/push-eax
 9364     51/push-ecx
 9365     56/push-esi
 9366     # esi = name
 9367     8b/-> *(ebp+8) 6/r32/esi
 9368     # if slice-empty?(name) abort
 9369     (slice-empty? %esi)  # => eax
 9370     3d/compare-eax-and 0/imm32/false
 9371     0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32
 9372     # var c/ecx: byte = *name->start
 9373     8b/-> *esi 1/r32/ecx
 9374     8a/copy-byte *ecx 1/r32/CL
 9375     81 4/subop/and %ecx 0xff/imm32
 9376     # if is-decimal-digit?(c) return new var(name)
 9377     {
 9378       (is-decimal-digit? %ecx)  # => eax
 9379       3d/compare-eax-and 0/imm32/false
 9380       74/jump-if-= break/disp8
 9381 $lookup-var-or-literal:literal:
 9382       (new-literal-integer Heap %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9383       eb/jump $lookup-var-or-literal:end/disp8
 9384     }
 9385     # else if (c == '"') return new var(name)
 9386     {
 9387       81 7/subop/compare %ecx 0x22/imm32/dquote
 9388       75/jump-if-!= break/disp8
 9389 $lookup-var-or-literal:literal-string:
 9390       (new-literal Heap %esi *(ebp+0x10))
 9391       eb/jump $lookup-var-or-literal:end/disp8
 9392     }
 9393     # otherwise return lookup-var(name, vars)
 9394     {
 9395 $lookup-var-or-literal:var:
 9396       (lookup-var %esi *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9397     }
 9398 $lookup-var-or-literal:end:
 9399     # . restore registers
 9400     5e/pop-to-esi
 9401     59/pop-to-ecx
 9402     58/pop-to-eax
 9403     # . epilogue
 9404     89/<- %esp 5/r32/ebp
 9405     5d/pop-to-ebp
 9406     c3/return
 9407 
 9408 $lookup-var-or-literal:abort:
 9409     (write-buffered *(ebp+0x18) "fn ")
 9410     8b/-> *(ebp+0x14) 0/r32/eax
 9411     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9412     (write-buffered *(ebp+0x18) %eax)
 9413     (write-buffered *(ebp+0x18) ": empty variable!")
 9414     (flush *(ebp+0x18))
 9415     (stop *(ebp+0x1c) 1)
 9416     # never gets here
 9417 
 9418 # return first 'name' from the top (back) of 'vars' and abort if not found
 9419 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)
 9420     # . prologue
 9421     55/push-ebp
 9422     89/<- %ebp 4/r32/esp
 9423     # . save registers
 9424     50/push-eax
 9425     #
 9426     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9427     # if (*out == 0) abort
 9428     8b/-> *(ebp+0x10) 0/r32/eax
 9429     81 7/subop/compare *eax 0/imm32
 9430     74/jump-if-= $lookup-var:abort/disp8
 9431 $lookup-var:end:
 9432     # . restore registers
 9433     58/pop-to-eax
 9434     # . epilogue
 9435     89/<- %esp 5/r32/ebp
 9436     5d/pop-to-ebp
 9437     c3/return
 9438 
 9439 $lookup-var:abort:
 9440     (write-buffered *(ebp+0x18) "fn ")
 9441     8b/-> *(ebp+0x14) 0/r32/eax
 9442     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9443     (write-buffered *(ebp+0x18) %eax)
 9444     (write-buffered *(ebp+0x18) ": unknown variable '")
 9445     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 9446     (write-buffered *(ebp+0x18) "'\n")
 9447     (flush *(ebp+0x18))
 9448     (stop *(ebp+0x1c) 1)
 9449     # never gets here
 9450 
 9451 # return first 'name' from the top (back) of 'vars', and 0/null if not found
 9452 # ensure that 'name' if in a register is the topmost variable in that register
 9453 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)
 9454     # pseudocode:
 9455     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 9456     #   var min = vars->data
 9457     #   while curr >= min
 9458     #     var v: (handle var) = *curr
 9459     #     if v->name == name
 9460     #       return
 9461     #     curr -= 12
 9462     #
 9463     # . prologue
 9464     55/push-ebp
 9465     89/<- %ebp 4/r32/esp
 9466     # . save registers
 9467     50/push-eax
 9468     51/push-ecx
 9469     52/push-edx
 9470     53/push-ebx
 9471     56/push-esi
 9472     57/push-edi
 9473     # clear out
 9474     (zero-out *(ebp+0x10) *Handle-size)
 9475     # esi = vars
 9476     8b/-> *(ebp+0xc) 6/r32/esi
 9477     # ebx = vars->top
 9478     8b/-> *esi 3/r32/ebx
 9479     # if (vars->top > vars->size) abort
 9480     3b/compare<- *(esi+4) 0/r32/eax
 9481     0f 8f/jump-if-> $lookup-var-helper:error1/disp32
 9482     # var min/edx: (addr handle var) = vars->data
 9483     8d/copy-address *(esi+8) 2/r32/edx
 9484     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
 9485     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
 9486     # var var-in-reg/edi: 8 addrs
 9487     68/push 0/imm32
 9488     68/push 0/imm32
 9489     68/push 0/imm32
 9490     68/push 0/imm32
 9491     68/push 0/imm32
 9492     68/push 0/imm32
 9493     68/push 0/imm32
 9494     68/push 0/imm32
 9495     89/<- %edi 4/r32/esp
 9496     {
 9497 $lookup-var-helper:loop:
 9498       # if (curr < min) return
 9499       39/compare %ebx 2/r32/edx
 9500       0f 82/jump-if-addr< break/disp32
 9501       # var v/ecx: (addr var) = lookup(*curr)
 9502       (lookup *ebx *(ebx+4))  # => eax
 9503       89/<- %ecx 0/r32/eax
 9504       # var vn/eax: (addr array byte) = lookup(v->name)
 9505       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 9506       # if (vn == name) return curr
 9507       (slice-equal? *(ebp+8) %eax)  # => eax
 9508       3d/compare-eax-and 0/imm32/false
 9509       {
 9510         74/jump-if-= break/disp8
 9511 $lookup-var-helper:found:
 9512         # var vr/eax: (addr array byte) = lookup(v->register)
 9513         (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 9514         3d/compare-eax-and 0/imm32
 9515         {
 9516           74/jump-if-= break/disp8
 9517 $lookup-var-helper:found-register:
 9518           # var reg/eax: int = get(Registers, vr)
 9519           (get Mu-registers %eax 0xc "Mu-registers")  # => eax
 9520           8b/-> *eax 0/r32/eax
 9521           # if (var-in-reg[reg]) error
 9522           8b/-> *(edi+eax<<2) 0/r32/eax
 9523           3d/compare-eax-and 0/imm32
 9524           0f 85/jump-if-!= $lookup-var-helper:error2/disp32
 9525         }
 9526 $lookup-var-helper:return:
 9527         # esi = out
 9528         8b/-> *(ebp+0x10) 6/r32/esi
 9529         # *out = *curr
 9530         8b/-> *ebx 0/r32/eax
 9531         89/<- *esi 0/r32/eax
 9532         8b/-> *(ebx+4) 0/r32/eax
 9533         89/<- *(esi+4) 0/r32/eax
 9534         # return
 9535         eb/jump $lookup-var-helper:end/disp8
 9536       }
 9537       # 'name' not yet found; update var-in-reg if v in register
 9538       # . var vr/eax: (addr array byte) = lookup(v->register)
 9539       (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 9540       # . if (var == 0) continue
 9541       3d/compare-eax-and 0/imm32
 9542       74/jump-if-= $lookup-var-helper:continue/disp8
 9543       # . var reg/eax: int = get(Registers, vr)
 9544       (get Mu-registers %eax 0xc "Mu-registers")  # => eax
 9545       8b/-> *eax 0/r32/eax
 9546       # . if (var-in-reg[reg] == 0) var-in-reg[reg] = v
 9547       81 7/subop/compare *(edi+eax<<2) 0/imm32
 9548       75/jump-if-!= $lookup-var-helper:continue/disp8
 9549       89/<- *(edi+eax<<2) 1/r32/ecx
 9550 $lookup-var-helper:continue:
 9551       # curr -= 12
 9552       81 5/subop/subtract %ebx 0xc/imm32
 9553       e9/jump loop/disp32
 9554     }
 9555 $lookup-var-helper:end:
 9556     # . reclaim locals
 9557     81 0/subop/add %esp 0x20/imm32
 9558     # . restore registers
 9559     5f/pop-to-edi
 9560     5e/pop-to-esi
 9561     5b/pop-to-ebx
 9562     5a/pop-to-edx
 9563     59/pop-to-ecx
 9564     58/pop-to-eax
 9565     # . epilogue
 9566     89/<- %esp 5/r32/ebp
 9567     5d/pop-to-ebp
 9568     c3/return
 9569 
 9570 $lookup-var-helper:error1:
 9571     (write-buffered *(ebp+0x18) "fn ")
 9572     8b/-> *(ebp+0x14) 0/r32/eax
 9573     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9574     (write-buffered *(ebp+0x18) %eax)
 9575     (write-buffered *(ebp+0x18) ": malformed stack when looking up '")
 9576     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 9577     (write-buffered *(ebp+0x18) "'\n")
 9578     (flush *(ebp+0x18))
 9579     (stop *(ebp+0x1c) 1)
 9580     # never gets here
 9581 
 9582 $lookup-var-helper:error2:
 9583     # eax contains the conflicting var at this point
 9584     (write-buffered *(ebp+0x18) "fn ")
 9585     50/push-eax
 9586     8b/-> *(ebp+0x14) 0/r32/eax
 9587     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9588     (write-buffered *(ebp+0x18) %eax)
 9589     58/pop-eax
 9590     (write-buffered *(ebp+0x18) ": register ")
 9591     50/push-eax
 9592     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 9593     (write-buffered *(ebp+0x18) %eax)
 9594     58/pop-to-eax
 9595     (write-buffered *(ebp+0x18) " reads var '")
 9596     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 9597     (write-buffered *(ebp+0x18) "' after writing var '")
 9598     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9599     (write-buffered *(ebp+0x18) %eax)
 9600     (write-buffered *(ebp+0x18) "'\n")
 9601     (flush *(ebp+0x18))
 9602     (stop *(ebp+0x1c) 1)
 9603     # never gets here
 9604 
 9605 dump-vars:  # vars: (addr stack live-var)
 9606     # pseudocode:
 9607     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 9608     #   var min = vars->data
 9609     #   while curr >= min
 9610     #     var v: (handle var) = *curr
 9611     #     print v
 9612     #     curr -= 12
 9613     #
 9614     # . prologue
 9615     55/push-ebp
 9616     89/<- %ebp 4/r32/esp
 9617     # . save registers
 9618     52/push-edx
 9619     53/push-ebx
 9620     56/push-esi
 9621     # esi = vars
 9622     8b/-> *(ebp+8) 6/r32/esi
 9623     # ebx = vars->top
 9624     8b/-> *esi 3/r32/ebx
 9625     # var min/edx: (addr handle var) = vars->data
 9626     8d/copy-address *(esi+8) 2/r32/edx
 9627     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
 9628     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
 9629     {
 9630 $dump-vars:loop:
 9631       # if (curr < min) return
 9632       39/compare %ebx 2/r32/edx
 9633       0f 82/jump-if-addr< break/disp32
 9634       #
 9635       (write-buffered Stderr "  var@")
 9636       (dump-var 2 %ebx)
 9637       # curr -= 12
 9638       81 5/subop/subtract %ebx 0xc/imm32
 9639       e9/jump loop/disp32
 9640     }
 9641 $dump-vars:end:
 9642     # . restore registers
 9643     5e/pop-to-esi
 9644     5b/pop-to-ebx
 9645     5a/pop-to-edx
 9646     # . epilogue
 9647     89/<- %esp 5/r32/ebp
 9648     5d/pop-to-ebp
 9649     c3/return
 9650 
 9651 == data
 9652 # Like Registers, but no esp or ebp
 9653 Mu-registers:  # (addr stream {(handle array byte), int})
 9654   # a table is a stream
 9655   0x48/imm32/write
 9656   0/imm32/read
 9657   0x48/imm32/length
 9658   # data
 9659   # it is perfectly ok to use fake alloc-ids -- as long as you never try to reclaim them
 9660   0x11/imm32/alloc-id $Mu-register-eax/imm32 0/imm32
 9661   0x11/imm32/alloc-id $Mu-register-ecx/imm32 1/imm32
 9662   0x11/imm32/alloc-id $Mu-register-edx/imm32 2/imm32
 9663   0x11/imm32/alloc-id $Mu-register-ebx/imm32 3/imm32
 9664   0x11/imm32/alloc-id $Mu-register-esi/imm32 6/imm32
 9665   0x11/imm32/alloc-id $Mu-register-edi/imm32 7/imm32
 9666 
 9667 $Mu-register-eax:
 9668   0x11/imm32/alloc-id
 9669   3/imm32/size
 9670   0x65/e 0x61/a 0x78/x
 9671 
 9672 $Mu-register-ecx:
 9673   0x11/imm32/alloc-id
 9674   3/imm32/size
 9675   0x65/e 0x63/c 0x78/x
 9676 
 9677 $Mu-register-edx:
 9678   0x11/imm32/alloc-id
 9679   3/imm32/size
 9680   0x65/e 0x64/d 0x78/x
 9681 
 9682 $Mu-register-ebx:
 9683   0x11/imm32/alloc-id
 9684   3/imm32/size
 9685   0x65/e 0x62/b 0x78/x
 9686 
 9687 $Mu-register-esi:
 9688   0x11/imm32/alloc-id
 9689   3/imm32/size
 9690   0x65/e 0x73/s 0x69/i
 9691 
 9692 $Mu-register-edi:
 9693   0x11/imm32/alloc-id
 9694   3/imm32/size
 9695   0x65/e 0x64/d 0x69/i
 9696 
 9697 == code
 9698 
 9699 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found
 9700 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)
 9701     # . prologue
 9702     55/push-ebp
 9703     89/<- %ebp 4/r32/esp
 9704     # . save registers
 9705     50/push-eax
 9706     #
 9707     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))  # arg order slightly different; 'fn' is deemphasized
 9708     {
 9709       # if (out != 0) return
 9710       8b/-> *(ebp+0x14) 0/r32/eax
 9711       81 7/subop/compare *eax 0/imm32
 9712       75/jump-if-!= break/disp8
 9713       # if name is one of fn's outputs, return it
 9714       (find-in-function-outputs *(ebp+0x10) *(ebp+8) *(ebp+0x14))
 9715       8b/-> *(ebp+0x14) 0/r32/eax
 9716       81 7/subop/compare *eax 0/imm32
 9717       # otherwise abort
 9718       0f 84/jump-if-= $lookup-or-define-var:abort/disp32
 9719     }
 9720 $lookup-or-define-var:end:
 9721     # . restore registers
 9722     58/pop-to-eax
 9723     # . epilogue
 9724     89/<- %esp 5/r32/ebp
 9725     5d/pop-to-ebp
 9726     c3/return
 9727 
 9728 $lookup-or-define-var:abort:
 9729     (write-buffered *(ebp+0x18) "unknown variable '")
 9730     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 9731     (write-buffered *(ebp+0x18) "'\n")
 9732     (flush *(ebp+0x18))
 9733     (stop *(ebp+0x1c) 1)
 9734     # never gets here
 9735 
 9736 find-in-function-outputs:  # fn: (addr function), name: (addr slice), out: (addr handle var)
 9737     # . prologue
 9738     55/push-ebp
 9739     89/<- %ebp 4/r32/esp
 9740     # . save registers
 9741     50/push-eax
 9742     51/push-ecx
 9743     # var curr/ecx: (addr list var) = lookup(fn->outputs)
 9744     8b/-> *(ebp+8) 1/r32/ecx
 9745     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 9746     89/<- %ecx 0/r32/eax
 9747     # while curr != null
 9748     {
 9749       81 7/subop/compare %ecx 0/imm32
 9750       74/jump-if-= break/disp8
 9751       # var v/eax: (addr var) = lookup(curr->value)
 9752       (lookup *ecx *(ecx+4))  # List-value List-value => eax
 9753       # var s/eax: (addr array byte) = lookup(v->name)
 9754       (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9755       # if (s == name) return curr->value
 9756       (slice-equal? *(ebp+0xc) %eax)  # => eax
 9757       3d/compare-eax-and 0/imm32/false
 9758       {
 9759         74/jump-if-= break/disp8
 9760         # var edi = out
 9761         57/push-edi
 9762         8b/-> *(ebp+0x10) 7/r32/edi
 9763         # *out = curr->value
 9764         8b/-> *ecx 0/r32/eax
 9765         89/<- *edi 0/r32/eax
 9766         8b/-> *(ecx+4) 0/r32/eax
 9767         89/<- *(edi+4) 0/r32/eax
 9768         #
 9769         5f/pop-to-edi
 9770         eb/jump $find-in-function-outputs:end/disp8
 9771       }
 9772       # curr = curr->next
 9773       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
 9774       89/<- %ecx 0/r32/eax
 9775       #
 9776       eb/jump loop/disp8
 9777     }
 9778     b8/copy-to-eax 0/imm32
 9779 $find-in-function-outputs:end:
 9780     # . restore registers
 9781     59/pop-to-ecx
 9782     58/pop-to-eax
 9783     # . epilogue
 9784     89/<- %esp 5/r32/ebp
 9785     5d/pop-to-ebp
 9786     c3/return
 9787 
 9788 # push 'out' to 'vars' if not already there; it's assumed to be a fn output
 9789 maybe-define-var:  # out: (handle var), vars: (addr stack live-var)
 9790     # . prologue
 9791     55/push-ebp
 9792     89/<- %ebp 4/r32/esp
 9793     # . save registers
 9794     50/push-eax
 9795     # var out-addr/eax: (addr var)
 9796     (lookup *(ebp+8) *(ebp+0xc))  # => eax
 9797     #
 9798     (binding-exists? %eax *(ebp+0x10))  # => eax
 9799     3d/compare-eax-and 0/imm32/false
 9800     75/jump-if-!= $maybe-define-var:end/disp8
 9801     # otherwise update vars
 9802     (push *(ebp+0x10) *(ebp+8))
 9803     (push *(ebp+0x10) *(ebp+0xc))
 9804     (push *(ebp+0x10) 0)  # 'out' is always a fn output; never spill it
 9805 $maybe-define-var:end:
 9806     # . restore registers
 9807     58/pop-to-eax
 9808     # . epilogue
 9809     89/<- %esp 5/r32/ebp
 9810     5d/pop-to-ebp
 9811     c3/return
 9812 
 9813 # simpler version of lookup-var-helper
 9814 binding-exists?:  # target: (addr var), vars: (addr stack live-var) -> result/eax: boolean
 9815     # pseudocode:
 9816     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 9817     #   var min = vars->data
 9818     #   while curr >= min
 9819     #     var v: (handle var) = *curr
 9820     #     if v->name == target->name
 9821     #       return true
 9822     #     curr -= 12
 9823     #   return false
 9824     #
 9825     # . prologue
 9826     55/push-ebp
 9827     89/<- %ebp 4/r32/esp
 9828     # . save registers
 9829     51/push-ecx
 9830     52/push-edx
 9831     56/push-esi
 9832     # var target-name/ecx: (addr array byte) = lookup(target->name)
 9833     8b/-> *(ebp+8) 0/r32/eax
 9834     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9835     89/<- %ecx 0/r32/eax
 9836     # esi = vars
 9837     8b/-> *(ebp+0xc) 6/r32/esi
 9838     # eax = vars->top
 9839     8b/-> *esi 0/r32/eax
 9840     # var min/edx: (addr handle var) = vars->data
 9841     8d/copy-address *(esi+8) 2/r32/edx
 9842     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
 9843     8d/copy-address *(esi+eax-4) 6/r32/esi  # vars + 8 + vars->type - 12
 9844     {
 9845 $binding-exists?:loop:
 9846       # if (curr < min) return
 9847       39/compare %esi 2/r32/edx
 9848       0f 82/jump-if-addr< break/disp32
 9849       # var v/eax: (addr var) = lookup(*curr)
 9850       (lookup *esi *(esi+4))  # => eax
 9851       # var vn/eax: (addr array byte) = lookup(v->name)
 9852       (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9853       # if (vn == target-name) return true
 9854       (string-equal? %ecx %eax)  # => eax
 9855       3d/compare-eax-and 0/imm32/false
 9856       75/jump-if-!= $binding-exists?:end/disp8  # eax already contains true
 9857       # curr -= 12
 9858       81 5/subop/subtract %esi 0xc/imm32
 9859       e9/jump loop/disp32
 9860     }
 9861     b8/copy-to-eax 0/imm32/false
 9862 $binding-exists?:end:
 9863     # . restore registers
 9864     5e/pop-to-esi
 9865     5a/pop-to-edx
 9866     59/pop-to-ecx
 9867     # . epilogue
 9868     89/<- %esp 5/r32/ebp
 9869     5d/pop-to-ebp
 9870     c3/return
 9871 
 9872 test-parse-mu-stmt:
 9873     # . prologue
 9874     55/push-ebp
 9875     89/<- %ebp 4/r32/esp
 9876     # setup
 9877     (clear-stream _test-input-stream)
 9878     (write _test-input-stream "increment n\n")
 9879     # var vars/ecx: (stack (addr var) 16)
 9880     81 5/subop/subtract %esp 0xc0/imm32
 9881     68/push 0xc0/imm32/size
 9882     68/push 0/imm32/top
 9883     89/<- %ecx 4/r32/esp
 9884     (clear-stack %ecx)
 9885     # var v/edx: (handle var)
 9886     68/push 0/imm32
 9887     68/push 0/imm32
 9888     89/<- %edx 4/r32/esp
 9889     # var s/eax: (handle array byte)
 9890     68/push 0/imm32
 9891     68/push 0/imm32
 9892     89/<- %eax 4/r32/esp
 9893     # v = new var("n")
 9894     (copy-array Heap "n" %eax)
 9895     (new-var Heap *eax *(eax+4) %edx)
 9896     #
 9897     (push %ecx *edx)
 9898     (push %ecx *(edx+4))
 9899     (push %ecx 0)
 9900     # var out/eax: (handle stmt)
 9901     68/push 0/imm32
 9902     68/push 0/imm32
 9903     89/<- %eax 4/r32/esp
 9904     # convert
 9905     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
 9906     # var out-addr/edx: (addr stmt) = lookup(*out)
 9907     (lookup *eax *(eax+4))  # => eax
 9908     89/<- %edx 0/r32/eax
 9909     # out->tag
 9910     (check-ints-equal *edx 1 "F - test-parse-mu-stmt/tag")  # Stmt-tag is Stmt1
 9911     # out->operation
 9912     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
 9913     (check-strings-equal %eax "increment" "F - test-parse-mu-stmt/name")  # Stmt1-operation
 9914     # out->inouts->value->name
 9915     # . eax = out->inouts
 9916     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9917     # . eax = out->inouts->value
 9918     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9919     # . eax = out->inouts->value->name
 9920     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9921     # .
 9922     (check-strings-equal %eax "n" "F - test-parse-mu-stmt/inout:0")
 9923     # . epilogue
 9924     89/<- %esp 5/r32/ebp
 9925     5d/pop-to-ebp
 9926     c3/return
 9927 
 9928 test-parse-mu-stmt-with-comma:
 9929     # . prologue
 9930     55/push-ebp
 9931     89/<- %ebp 4/r32/esp
 9932     # setup
 9933     (clear-stream _test-input-stream)
 9934     (write _test-input-stream "copy-to n, 3\n")
 9935     # var vars/ecx: (stack (addr var) 16)
 9936     81 5/subop/subtract %esp 0xc0/imm32
 9937     68/push 0xc0/imm32/size
 9938     68/push 0/imm32/top
 9939     89/<- %ecx 4/r32/esp
 9940     (clear-stack %ecx)
 9941     # var v/edx: (handle var)
 9942     68/push 0/imm32
 9943     68/push 0/imm32
 9944     89/<- %edx 4/r32/esp
 9945     # var s/eax: (handle array byte)
 9946     68/push 0/imm32
 9947     68/push 0/imm32
 9948     89/<- %eax 4/r32/esp
 9949     # v = new var("n")
 9950     (copy-array Heap "n" %eax)
 9951     (new-var Heap *eax *(eax+4) %edx)
 9952     #
 9953     (push %ecx *edx)
 9954     (push %ecx *(edx+4))
 9955     (push %ecx 0)
 9956     # var out/eax: (handle stmt)
 9957     68/push 0/imm32
 9958     68/push 0/imm32
 9959     89/<- %eax 4/r32/esp
 9960     # convert
 9961     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
 9962     # var out-addr/edx: (addr stmt) = lookup(*out)
 9963     (lookup *eax *(eax+4))  # => eax
 9964     89/<- %edx 0/r32/eax
 9965     # out->tag
 9966     (check-ints-equal *edx 1 "F - test-parse-mu-stmt-with-comma/tag")  # Stmt-tag is Stmt1
 9967     # out->operation
 9968     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
 9969     (check-strings-equal %eax "copy-to" "F - test-parse-mu-stmt-with-comma/name")  # Stmt1-operation
 9970     # out->inouts->value->name
 9971     # . eax = out->inouts
 9972     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9973     # . eax = out->inouts->value
 9974     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9975     # . eax = out->inouts->value->name
 9976     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9977     # .
 9978     (check-strings-equal %eax "n" "F - test-parse-mu-stmt-with-comma/inout:0")
 9979     # . epilogue
 9980     89/<- %esp 5/r32/ebp
 9981     5d/pop-to-ebp
 9982     c3/return
 9983 
 9984 new-var:  # ad: (addr allocation-descriptor), name: (handle array byte), out: (addr handle var)
 9985     # . prologue
 9986     55/push-ebp
 9987     89/<- %ebp 4/r32/esp
 9988     # . save registers
 9989     50/push-eax
 9990     51/push-ecx
 9991     # ecx = out
 9992     8b/-> *(ebp+0x14) 1/r32/ecx
 9993     #
 9994     (allocate *(ebp+8) *Var-size %ecx)
 9995     # var out-addr/eax: (addr var)
 9996     (lookup *ecx *(ecx+4))  # => eax
 9997     # out-addr->name = name
 9998     8b/-> *(ebp+0xc) 1/r32/ecx
 9999     89/<- *eax 1/r32/ecx  # Var-name
10000     8b/-> *(ebp+0x10) 1/r32/ecx
10001     89/<- *(eax+4) 1/r32/ecx  # Var-name
10002 #?     (write-buffered Stderr "var ")
10003 #?     (lookup *(ebp+0xc) *(ebp+0x10))
10004 #?     (write-buffered Stderr %eax)
10005 #?     (write-buffered Stderr " at ")
10006 #?     8b/-> *(ebp+0x14) 1/r32/ecx
10007 #?     (lookup *ecx *(ecx+4))  # => eax
10008 #?     (write-int32-hex-buffered Stderr %eax)
10009 #?     (write-buffered Stderr Newline)
10010 #?     (flush Stderr)
10011 $new-var:end:
10012     # . restore registers
10013     59/pop-to-ecx
10014     58/pop-to-eax
10015     # . epilogue
10016     89/<- %esp 5/r32/ebp
10017     5d/pop-to-ebp
10018     c3/return
10019 
10020 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)
10021     # . prologue
10022     55/push-ebp
10023     89/<- %ebp 4/r32/esp
10024     # . save registers
10025     50/push-eax
10026     51/push-ecx
10027     # if (!is-hex-int?(name)) abort
10028     (is-hex-int? *(ebp+0xc))  # => eax
10029     3d/compare-eax-and 0/imm32/false
10030     0f 84/jump-if-= $new-literal-integer:abort/disp32
10031     # a little more error-checking
10032     (check-mu-hex-int *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
10033     # out = new var(s)
10034     (new-var-from-slice *(ebp+8) *(ebp+0xc) *(ebp+0x10))
10035     # var out-addr/ecx: (addr var) = lookup(*out)
10036     8b/-> *(ebp+0x10) 0/r32/eax
10037     (lookup *eax *(eax+4))  # => eax
10038     89/<- %ecx 0/r32/eax
10039     # out-addr->block-depth = *Curr-block-depth
10040     8b/-> *Curr-block-depth 0/r32/eax
10041     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
10042     # out-addr->type = new tree()
10043     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
10044     (allocate *(ebp+8) *Type-tree-size %eax)
10045     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
10046     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
10047     # nothing else to do; default type is 'literal'
10048 $new-literal-integer:end:
10049     # . reclaim locals
10050     81 0/subop/add %esp 8/imm32
10051     # . restore registers
10052     59/pop-to-ecx
10053     58/pop-to-eax
10054     # . epilogue
10055     89/<- %esp 5/r32/ebp
10056     5d/pop-to-ebp
10057     c3/return
10058 
10059 $new-literal-integer:abort:
10060     (write-buffered *(ebp+0x18) "fn ")
10061     8b/-> *(ebp+0x14) 0/r32/eax
10062     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10063     (write-buffered *(ebp+0x18) %eax)
10064     (write-buffered *(ebp+0x18) ": variable '")
10065     (write-slice-buffered *(ebp+0x18) *(ebp+0xc))
10066     (write-buffered *(ebp+0x18) "' cannot begin with a digit (or do you have a typo in a number?)\n")
10067     (flush *(ebp+0x18))
10068     (stop *(ebp+0x1c) 1)
10069     # never gets here
10070 
10071 # precondition: name is a valid hex integer; require a '0x' prefix
10072 check-mu-hex-int:  # name: (addr slice), err: (addr buffered-file), ed: (addr exit-descriptor)
10073     # . prologue
10074     55/push-ebp
10075     89/<- %ebp 4/r32/esp
10076     # . save registers
10077     50/push-eax
10078     51/push-ecx
10079     52/push-edx
10080     #
10081     8b/-> *(ebp+8) 1/r32/ecx
10082     # var start/ecx: (addr byte) = name->start
10083     8b/-> *(ecx+4) 2/r32/edx
10084     # var end/ecx: (addr byte) = name->end
10085     8b/-> *ecx 1/r32/ecx
10086     # var len/eax: int = name->end - name->start
10087     89/<- %eax 2/r32/edx
10088     29/subtract-from %eax 1/r32/ecx
10089     # if (len <= 1) return
10090     3d/compare-eax-with 1/imm32
10091     0f 8e/jump-if-<= $check-mu-hex-int:end/disp32
10092 $check-mu-hex-int:length->-1:
10093     # if slice-starts-with?("0x") return
10094     (slice-starts-with? *(ebp+8) "0x")  # => eax
10095     3d/compare-eax-with 0/imm32/false
10096     75/jump-if-!= $check-mu-hex-int:end/disp8
10097 $check-mu-hex-int:abort:
10098     # otherwise abort
10099     (write-buffered *(ebp+0xc) "literal integers are always hex in Mu; either start '")
10100     (write-slice-buffered *(ebp+0xc) *(ebp+8))
10101     (write-buffered *(ebp+0xc) "' with a '0x' to be unambiguous, or convert it to decimal.\n")
10102     (flush *(ebp+0xc))
10103     (stop *(ebp+0x10) 1)
10104 $check-mu-hex-int:end:
10105     # . restore registers
10106     5a/pop-to-edx
10107     59/pop-to-ecx
10108     58/pop-to-eax
10109     # . epilogue
10110     89/<- %esp 5/r32/ebp
10111     5d/pop-to-ebp
10112     c3/return
10113 
10114 new-literal:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
10115     # . prologue
10116     55/push-ebp
10117     89/<- %ebp 4/r32/esp
10118     # . save registers
10119     50/push-eax
10120     51/push-ecx
10121     # var s/ecx: (handle array byte)
10122     68/push 0/imm32
10123     68/push 0/imm32
10124     89/<- %ecx 4/r32/esp
10125     # s = slice-to-string(name)
10126     (slice-to-string Heap *(ebp+0xc) %ecx)
10127     # allocate to out
10128     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
10129     # var out-addr/ecx: (addr var) = lookup(*out)
10130     8b/-> *(ebp+0x10) 1/r32/ecx
10131     (lookup *ecx *(ecx+4))  # => eax
10132     89/<- %ecx 0/r32/eax
10133     # out-addr->block-depth = *Curr-block-depth
10134     8b/-> *Curr-block-depth 0/r32/eax
10135     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
10136     # out-addr->type/eax = new type
10137     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
10138     (allocate *(ebp+8) *Type-tree-size %eax)
10139     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
10140     # nothing else to do; default type is 'literal'
10141     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
10142 $new-literal:end:
10143     # . reclaim locals
10144     81 0/subop/add %esp 8/imm32
10145     # . restore registers
10146     59/pop-to-ecx
10147     58/pop-to-eax
10148     # . epilogue
10149     89/<- %esp 5/r32/ebp
10150     5d/pop-to-ebp
10151     c3/return
10152 
10153 new-var-from-slice:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
10154     # . prologue
10155     55/push-ebp
10156     89/<- %ebp 4/r32/esp
10157     # . save registers
10158     51/push-ecx
10159     # var tmp/ecx: (handle array byte)
10160     68/push 0/imm32
10161     68/push 0/imm32
10162     89/<- %ecx 4/r32/esp
10163     # tmp = slice-to-string(name)
10164     (slice-to-string Heap *(ebp+0xc) %ecx)
10165     # out = new-var(tmp)
10166     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
10167 $new-var-from-slice:end:
10168     # . reclaim locals
10169     81 0/subop/add %esp 8/imm32
10170     # . restore registers
10171     59/pop-to-ecx
10172     # . epilogue
10173     89/<- %esp 5/r32/ebp
10174     5d/pop-to-ebp
10175     c3/return
10176 
10177 new-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
10178     # . prologue
10179     55/push-ebp
10180     89/<- %ebp 4/r32/esp
10181     # . save registers
10182     50/push-eax
10183     51/push-ecx
10184     #
10185     (allocate *(ebp+8) *Stmt-size *(ebp+0x14))
10186     # var out-addr/eax: (addr stmt) = lookup(*out)
10187     8b/-> *(ebp+0x14) 0/r32/eax
10188     (lookup *eax *(eax+4))  # => eax
10189     # out-addr->tag = stmt
10190     c7 0/subop/copy *eax 2/imm32/tag/var-on-stack  # Stmt-tag
10191     # result->var = var
10192     8b/-> *(ebp+0xc) 1/r32/ecx
10193     89/<- *(eax+4) 1/r32/ecx  # Vardef-var
10194     8b/-> *(ebp+0x10) 1/r32/ecx
10195     89/<- *(eax+8) 1/r32/ecx  # Vardef-var
10196 $new-var-def:end:
10197     # . restore registers
10198     59/pop-to-ecx
10199     58/pop-to-eax
10200     # . epilogue
10201     89/<- %esp 5/r32/ebp
10202     5d/pop-to-ebp
10203     c3/return
10204 
10205 new-reg-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
10206     # . prologue
10207     55/push-ebp
10208     89/<- %ebp 4/r32/esp
10209     # . save registers
10210     50/push-eax
10211     # eax = out
10212     8b/-> *(ebp+0x14) 0/r32/eax
10213     #
10214     (allocate *(ebp+8) *Stmt-size %eax)
10215     # var out-addr/eax: (addr stmt) = lookup(*out)
10216     (lookup *eax *(eax+4))  # => eax
10217     # set tag
10218     c7 0/subop/copy *eax 3/imm32/tag/var-in-register  # Stmt-tag
10219     # set output
10220     8d/copy-address *(eax+0x14) 0/r32/eax  # Regvardef-outputs
10221     (append-stmt-var Heap  *(ebp+0xc) *(ebp+0x10)  0 0  0  %eax)
10222 $new-reg-var-def:end:
10223     # . restore registers
10224     58/pop-to-eax
10225     # . epilogue
10226     89/<- %esp 5/r32/ebp
10227     5d/pop-to-ebp
10228     c3/return
10229 
10230 append-list:  # ad: (addr allocation-descriptor), value: (handle _type), list: (handle list _type), out: (addr handle list _type)
10231     # . prologue
10232     55/push-ebp
10233     89/<- %ebp 4/r32/esp
10234     # . save registers
10235     50/push-eax
10236     51/push-ecx
10237     57/push-edi
10238     # edi = out
10239     8b/-> *(ebp+0x1c) 7/r32/edi
10240     # *out = new list
10241     (allocate *(ebp+8) *List-size %edi)
10242     # var out-addr/edi: (addr list _type) = lookup(*out)
10243     (lookup *edi *(edi+4))  # => eax
10244     89/<- %edi 0/r32/eax
10245     # out-addr->value = value
10246     8b/-> *(ebp+0xc) 0/r32/eax
10247     89/<- *edi 0/r32/eax  # List-value
10248     8b/-> *(ebp+0x10) 0/r32/eax
10249     89/<- *(edi+4) 0/r32/eax  # List-value
10250     # if (list == null) return
10251     81 7/subop/compare *(ebp+0x14) 0/imm32
10252     74/jump-if-= $append-list:end/disp8
10253     # otherwise append
10254 $append-list:non-empty-list:
10255     # var curr/eax: (addr list _type) = lookup(list)
10256     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
10257     # while (curr->next != null) curr = curr->next
10258     {
10259       81 7/subop/compare *(eax+8) 0/imm32  # List-next
10260       74/jump-if-= break/disp8
10261       # curr = lookup(curr->next)
10262       (lookup *(eax+8) *(eax+0xc))  # List-next, List-next => eax
10263       #
10264       eb/jump loop/disp8
10265     }
10266     # edi = out
10267     8b/-> *(ebp+0x1c) 7/r32/edi
10268     # curr->next = out
10269     8b/-> *edi 1/r32/ecx
10270     89/<- *(eax+8) 1/r32/ecx  # List-next
10271     8b/-> *(edi+4) 1/r32/ecx
10272     89/<- *(eax+0xc) 1/r32/ecx  # List-next
10273     # out = list
10274     8b/-> *(ebp+0x14) 1/r32/ecx
10275     89/<- *edi 1/r32/ecx
10276     8b/-> *(ebp+0x18) 1/r32/ecx
10277     89/<- *(edi+4) 1/r32/ecx
10278 $append-list:end:
10279     # . restore registers
10280     5f/pop-to-edi
10281     59/pop-to-ecx
10282     58/pop-to-eax
10283     # . epilogue
10284     89/<- %esp 5/r32/ebp
10285     5d/pop-to-ebp
10286     c3/return
10287 
10288 append-stmt-var:  # ad: (addr allocation-descriptor), v: (handle var), vars: (handle stmt-var), is-deref?: boolean, out: (addr handle stmt-var)
10289     # . prologue
10290     55/push-ebp
10291     89/<- %ebp 4/r32/esp
10292     # . save registers
10293     50/push-eax
10294     51/push-ecx
10295     57/push-edi
10296     # edi = out
10297     8b/-> *(ebp+0x20) 7/r32/edi
10298     # out = new stmt-var
10299     (allocate *(ebp+8) *Stmt-var-size %edi)
10300     # var out-addr/ecx: (addr stmt-var) = lookup(*out)
10301     (lookup *edi *(edi+4))  # => eax
10302     89/<- %ecx 0/r32/eax
10303     # out-addr->value = v
10304     8b/-> *(ebp+0xc) 0/r32/eax
10305     89/<- *ecx 0/r32/eax  # Stmt-var-value
10306     8b/-> *(ebp+0x10) 0/r32/eax
10307     89/<- *(ecx+4) 0/r32/eax  # Stmt-var-value
10308     # out-addr->is-deref? = is-deref?
10309     8b/-> *(ebp+0x1c) 0/r32/eax
10310     89/<- *(ecx+0x10) 0/r32/eax  # Stmt-var-is-deref
10311     # if (vars == null) return result
10312     81 7/subop/compare *(ebp+0x14) 0/imm32/null
10313     74/jump-if-= $append-stmt-var:end/disp8
10314     # otherwise append
10315     # var curr/eax: (addr stmt-var) = lookup(vars)
10316     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
10317     # while (curr->next != null) curr = curr->next
10318     {
10319       81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
10320       74/jump-if-= break/disp8
10321       # curr = lookup(curr->next)
10322       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next, Stmt-var-next => eax
10323       #
10324       eb/jump loop/disp8
10325     }
10326     # curr->next = out
10327     8b/-> *edi 1/r32/ecx
10328     89/<- *(eax+8) 1/r32/ecx  # Stmt-var-next
10329     8b/-> *(edi+4) 1/r32/ecx
10330     89/<- *(eax+0xc) 1/r32/ecx  # Stmt-var-next
10331     # out = vars
10332     8b/-> *(ebp+0x14) 1/r32/ecx
10333     89/<- *edi 1/r32/ecx
10334     8b/-> *(ebp+0x18) 1/r32/ecx
10335     89/<- *(edi+4) 1/r32/ecx
10336 $append-stmt-var:end:
10337     # . restore registers
10338     5f/pop-to-edi
10339     59/pop-to-ecx
10340     58/pop-to-eax
10341     # . epilogue
10342     89/<- %esp 5/r32/ebp
10343     5d/pop-to-ebp
10344     c3/return
10345 
10346 append-to-block:  # ad: (addr allocation-descriptor), block: (addr block), x: (handle stmt)
10347     # . prologue
10348     55/push-ebp
10349     89/<- %ebp 4/r32/esp
10350     # . save registers
10351     50/push-eax
10352     56/push-esi
10353     # esi = block
10354     8b/-> *(ebp+0xc) 6/r32/esi
10355     # block->stmts = append(x, block->stmts)
10356     8d/copy-address *(esi+4) 0/r32/eax  # Block-stmts
10357     (append-list *(ebp+8)  *(ebp+0x10) *(ebp+0x14)  *(esi+4) *(esi+8)  %eax)  # ad, x, x, Block-stmts, Block-stmts
10358 $append-to-block:end:
10359     # . restore registers
10360     5e/pop-to-esi
10361     58/pop-to-eax
10362     # . epilogue
10363     89/<- %esp 5/r32/ebp
10364     5d/pop-to-ebp
10365     c3/return
10366 
10367 ## Parsing types
10368 # We need to create metadata on user-defined types, and we need to use this
10369 # metadata as we parse instructions.
10370 # However, we also want to allow types to be used before their definitions.
10371 # This means we can't ever assume any type data structures exist.
10372 
10373 lookup-or-create-constant:  # container: (addr stmt-var), field-name: (addr slice), out: (addr handle var)
10374     # . prologue
10375     55/push-ebp
10376     89/<- %ebp 4/r32/esp
10377     # . save registers
10378     50/push-eax
10379     56/push-esi
10380     # var container-type/esi: type-id
10381     (container-type *(ebp+8))  # => eax
10382     89/<- %esi 0/r32/eax
10383     # var tmp/eax: (handle typeinfo) = find-or-create-typeinfo(container-type)
10384     68/push 0/imm32
10385     68/push 0/imm32
10386     89/<- %eax 4/r32/esp
10387     (find-or-create-typeinfo %esi %eax)
10388     # var tmp-addr/eax: (addr typeinfo) = lookup(tmp)
10389     (lookup *eax *(eax+4))  # => eax
10390     # result = find-or-create-typeinfo-output-var(typeinfo, field-name)
10391 #?     (write-buffered Stderr "constant: ")
10392 #?     (write-slice-buffered Stderr *(ebp+0xc))
10393 #?     (write-buffered Stderr Newline)
10394 #?     (flush Stderr)
10395     (find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10))
10396 #?     8b/-> *(ebp+0x10) 0/r32/eax
10397 #?     (write-buffered Stderr "@")
10398 #?     (lookup *eax *(eax+4))
10399 #?     (write-int32-hex-buffered Stderr %eax)
10400 #?     (lookup *eax *(eax+4))
10401 #?     (write-buffered Stderr %eax)
10402 #?     (write-buffered Stderr Newline)
10403 #?     (flush Stderr)
10404 #?     (write-buffered Stderr "offset: ")
10405 #?     8b/-> *(eax+0x14) 0/r32/eax
10406 #?     (write-int32-hex-buffered Stderr %eax)
10407 #?     (write-buffered Stderr Newline)
10408 #?     (flush Stderr)
10409 $lookup-or-create-constant:end:
10410     # . reclaim locals
10411     81 0/subop/add %esp 8/imm32
10412     # . restore registers
10413     5e/pop-to-esi
10414     58/pop-to-eax
10415     # . epilogue
10416     89/<- %esp 5/r32/ebp
10417     5d/pop-to-ebp
10418     c3/return
10419 
10420 # if addr var:
10421 #   container->var->type->right->left->value
10422 # otherwise
10423 #   container->var->type->value
10424 container-type:  # container: (addr stmt-var) -> result/eax: type-id
10425     # . prologue
10426     55/push-ebp
10427     89/<- %ebp 4/r32/esp
10428     #
10429     8b/-> *(ebp+8) 0/r32/eax
10430     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10431     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10432     {
10433       81 7/subop/compare *(eax+8) 0/imm32  # Type-tree-right
10434       74/jump-if-= break/disp8
10435       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
10436       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
10437     }
10438     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
10439 $container-type:end:
10440     # . epilogue
10441     89/<- %esp 5/r32/ebp
10442     5d/pop-to-ebp
10443     c3/return
10444 
10445 is-container?:  # t: type-id -> result/eax: boolean
10446     # . prologue
10447     55/push-ebp
10448     89/<- %ebp 4/r32/esp
10449     #
10450     8b/-> *(ebp+8) 0/r32/eax
10451     c1/shift 4/subop/left %eax 2/imm8
10452     3b/compare 0/r32/eax *Primitive-type-ids
10453     0f 9d/set-if->= %al
10454     81 4/subop/and %eax 0xff/imm32
10455 $is-container?:end:
10456     # . epilogue
10457     89/<- %esp 5/r32/ebp
10458     5d/pop-to-ebp
10459     c3/return
10460 
10461 find-or-create-typeinfo:  # t: type-id, out: (addr handle typeinfo)
10462     # . prologue
10463     55/push-ebp
10464     89/<- %ebp 4/r32/esp
10465     # . save registers
10466     50/push-eax
10467     51/push-ecx
10468     52/push-edx
10469     57/push-edi
10470     # edi = out
10471     8b/-> *(ebp+0xc) 7/r32/edi
10472     # var fields/ecx: (handle table (handle array byte) (handle typeinfo-entry))
10473     68/push 0/imm32
10474     68/push 0/imm32
10475     89/<- %ecx 4/r32/esp
10476     # find-typeinfo(t, out)
10477     (find-typeinfo *(ebp+8) %edi)
10478     {
10479       # if (*out != 0) break
10480       81 7/subop/compare *edi 0/imm32
10481       0f 85/jump-if-!= break/disp32
10482 $find-or-create-typeinfo:create:
10483       # *out = allocate
10484       (allocate Heap *Typeinfo-size %edi)
10485       # var tmp/eax: (addr typeinfo) = lookup(*out)
10486       (lookup *edi *(edi+4))  # => eax
10487 #?     (write-buffered Stderr "created typeinfo at ")
10488 #?     (write-int32-hex-buffered Stderr %eax)
10489 #?     (write-buffered Stderr " for type-id ")
10490 #?     (write-int32-hex-buffered Stderr *(ebp+8))
10491 #?     (write-buffered Stderr Newline)
10492 #?     (flush Stderr)
10493       # tmp->id = t
10494       8b/-> *(ebp+8) 2/r32/edx
10495       89/<- *eax 2/r32/edx  # Typeinfo-id
10496       # tmp->fields = new table
10497       # . fields = new table
10498       (new-stream Heap 0x40 *Typeinfo-fields-row-size %ecx)
10499       # . tmp->fields = fields
10500       8b/-> *ecx 2/r32/edx
10501       89/<- *(eax+4) 2/r32/edx  # Typeinfo-fields
10502       8b/-> *(ecx+4) 2/r32/edx
10503       89/<- *(eax+8) 2/r32/edx  # Typeinfo-fields
10504       # tmp->next = Program->types
10505       8b/-> *_Program-types 1/r32/ecx
10506       89/<- *(eax+0x10) 1/r32/ecx  # Typeinfo-next
10507       8b/-> *_Program-types->payload 1/r32/ecx
10508       89/<- *(eax+0x14) 1/r32/ecx  # Typeinfo-next
10509       # Program->types = out
10510       8b/-> *edi 1/r32/ecx
10511       89/<- *_Program-types 1/r32/ecx
10512       8b/-> *(edi+4) 1/r32/ecx
10513       89/<- *_Program-types->payload 1/r32/ecx
10514     }
10515 $find-or-create-typeinfo:end:
10516     # . reclaim locals
10517     81 0/subop/add %esp 8/imm32
10518     # . restore registers
10519     5f/pop-to-edi
10520     5a/pop-to-edx
10521     59/pop-to-ecx
10522     58/pop-to-eax
10523     # . epilogue
10524     89/<- %esp 5/r32/ebp
10525     5d/pop-to-ebp
10526     c3/return
10527 
10528 find-typeinfo:  # t: type-id, out: (addr handle typeinfo)
10529     # . prologue
10530     55/push-ebp
10531     89/<- %ebp 4/r32/esp
10532     # . save registers
10533     50/push-eax
10534     51/push-ecx
10535     52/push-edx
10536     57/push-edi
10537     # ecx = t
10538     8b/-> *(ebp+8) 1/r32/ecx
10539     # edi = out
10540     8b/-> *(ebp+0xc) 7/r32/edi
10541     # *out = Program->types
10542     8b/-> *_Program-types 0/r32/eax
10543     89/<- *edi 0/r32/eax
10544     8b/-> *_Program-types->payload 0/r32/eax
10545     89/<- *(edi+4) 0/r32/eax
10546     {
10547 $find-typeinfo:loop:
10548       # if (*out == 0) break
10549       81 7/subop/compare *edi 0/imm32
10550       74/jump-if-= break/disp8
10551 $find-typeinfo:check:
10552       # var tmp/eax: (addr typeinfo) = lookup(*out)
10553       (lookup *edi *(edi+4))  # => eax
10554       # if (tmp->id == t) break
10555       39/compare *eax 1/r32/ecx  # Typeinfo-id
10556       74/jump-if-= break/disp8
10557 $find-typeinfo:continue:
10558       # *out = tmp->next
10559       8b/-> *(eax+0x10) 2/r32/edx  # Typeinfo-next
10560       89/<- *edi 2/r32/edx
10561       8b/-> *(eax+0x14) 2/r32/edx  # Typeinfo-next
10562       89/<- *(edi+4) 2/r32/edx
10563       #
10564       eb/jump loop/disp8
10565     }
10566 $find-typeinfo:end:
10567     # . restore registers
10568     5f/pop-to-edi
10569     5a/pop-to-edx
10570     59/pop-to-ecx
10571     58/pop-to-eax
10572     # . epilogue
10573     89/<- %esp 5/r32/ebp
10574     5d/pop-to-ebp
10575     c3/return
10576 
10577 find-or-create-typeinfo-output-var:  # T: (addr typeinfo), f: (addr slice), out: (addr handle var)
10578     # . prologue
10579     55/push-ebp
10580     89/<- %ebp 4/r32/esp
10581     # . save registers
10582     50/push-eax
10583     52/push-edx
10584     57/push-edi
10585     # var dest/edi: (handle typeinfo-entry)
10586     68/push 0/imm32
10587     68/push 0/imm32
10588     89/<- %edi 4/r32/esp
10589     # find-or-create-typeinfo-fields(T, f, dest)
10590     (find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi)
10591     # var dest-addr/edi: (addr typeinfo-entry) = lookup(dest)
10592     (lookup *edi *(edi+4))  # => eax
10593     89/<- %edi 0/r32/eax
10594     # if dest-addr->output-var doesn't exist, create it
10595     {
10596       81 7/subop/compare *(edi+0xc) 0/imm32  # Typeinfo-entry-output-var
10597       0f 85/jump-if-!= break/disp32
10598       # dest-addr->output-var = new var(dummy name, type, -1 offset)
10599       # . var name/eax: (handle array byte) = "field"
10600       68/push 0/imm32
10601       68/push 0/imm32
10602       89/<- %eax 4/r32/esp
10603       (slice-to-string Heap *(ebp+0xc) %eax)
10604       # . new var
10605       8d/copy-address *(edi+0xc) 2/r32/edx
10606       (new-var Heap  *eax *(eax+4)  %edx)
10607       # . reclaim name
10608       81 0/subop/add %esp 8/imm32
10609       # var result/edx: (addr var) = lookup(dest-addr->output-var)
10610       (lookup *(edi+0xc) *(edi+0x10))  # => eax
10611       89/<- %edx 0/r32/eax
10612       # result->type = new constant type
10613       8d/copy-address *(edx+8) 0/r32/eax  # Var-type
10614       (allocate Heap *Type-tree-size %eax)
10615       (lookup *(edx+8) *(edx+0xc))  # => eax
10616       c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
10617       c7 0/subop/copy *(eax+4) 6/imm32/constant  # Type-tree-value
10618       c7 0/subop/copy *(eax+8) 0/imm32  # Type-tree-left
10619       c7 0/subop/copy *(eax+0xc) 0/imm32  # Type-tree-right
10620       c7 0/subop/copy *(eax+0x10) 0/imm32  # Type-tree-right
10621       # result->offset isn't filled out yet
10622       c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized  # Var-offset
10623     }
10624     # out = dest-addr->output-var
10625     8b/-> *(ebp+0x10) 2/r32/edx
10626     8b/-> *(edi+0xc) 0/r32/eax  # Typeinfo-entry-output-var
10627     89/<- *edx 0/r32/eax
10628     8b/-> *(edi+0x10) 0/r32/eax  # Typeinfo-entry-output-var
10629     89/<- *(edx+4) 0/r32/eax
10630 $find-or-create-typeinfo-output-var:end:
10631     # . reclaim locals
10632     81 0/subop/add %esp 8/imm32
10633     # . restore registers
10634     5f/pop-to-edi
10635     5a/pop-to-edx
10636     58/pop-to-eax
10637     # . epilogue
10638     89/<- %esp 5/r32/ebp
10639     5d/pop-to-ebp
10640     c3/return
10641 
10642 find-or-create-typeinfo-fields:  # T: (addr typeinfo), f: (addr slice), out: (addr handle typeinfo-entry)
10643     # . prologue
10644     55/push-ebp
10645     89/<- %ebp 4/r32/esp
10646     # . save registers
10647     50/push-eax
10648     56/push-esi
10649     57/push-edi
10650     # eax = lookup(T->fields)
10651     8b/-> *(ebp+8) 0/r32/eax
10652     (lookup *(eax+4) *(eax+8))  # Typeinfo-fields Typeinfo-fields => eax
10653     # edi = out
10654     8b/-> *(ebp+0x10) 7/r32/edi
10655     # var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f)
10656     (get-or-insert-slice %eax *(ebp+0xc) *Typeinfo-fields-row-size Heap)  # => eax
10657     89/<- %esi 0/r32/eax
10658     # if src doesn't exist, allocate it
10659     {
10660       81 7/subop/compare *esi 0/imm32
10661       75/jump-if-!= break/disp8
10662       (allocate Heap *Typeinfo-entry-size %esi)
10663 #?       (write-buffered Stderr "handle at ")
10664 #?       (write-int32-hex-buffered Stderr %esi)
10665 #?       (write-buffered Stderr ": ")
10666 #?       (write-int32-hex-buffered Stderr *esi)
10667 #?       (write-buffered Stderr " ")
10668 #?       (write-int32-hex-buffered Stderr *(esi+4))
10669 #?       (write-buffered Stderr Newline)
10670 #?       (flush Stderr)
10671 #?       (lookup *esi *(esi+4))
10672 #?       (write-buffered Stderr "created typeinfo fields at ")
10673 #?       (write-int32-hex-buffered Stderr %esi)
10674 #?       (write-buffered Stderr " for ")
10675 #?       (write-int32-hex-buffered Stderr *(ebp+8))
10676 #?       (write-buffered Stderr Newline)
10677 #?       (flush Stderr)
10678     }
10679     # *out = src
10680     # . *edi = *src
10681     8b/-> *esi 0/r32/eax
10682     89/<- *edi 0/r32/eax
10683     8b/-> *(esi+4) 0/r32/eax
10684     89/<- *(edi+4) 0/r32/eax
10685 $find-or-create-typeinfo-fields:end:
10686     # . restore registers
10687     5f/pop-to-edi
10688     5e/pop-to-esi
10689     58/pop-to-eax
10690     # . epilogue
10691     89/<- %esp 5/r32/ebp
10692     5d/pop-to-ebp
10693     c3/return
10694 
10695 populate-mu-type:  # in: (addr stream byte), t: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
10696     # pseudocode:
10697     #   var line: (stream byte 512)
10698     #   curr-index = 0
10699     #   while true
10700     #     clear-stream(line)
10701     #     read-line-buffered(in, line)
10702     #     if line->write == 0
10703     #       abort
10704     #     word-slice = next-mu-token(line)
10705     #     if slice-empty?(word-slice)               # end of line
10706     #       continue
10707     #     if slice-equal?(word-slice, "}")
10708     #       break
10709     #     var v: (handle var) = parse-var-with-type(word-slice, line)
10710     #     var r: (handle typeinfo-fields) = find-or-create-typeinfo-fields(t, word-slice/v->name)
10711     #     TODO: ensure that r->first is null
10712     #     r->index = curr-index
10713     #     curr-index++
10714     #     r->input-var = v
10715     #     if r->output-var == 0
10716     #       r->output-var = new literal
10717     #     TODO: ensure nothing else in line
10718     # t->total-size-in-bytes = -2 (not yet initialized)
10719     #
10720     # . prologue
10721     55/push-ebp
10722     89/<- %ebp 4/r32/esp
10723     # var curr-index: int at *(ebp-4)
10724     68/push 0/imm32
10725     # . save registers
10726     50/push-eax
10727     51/push-ecx
10728     52/push-edx
10729     53/push-ebx
10730     56/push-esi
10731     57/push-edi
10732     # edi = t
10733     8b/-> *(ebp+0xc) 7/r32/edi
10734     # var line/ecx: (stream byte 512)
10735     81 5/subop/subtract %esp 0x200/imm32
10736     68/push 0x200/imm32/size
10737     68/push 0/imm32/read
10738     68/push 0/imm32/write
10739     89/<- %ecx 4/r32/esp
10740     # var word-slice/edx: slice
10741     68/push 0/imm32/end
10742     68/push 0/imm32/start
10743     89/<- %edx 4/r32/esp
10744     # var v/esi: (handle var)
10745     68/push 0/imm32
10746     68/push 0/imm32
10747     89/<- %esi 4/r32/esp
10748     # var r/ebx: (handle typeinfo-entry)
10749     68/push 0/imm32
10750     68/push 0/imm32
10751     89/<- %ebx 4/r32/esp
10752     {
10753 $populate-mu-type:line-loop:
10754       (clear-stream %ecx)
10755       (read-line-buffered *(ebp+8) %ecx)
10756       # if (line->write == 0) abort
10757       81 7/subop/compare *ecx 0/imm32
10758       0f 84/jump-if-= $populate-mu-type:error1/disp32
10759 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
10765       (next-mu-token %ecx %edx)
10766       # if slice-empty?(word-slice) continue
10767       (slice-empty? %edx)  # => eax
10768       3d/compare-eax-and 0/imm32
10769       0f 85/jump-if-!= loop/disp32
10770       # if slice-equal?(word-slice, "}") break
10771       (slice-equal? %edx "}")
10772       3d/compare-eax-and 0/imm32
10773       0f 85/jump-if-!= break/disp32
10774 $populate-mu-type:parse-element:
10775       # v = parse-var-with-type(word-slice, first-line)
10776       # must do this first to strip the trailing ':' from word-slice before
10777       # using it in find-or-create-typeinfo-fields below
10778       # TODO: clean up that mutation in parse-var-with-type
10779       (parse-var-with-type %edx %ecx %esi *(ebp+0x10) *(ebp+0x14))
10780       # if v is an addr, abort
10781       (lookup *esi *(esi+4))  # => eax
10782       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10783       (is-mu-addr-type? %eax)  # => eax
10784       3d/compare-eax-and 0/imm32/false
10785       0f 85/jump-if-!= $populate-mu-type:error2/disp32
10786       # if v is an array, abort  (we could support it, but initialization gets complex)
10787       (lookup *esi *(esi+4))  # => eax
10788       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10789       (is-mu-array-type? %eax)  # => eax
10790       3d/compare-eax-and 0/imm32/false
10791       0f 85/jump-if-!= $populate-mu-type:error3/disp32
10792       # var tmp/ecx
10793       51/push-ecx
10794 $populate-mu-type:create-typeinfo-fields:
10795       # var r/ebx: (handle typeinfo-entry)
10796       (find-or-create-typeinfo-fields %edi %edx %ebx)
10797       # r->index = curr-index
10798       (lookup *ebx *(ebx+4))  # => eax
10799       8b/-> *(ebp-4) 1/r32/ecx
10800 #?       (write-buffered Stderr "saving index ")
10801 #?       (write-int32-hex-buffered Stderr %ecx)
10802 #?       (write-buffered Stderr " at ")
10803 #?       (write-int32-hex-buffered Stderr %edi)
10804 #?       (write-buffered Stderr Newline)
10805 #?       (flush Stderr)
10806       89/<- *(eax+8) 1/r32/ecx  # Typeinfo-entry-index
10807       # ++curr-index
10808       ff 0/subop/increment *(ebp-4)
10809 $populate-mu-type:set-input-type:
10810       # r->input-var = v
10811       8b/-> *esi 1/r32/ecx
10812       89/<- *eax 1/r32/ecx  # Typeinfo-entry-input-var
10813       8b/-> *(esi+4) 1/r32/ecx
10814       89/<- *(eax+4) 1/r32/ecx  # Typeinfo-entry-input-var
10815       # restore line
10816       59/pop-to-ecx
10817       {
10818 $populate-mu-type:create-output-type:
10819         # if (r->output-var == 0) create a new var with some placeholder data
10820         81 7/subop/compare *(eax+0xc) 0/imm32  # Typeinfo-entry-output-var
10821         75/jump-if-!= break/disp8
10822         8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
10823         (new-literal Heap %edx %eax)
10824       }
10825       e9/jump loop/disp32
10826     }
10827 $populate-mu-type:invalidate-total-size-in-bytes:
10828     # Offsets and total size may not be accurate here since we may not yet
10829     # have encountered the element types.
10830     # We'll recompute them separately after parsing the entire program.
10831     c7 0/subop/copy *(edi+0xc) -2/imm32/uninitialized  # Typeinfo-total-size-in-bytes
10832 $populate-mu-type:end:
10833     # . reclaim locals
10834     81 0/subop/add %esp 0x224/imm32
10835     # . restore registers
10836     5f/pop-to-edi
10837     5e/pop-to-esi
10838     5b/pop-to-ebx
10839     5a/pop-to-edx
10840     59/pop-to-ecx
10841     58/pop-to-eax
10842     # reclaim curr-index
10843     81 0/subop/add %esp 4/imm32
10844     # . epilogue
10845     89/<- %esp 5/r32/ebp
10846     5d/pop-to-ebp
10847     c3/return
10848 
10849 $populate-mu-type:error1:
10850     # error("incomplete type definition '" t->name "'\n")
10851     (write-buffered *(ebp+0x10) "incomplete type definition '")
10852     (type-name *edi)  # Typeinfo-id => eax
10853     (write-buffered *(ebp+0x10) %eax)
10854     (write-buffered *(ebp+0x10) "\n")
10855     (flush *(ebp+0x10))
10856     (stop *(ebp+0x14) 1)
10857     # never gets here
10858 
10859 $populate-mu-type:error2:
10860     # error("type " t->name ": invalid type 'addr'\n")
10861     (write-buffered *(ebp+0x10) "type ")
10862     (type-name *edi)  # Typeinfo-id => eax
10863     (write-buffered *(ebp+0x10) %eax)
10864     (write-buffered *(ebp+0x10) ": invalid type 'addr'\n")
10865     (flush *(ebp+0x10))
10866     (stop *(ebp+0x14) 1)
10867     # never gets here
10868 
10869 $populate-mu-type:error3:
10870     # error("type " t->name ": invalid type 'array'\n")
10871     (write-buffered *(ebp+0x10) "type ")
10872     (type-name *edi)  # Typeinfo-id => eax
10873     (write-buffered *(ebp+0x10) %eax)
10874     (write-buffered *(ebp+0x10) ": invalid type 'array'\n")
10875     (flush *(ebp+0x10))
10876     (stop *(ebp+0x14) 1)
10877     # never gets here
10878 
10879 type-name:  # index: int -> result/eax: (addr array byte)
10880     # . prologue
10881     55/push-ebp
10882     89/<- %ebp 4/r32/esp
10883     #
10884     (index Type-id *(ebp+8))
10885 $type-name:end:
10886     # . epilogue
10887     89/<- %esp 5/r32/ebp
10888     5d/pop-to-ebp
10889     c3/return
10890 
10891 index:  # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte)
10892     # . prologue
10893     55/push-ebp
10894     89/<- %ebp 4/r32/esp
10895     # . save registers
10896     56/push-esi
10897     # TODO: bounds-check index
10898     # esi = arr
10899     8b/-> *(ebp+8) 6/r32/esi
10900     # eax = index
10901     8b/-> *(ebp+0xc) 0/r32/eax
10902     # eax = *(arr + 12 + index)
10903     8b/-> *(esi+eax<<2+0xc) 0/r32/eax
10904 $index:end:
10905     # . restore registers
10906     5e/pop-to-esi
10907     # . epilogue
10908     89/<- %esp 5/r32/ebp
10909     5d/pop-to-ebp
10910     c3/return
10911 
10912 #######################################################
10913 # Compute type sizes
10914 #######################################################
10915 
10916 # Compute the sizes of all user-defined types.
10917 # We'll need the sizes of their elements, which may be other user-defined
10918 # types, which we will compute as needed.
10919 
10920 # Initially, all user-defined types have their sizes set to -2 (invalid)
10921 populate-mu-type-sizes:  # err: (addr buffered-file), ed: (addr exit-descriptor)
10922     # . prologue
10923     55/push-ebp
10924     89/<- %ebp 4/r32/esp
10925 $populate-mu-type-sizes:total-sizes:
10926     # var curr/eax: (addr typeinfo) = lookup(Program->types)
10927     (lookup *_Program-types *_Program-types->payload)  # => eax
10928     {
10929       # if (curr == null) break
10930       3d/compare-eax-and 0/imm32/null
10931       74/jump-if-= break/disp8
10932       (populate-mu-type-sizes-in-type %eax *(ebp+8) *(ebp+0xc))
10933       # curr = lookup(curr->next)
10934       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
10935       eb/jump loop/disp8
10936     }
10937 $populate-mu-type-sizes:offsets:
10938     # curr = *Program->types
10939     (lookup *_Program-types *_Program-types->payload)  # => eax
10940     {
10941       # if (curr == null) break
10942       3d/compare-eax-and 0/imm32/null
10943       74/jump-if-= break/disp8
10944       (populate-mu-type-offsets %eax *(ebp+8) *(ebp+0xc))
10945       # curr = curr->next
10946       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
10947       eb/jump loop/disp8
10948     }
10949 $populate-mu-type-sizes:end:
10950     # . epilogue
10951     89/<- %esp 5/r32/ebp
10952     5d/pop-to-ebp
10953     c3/return
10954 
10955 # compute sizes of all fields, recursing as necessary
10956 # sum up all their sizes to arrive at total size
10957 # fields may be out of order, but that doesn't affect the answer
10958 populate-mu-type-sizes-in-type:  # T: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
10959     # . prologue
10960     55/push-ebp
10961     89/<- %ebp 4/r32/esp
10962     # . save registers
10963     50/push-eax
10964     51/push-ecx
10965     52/push-edx
10966     56/push-esi
10967     57/push-edi
10968     # esi = T
10969     8b/-> *(ebp+8) 6/r32/esi
10970     # if T is already computed, return
10971     81 7/subop/compare *(esi+0xc) 0/imm32  # Typeinfo-total-size-in-bytes
10972     0f 8d/jump-if->= $populate-mu-type-sizes-in-type:end/disp32
10973     # if T is being computed, abort
10974     81 7/subop/compare *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
10975     0f 84/jump-if-= $populate-mu-type-sizes-in-type:abort/disp32
10976     # tag T (-2 to -1) to avoid infinite recursion
10977     c7 0/subop/copy *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
10978     # var total-size/edi: int = 0
10979     bf/copy-to-edi 0/imm32
10980     # - for every field, if it's a user-defined type, compute its size
10981     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
10982     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
10983     89/<- %ecx 0/r32/eax
10984     # var table-size/edx: int = table->write
10985     8b/-> *ecx 2/r32/edx  # stream-write
10986     # var curr/ecx: (addr table_row) = table->data
10987     8d/copy-address *(ecx+0xc) 1/r32/ecx
10988     # var max/edx: (addr table_row) = table->data + table->write
10989     8d/copy-address *(ecx+edx) 2/r32/edx
10990     {
10991 $populate-mu-type-sizes-in-type:loop:
10992       # if (curr >= max) break
10993       39/compare %ecx 2/r32/edx
10994       73/jump-if-addr>= break/disp8
10995       # var t/eax: (addr typeinfo-entry) = lookup(curr->value)
10996       (lookup *(ecx+8) *(ecx+0xc))  # => eax
10997       # if (t->input-var == 0) silently ignore it; we'll emit a nice error message while type-checking
10998       81 7/subop/compare *eax 0/imm32  # Typeinfo-entry-input-var
10999       74/jump-if-= $populate-mu-type-sizes-in-type:end/disp8
11000       # compute size of t->input-var
11001       (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
11002       (compute-size-of-var %eax)  # => eax
11003       # result += eax
11004       01/add-to %edi 0/r32/eax
11005       # curr += row-size
11006       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
11007       #
11008       eb/jump loop/disp8
11009     }
11010     # - save result
11011     89/<- *(esi+0xc) 7/r32/edi  # Typeinfo-total-size-in-bytes
11012 $populate-mu-type-sizes-in-type:end:
11013     # . restore registers
11014     5f/pop-to-edi
11015     5e/pop-to-esi
11016     5a/pop-to-edx
11017     59/pop-to-ecx
11018     58/pop-to-eax
11019     # . epilogue
11020     89/<- %esp 5/r32/ebp
11021     5d/pop-to-ebp
11022     c3/return
11023 
11024 $populate-mu-type-sizes-in-type:abort:
11025     (write-buffered *(ebp+0xc) "cycle in type definitions\n")
11026     (flush *(ebp+0xc))
11027     (stop *(ebp+0x10) 1)
11028     # never gets here
11029 
11030 # Analogous to size-of, except we need to compute what size-of can just read
11031 # off the right data structures.
11032 compute-size-of-var:  # in: (addr var) -> result/eax: int
11033     # . prologue
11034     55/push-ebp
11035     89/<- %ebp 4/r32/esp
11036     # . push registers
11037     51/push-ecx
11038     # var t/ecx: (addr type-tree) = lookup(v->type)
11039     8b/-> *(ebp+8) 1/r32/ecx
11040     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
11041     89/<- %ecx 0/r32/eax
11042     # if (t->is-atom == false) t = lookup(t->left)
11043     {
11044       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
11045       75/jump-if-!= break/disp8
11046       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
11047       89/<- %ecx 0/r32/eax
11048     }
11049     # TODO: ensure t is an atom
11050     (compute-size-of-type-id *(ecx+4))  # Type-tree-value => eax
11051 $compute-size-of-var:end:
11052     # . restore registers
11053     59/pop-to-ecx
11054     # . epilogue
11055     89/<- %esp 5/r32/ebp
11056     5d/pop-to-ebp
11057     c3/return
11058 
11059 compute-size-of-type-id:  # t: type-id -> result/eax: int
11060     # . prologue
11061     55/push-ebp
11062     89/<- %ebp 4/r32/esp
11063     # . save registers
11064     51/push-ecx
11065     # var out/ecx: (handle typeinfo)
11066     68/push 0/imm32
11067     68/push 0/imm32
11068     89/<- %ecx 4/r32/esp
11069     # eax = t
11070     8b/-> *(ebp+8) 0/r32/eax
11071     # if t is a literal, return 0
11072     3d/compare-eax-and 0/imm32/literal
11073     0f 84/jump-if-= $compute-size-of-type-id:end/disp32  # eax changes type from type-id to int
11074     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
11075     3d/compare-eax-and 8/imm32/byte
11076     {
11077       75/jump-if-!= break/disp8
11078       b8/copy-to-eax 4/imm32
11079       eb/jump $compute-size-of-type-id:end/disp8
11080     }
11081     # if t is a handle, return 8
11082     3d/compare-eax-and 4/imm32/handle
11083     {
11084       75/jump-if-!= break/disp8
11085       b8/copy-to-eax 8/imm32
11086       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
11087     }
11088     # if t is a user-defined type, compute its size
11089     # TODO: support non-atom type
11090     (find-typeinfo %eax %ecx)
11091     {
11092       81 7/subop/compare *ecx 0/imm32
11093       74/jump-if-= break/disp8
11094 $compute-size-of-type-id:user-defined:
11095       (populate-mu-type-sizes %eax)
11096       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
11097       eb/jump $compute-size-of-type-id:end/disp8
11098     }
11099     # otherwise return the word size
11100     b8/copy-to-eax 4/imm32
11101 $compute-size-of-type-id:end:
11102     # . reclaim locals
11103     81 0/subop/add %esp 8/imm32
11104     # . restore registers
11105     59/pop-to-ecx
11106     # . epilogue
11107     89/<- %esp 5/r32/ebp
11108     5d/pop-to-ebp
11109     c3/return
11110 
11111 # at this point we have total sizes for all user-defined types
11112 # compute offsets for each element
11113 # complication: fields may be out of order
11114 populate-mu-type-offsets:  # in: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
11115     # . prologue
11116     55/push-ebp
11117     89/<- %ebp 4/r32/esp
11118     # . save registers
11119     50/push-eax
11120     51/push-ecx
11121     52/push-edx
11122     53/push-ebx
11123     56/push-esi
11124     57/push-edi
11125 #?     (dump-typeinfos "aaa\n")
11126     # var curr-offset/edi: int = 0
11127     bf/copy-to-edi 0/imm32
11128     # var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(in->fields)
11129     8b/-> *(ebp+8) 1/r32/ecx
11130     (lookup *(ecx+4) *(ecx+8))  # Typeinfo-fields Typeinfo-fields => eax
11131     89/<- %ecx 0/r32/eax
11132     # var num-elems/edx: int = table->write / Typeinfo-fields-row-size
11133     8b/-> *ecx 2/r32/edx  # stream-write
11134     c1 5/subop/shift-right-logical  %edx 4/imm8
11135     # var i/ebx: int = 0
11136     bb/copy-to-ebx 0/imm32
11137     {
11138 $populate-mu-type-offsets:loop:
11139       39/compare %ebx 2/r32/edx
11140       0f 8d/jump-if->= break/disp32
11141 #?       (write-buffered Stderr "looking up index ")
11142 #?       (write-int32-hex-buffered Stderr %ebx)
11143 #?       (write-buffered Stderr " in ")
11144 #?       (write-int32-hex-buffered Stderr *(ebp+8))
11145 #?       (write-buffered Stderr Newline)
11146 #?       (flush Stderr)
11147       # var v/esi: (addr typeinfo-entry)
11148       (locate-typeinfo-entry-with-index %ecx %ebx *(ebp+0xc) *(ebp+0x10))  # => eax
11149       89/<- %esi 0/r32/eax
11150       # if v is null, silently move on; we'll emit a nice error message while type-checking
11151       81 7/subop/compare %esi 0/imm32  # Typeinfo-entry-input-var
11152       74/jump-if-= $populate-mu-type-offsets:end/disp8
11153       # if (v->input-var == 0) silently ignore v; we'll emit a nice error message while type-checking
11154       81 7/subop/compare *esi 0/imm32  # Typeinfo-entry-input-var
11155       74/jump-if-= $populate-mu-type-offsets:end/disp8
11156       # v->output-var->offset = curr-offset
11157       # . eax: (addr var)
11158       (lookup *(esi+0xc) *(esi+0x10))  # Typeinfo-entry-output-var Typeinfo-entry-output-var => eax
11159       89/<- *(eax+0x14) 7/r32/edi  # Var-offset
11160       # curr-offset += size-of(v->input-var)
11161       (lookup *esi *(esi+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
11162       (size-of %eax)  # => eax
11163       01/add-to %edi 0/r32/eax
11164       # ++i
11165       43/increment-ebx
11166       e9/jump loop/disp32
11167     }
11168 $populate-mu-type-offsets:end:
11169     # . restore registers
11170     5f/pop-to-edi
11171     5e/pop-to-esi
11172     5b/pop-to-ebx
11173     5a/pop-to-edx
11174     59/pop-to-ecx
11175     58/pop-to-eax
11176     # . epilogue
11177     89/<- %esp 5/r32/ebp
11178     5d/pop-to-ebp
11179     c3/return
11180 
11181 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)
11182     # . prologue
11183     55/push-ebp
11184     89/<- %ebp 4/r32/esp
11185     # . save registers
11186     51/push-ecx
11187     52/push-edx
11188     53/push-ebx
11189     56/push-esi
11190     57/push-edi
11191     # esi = table
11192     8b/-> *(ebp+8) 6/r32/esi
11193     # var curr/ecx: (addr row (handle array byte) (handle typeinfo-entry)) = table->data
11194     8d/copy-address *(esi+0xc) 1/r32/ecx
11195     # var max/edx: (addr byte) = &table->data[table->write]
11196     8b/-> *esi 2/r32/edx
11197     8d/copy-address *(ecx+edx) 2/r32/edx
11198     {
11199 $locate-typeinfo-entry-with-index:loop:
11200       39/compare %ecx 2/r32/edx
11201       73/jump-if-addr>= break/disp8
11202       # var v/eax: (addr typeinfo-entry)
11203       (lookup *(ecx+8) *(ecx+0xc))  # => eax
11204       # if (v->index == idx) return v
11205       8b/-> *(eax+8) 3/r32/ebx  # Typeinfo-entry-index
11206 #?       (write-buffered Stderr "comparing ")
11207 #?       (write-int32-hex-buffered Stderr %ebx)
11208 #?       (write-buffered Stderr " and ")
11209 #?       (write-int32-hex-buffered Stderr *(ebp+0xc))
11210 #?       (write-buffered Stderr Newline)
11211 #?       (flush Stderr)
11212       39/compare *(ebp+0xc) 3/r32/ebx
11213       74/jump-if-= $locate-typeinfo-entry-with-index:end/disp8
11214       # curr += Typeinfo-entry-size
11215       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-entry-size
11216       #
11217       eb/jump loop/disp8
11218     }
11219     # return 0
11220     b8/copy-to-eax 0/imm32
11221 $locate-typeinfo-entry-with-index:end:
11222 #?     (write-buffered Stderr "returning ")
11223 #?     (write-int32-hex-buffered Stderr %eax)
11224 #?     (write-buffered Stderr Newline)
11225 #?     (flush Stderr)
11226     # . restore registers
11227     5f/pop-to-edi
11228     5e/pop-to-esi
11229     5b/pop-to-ebx
11230     5a/pop-to-edx
11231     59/pop-to-ecx
11232     # . epilogue
11233     89/<- %esp 5/r32/ebp
11234     5d/pop-to-ebp
11235     c3/return
11236 
11237 dump-typeinfos:  # hdr: (addr array byte)
11238     # . prologue
11239     55/push-ebp
11240     89/<- %ebp 4/r32/esp
11241     # . save registers
11242     50/push-eax
11243     #
11244     (write-buffered Stderr *(ebp+8))
11245     (flush Stderr)
11246     # var curr/eax: (addr typeinfo) = lookup(Program->types)
11247     (lookup *_Program-types *_Program-types->payload)  # => eax
11248     {
11249       # if (curr == null) break
11250       3d/compare-eax-and 0/imm32
11251       74/jump-if-= break/disp8
11252       (write-buffered Stderr "---\n")
11253       (flush Stderr)
11254       (dump-typeinfo %eax)
11255       # curr = lookup(curr->next)
11256       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
11257       eb/jump loop/disp8
11258     }
11259 $dump-typeinfos:end:
11260     # . restore registers
11261     58/pop-to-eax
11262     # . epilogue
11263     89/<- %esp 5/r32/ebp
11264     5d/pop-to-ebp
11265     c3/return
11266 
11267 dump-typeinfo:  # in: (addr typeinfo)
11268     # . prologue
11269     55/push-ebp
11270     89/<- %ebp 4/r32/esp
11271     # . save registers
11272     50/push-eax
11273     51/push-ecx
11274     52/push-edx
11275     53/push-ebx
11276     56/push-esi
11277     57/push-edi
11278     # esi = in
11279     8b/-> *(ebp+8) 6/r32/esi
11280     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
11281     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
11282     89/<- %ecx 0/r32/eax
11283     (write-buffered Stderr "id:")
11284     (write-int32-hex-buffered Stderr *esi)
11285     (write-buffered Stderr "\n")
11286     (write-buffered Stderr "fields @ ")
11287     (write-int32-hex-buffered Stderr %ecx)
11288     (write-buffered Stderr Newline)
11289     (flush Stderr)
11290     (write-buffered Stderr "  write: ")
11291     (write-int32-hex-buffered Stderr *ecx)
11292     (write-buffered Stderr Newline)
11293     (flush Stderr)
11294     (write-buffered Stderr "  read: ")
11295     (write-int32-hex-buffered Stderr *(ecx+4))
11296     (write-buffered Stderr Newline)
11297     (flush Stderr)
11298     (write-buffered Stderr "  size: ")
11299     (write-int32-hex-buffered Stderr *(ecx+8))
11300     (write-buffered Stderr Newline)
11301     (flush Stderr)
11302     # var table-size/edx: int = table->write
11303     8b/-> *ecx 2/r32/edx  # stream-write
11304     # var curr/ecx: (addr table_row) = table->data
11305     8d/copy-address *(ecx+0xc) 1/r32/ecx
11306     # var max/edx: (addr table_row) = table->data + table->write
11307     8d/copy-address *(ecx+edx) 2/r32/edx
11308     {
11309 $dump-typeinfo:loop:
11310       # if (curr >= max) break
11311       39/compare %ecx 2/r32/edx
11312       0f 83/jump-if-addr>= break/disp32
11313       (write-buffered Stderr "  row:\n")
11314       (write-buffered Stderr "    key: ")
11315       (write-int32-hex-buffered Stderr *ecx)
11316       (write-buffered Stderr ",")
11317       (write-int32-hex-buffered Stderr *(ecx+4))
11318       (write-buffered Stderr " = '")
11319       (lookup *ecx *(ecx+4))
11320       (write-buffered Stderr %eax)
11321       (write-buffered Stderr "' @ ")
11322       (write-int32-hex-buffered Stderr %eax)
11323       (write-buffered Stderr Newline)
11324       (flush Stderr)
11325       (write-buffered Stderr "    value: ")
11326       (write-int32-hex-buffered Stderr *(ecx+8))
11327       (write-buffered Stderr ",")
11328       (write-int32-hex-buffered Stderr *(ecx+0xc))
11329       (write-buffered Stderr " = typeinfo-entry@")
11330       (lookup *(ecx+8) *(ecx+0xc))
11331       (write-int32-hex-buffered Stderr %eax)
11332       (write-buffered Stderr Newline)
11333       (flush Stderr)
11334       (write-buffered Stderr "        input var@")
11335       (dump-var 5 %eax)
11336       (lookup *(ecx+8) *(ecx+0xc))
11337       (write-buffered Stderr "        index: ")
11338       (write-int32-hex-buffered Stderr *(eax+8))
11339       (write-buffered Stderr Newline)
11340       (flush Stderr)
11341       (write-buffered Stderr "        output var@")
11342       8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
11343       (dump-var 5 %eax)
11344       (flush Stderr)
11345       # curr += row-size
11346       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
11347       #
11348       e9/jump loop/disp32
11349     }
11350 $dump-typeinfo:end:
11351     # . restore registers
11352     5f/pop-to-edi
11353     5e/pop-to-esi
11354     5b/pop-to-ebx
11355     5a/pop-to-edx
11356     59/pop-to-ecx
11357     58/pop-to-eax
11358     # . epilogue
11359     89/<- %esp 5/r32/ebp
11360     5d/pop-to-ebp
11361     c3/return
11362 
11363 dump-var:  # indent: int, v: (addr handle var)
11364     # . prologue
11365     55/push-ebp
11366     89/<- %ebp 4/r32/esp
11367     # . save registers
11368     50/push-eax
11369     53/push-ebx
11370     # eax = v
11371     8b/-> *(ebp+0xc) 0/r32/eax
11372     #
11373     (write-int32-hex-buffered Stderr *eax)
11374     (write-buffered Stderr ",")
11375     (write-int32-hex-buffered Stderr *(eax+4))
11376     (write-buffered Stderr "->")
11377     (lookup *eax *(eax+4))
11378     (write-int32-hex-buffered Stderr %eax)
11379     (write-buffered Stderr Newline)
11380     (flush Stderr)
11381     {
11382       3d/compare-eax-and 0/imm32
11383       0f 84/jump-if-= break/disp32
11384       (emit-indent Stderr *(ebp+8))
11385       (write-buffered Stderr "name: ")
11386       89/<- %ebx 0/r32/eax
11387       (write-int32-hex-buffered Stderr *ebx)  # Var-name
11388       (write-buffered Stderr ",")
11389       (write-int32-hex-buffered Stderr *(ebx+4))  # Var-name
11390       (write-buffered Stderr "->")
11391       (lookup *ebx *(ebx+4))  # Var-name
11392       (write-int32-hex-buffered Stderr %eax)
11393       {
11394         3d/compare-eax-and 0/imm32
11395         74/jump-if-= break/disp8
11396         (write-buffered Stderr Space)
11397         (write-buffered Stderr %eax)
11398       }
11399       (write-buffered Stderr Newline)
11400       (flush Stderr)
11401       (emit-indent Stderr *(ebp+8))
11402       (write-buffered Stderr "block depth: ")
11403       (write-int32-hex-buffered Stderr *(ebx+0x10))  # Var-block-depth
11404       (write-buffered Stderr Newline)
11405       (flush Stderr)
11406       (emit-indent Stderr *(ebp+8))
11407       (write-buffered Stderr "stack offset: ")
11408       (write-int32-hex-buffered Stderr *(ebx+0x14))  # Var-offset
11409       (write-buffered Stderr Newline)
11410       (flush Stderr)
11411       (emit-indent Stderr *(ebp+8))
11412       (write-buffered Stderr "reg: ")
11413       (write-int32-hex-buffered Stderr *(ebx+0x18))  # Var-register
11414       (write-buffered Stderr ",")
11415       (write-int32-hex-buffered Stderr *(ebx+0x1c))  # Var-register
11416       (write-buffered Stderr "->")
11417       (flush Stderr)
11418       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register
11419       (write-int32-hex-buffered Stderr %eax)
11420       {
11421         3d/compare-eax-and 0/imm32
11422         74/jump-if-= break/disp8
11423         (write-buffered Stderr Space)
11424         (write-buffered Stderr %eax)
11425       }
11426       (write-buffered Stderr Newline)
11427       (flush Stderr)
11428     }
11429 $dump-var:end:
11430     # . restore registers
11431     5b/pop-to-ebx
11432     58/pop-to-eax
11433     # . epilogue
11434     89/<- %esp 5/r32/ebp
11435     5d/pop-to-ebp
11436     c3/return
11437 
11438 #######################################################
11439 # Type-checking
11440 #######################################################
11441 
11442 check-mu-types:  # err: (addr buffered-file), ed: (addr exit-descriptor)
11443     # . prologue
11444     55/push-ebp
11445     89/<- %ebp 4/r32/esp
11446     # . save registers
11447     50/push-eax
11448     # var curr/eax: (addr function) = lookup(Program->functions)
11449     (lookup *_Program-functions *_Program-functions->payload)  # => eax
11450     {
11451 $check-mu-types:loop:
11452       # if (curr == null) break
11453       3d/compare-eax-and 0/imm32
11454       0f 84/jump-if-= break/disp32
11455 +--  8 lines: #?       # dump curr->name ------------------------------------------------------------------------------------------------------------------------------------------------
11463       (check-mu-function %eax *(ebp+8) *(ebp+0xc))
11464       # curr = lookup(curr->next)
11465       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
11466       e9/jump loop/disp32
11467     }
11468 $check-mu-types:end:
11469     # . restore registers
11470     58/pop-to-eax
11471     # . epilogue
11472     89/<- %esp 5/r32/ebp
11473     5d/pop-to-ebp
11474     c3/return
11475 
11476 check-mu-function:  # fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11477     # . prologue
11478     55/push-ebp
11479     89/<- %ebp 4/r32/esp
11480     # . save registers
11481     50/push-eax
11482     # eax = f
11483     8b/-> *(ebp+8) 0/r32/eax
11484     # TODO: anything to check in header?
11485     # var body/eax: (addr block) = lookup(f->body)
11486     (lookup *(eax+0x18) *(eax+0x1c))  # Function-body Function-body => eax
11487     (check-mu-block %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10))
11488 $check-mu-function:end:
11489     # . restore registers
11490     58/pop-to-eax
11491     # . epilogue
11492     89/<- %esp 5/r32/ebp
11493     5d/pop-to-ebp
11494     c3/return
11495 
11496 check-mu-block:  # block: (addr block), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11497     # . prologue
11498     55/push-ebp
11499     89/<- %ebp 4/r32/esp
11500     # . save registers
11501     50/push-eax
11502     # eax = block
11503     8b/-> *(ebp+8) 0/r32/eax
11504     # var stmts/eax: (addr list stmt) = lookup(block->statements)
11505     (lookup *(eax+4) *(eax+8))  # Block-stmts Block-stmts => eax
11506     #
11507     {
11508 $check-mu-block:check-empty:
11509       3d/compare-eax-and 0/imm32
11510       0f 84/jump-if-= break/disp32
11511       # emit block->statements
11512       (check-mu-stmt-list %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11513     }
11514 $check-mu-block:end:
11515     # . restore registers
11516     58/pop-to-eax
11517     # . epilogue
11518     89/<- %esp 5/r32/ebp
11519     5d/pop-to-ebp
11520     c3/return
11521 
11522 check-mu-stmt-list:  # stmts: (addr list stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11523     # . prologue
11524     55/push-ebp
11525     89/<- %ebp 4/r32/esp
11526     # . save registers
11527     50/push-eax
11528     56/push-esi
11529     # esi = stmts
11530     8b/-> *(ebp+8) 6/r32/esi
11531     {
11532 $check-mu-stmt-list:loop:
11533       81 7/subop/compare %esi 0/imm32
11534       0f 84/jump-if-= break/disp32
11535       # var curr-stmt/eax: (addr stmt) = lookup(stmts->value)
11536       (lookup *esi *(esi+4))  # List-value List-value => eax
11537       {
11538 $check-mu-stmt-list:check-for-block:
11539         81 7/subop/compare *eax 0/imm32/block  # Stmt-tag
11540         75/jump-if-!= break/disp8
11541 $check-mu-stmt-list:block:
11542         (check-mu-block %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11543         eb/jump $check-mu-stmt-list:continue/disp8
11544       }
11545       {
11546 $check-mu-stmt-list:check-for-stmt1:
11547         81 7/subop/compare *eax 1/imm32/stmt1  # Stmt-tag
11548         0f 85/jump-if-!= break/disp32
11549 $check-mu-stmt-list:stmt1:
11550         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11551         eb/jump $check-mu-stmt-list:continue/disp8
11552       }
11553       {
11554 $check-mu-stmt-list:check-for-reg-var-def:
11555         81 7/subop/compare *eax 3/imm32/reg-var-def  # Stmt-tag
11556         0f 85/jump-if-!= break/disp32
11557 $check-mu-stmt-list:reg-var-def:
11558         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11559         eb/jump $check-mu-stmt-list:continue/disp8
11560       }
11561 $check-mu-stmt-list:continue:
11562       # TODO: raise an error on unrecognized Stmt-tag
11563       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
11564       89/<- %esi 0/r32/eax
11565       e9/jump loop/disp32
11566     }
11567 $check-mu-stmt-list:end:
11568     # . restore registers
11569     5e/pop-to-esi
11570     58/pop-to-eax
11571     # . epilogue
11572     89/<- %esp 5/r32/ebp
11573     5d/pop-to-ebp
11574     c3/return
11575 
11576 check-mu-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11577     # . prologue
11578     55/push-ebp
11579     89/<- %ebp 4/r32/esp
11580     # . save registers
11581     50/push-eax
11582     # - if stmt's operation matches a primitive, check against it
11583     (has-primitive-name? *(ebp+8))  # => eax
11584     3d/compare-eax-and 0/imm32/false
11585     {
11586       74/jump-if-= break/disp8
11587       (check-mu-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11588       e9/jump $check-mu-stmt:end/disp32
11589     }
11590     # - otherwise find a function to check against
11591     # var f/eax: (addr function) = lookup(*Program->functions)
11592     (lookup *_Program-functions *_Program-functions->payload)  # => eax
11593     (find-matching-function %eax *(ebp+8))  # => eax
11594     3d/compare-eax-and 0/imm32
11595     {
11596       74/jump-if-= break/disp8
11597       (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11598       eb/jump $check-mu-stmt:end/disp8
11599     }
11600     # var f/eax: (addr function) = lookup(*Program->signatures)
11601     (lookup *_Program-signatures *_Program-signatures->payload)  # => eax
11602     (find-matching-function %eax *(ebp+8))  # => eax
11603     3d/compare-eax-and 0/imm32
11604     {
11605       74/jump-if-= break/disp8
11606       (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11607       eb/jump $check-mu-stmt:end/disp8
11608     }
11609     # - otherwise abort
11610     e9/jump $check-mu-stmt:unknown-call/disp32
11611 $check-mu-stmt:end:
11612     # . restore registers
11613     58/pop-to-eax
11614     # . epilogue
11615     89/<- %esp 5/r32/ebp
11616     5d/pop-to-ebp
11617     c3/return
11618 
11619 $check-mu-stmt:unknown-call:
11620     (write-buffered *(ebp+0x10) "unknown function '")
11621     8b/-> *(ebp+8) 0/r32/eax
11622     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
11623     (write-buffered *(ebp+0x10) %eax)
11624     (write-buffered *(ebp+0x10) "'\n")
11625     (flush *(ebp+0x10))
11626     (stop *(ebp+0x14) 1)
11627     # never gets here
11628 
11629 has-primitive-name?:  # stmt: (addr stmt) -> result/eax: boolean
11630     # . prologue
11631     55/push-ebp
11632     89/<- %ebp 4/r32/esp
11633     # . save registers
11634     51/push-ecx
11635     56/push-esi
11636     # var name/esi: (addr array byte) = lookup(stmt->operation)
11637     8b/-> *(ebp+8) 6/r32/esi
11638     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
11639     89/<- %esi 0/r32/eax
11640     # if (name == "get") return true
11641     (string-equal? %esi "get")  # => eax
11642     3d/compare-eax-and 0/imm32/false
11643     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11644     # if (name == "index") return true
11645     (string-equal? %esi "index")  # => eax
11646     3d/compare-eax-and 0/imm32/false
11647     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11648     # if (name == "length") return true
11649     (string-equal? %esi "length")  # => eax
11650     3d/compare-eax-and 0/imm32/false
11651     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11652     # if (name == "compute-offset") return true
11653     (string-equal? %esi "compute-offset")  # => eax
11654     3d/compare-eax-and 0/imm32/false
11655     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11656     # if (name == "lookup") return true
11657     (string-equal? %esi "lookup")  # => eax
11658     3d/compare-eax-and 0/imm32/false
11659     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11660     # if (name == "allocate") return true
11661     (string-equal? %esi "allocate")  # => eax
11662     3d/compare-eax-and 0/imm32/false
11663     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11664     # if (name == "populate") return true
11665     (string-equal? %esi "populate")  # => eax
11666     3d/compare-eax-and 0/imm32/false
11667     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11668     # var curr/ecx: (addr primitive) = Primitives
11669     b9/copy-to-ecx Primitives/imm32
11670     {
11671 $has-primitive-name?:loop:
11672       # if (curr == null) break
11673       81 7/subop/compare %ecx 0/imm32
11674       74/jump-if-= break/disp8
11675       # if (primitive->name == name) return true
11676       (lookup *ecx *(ecx+4))  # Primitive-name Primitive-name => eax
11677       (string-equal? %esi %eax)  # => eax
11678       3d/compare-eax-and 0/imm32/false
11679       75/jump-if-!= $has-primitive-name?:end/disp8
11680 $has-primitive-name?:next-primitive:
11681       # curr = curr->next
11682       (lookup *(ecx+0x38) *(ecx+0x3c))  # Primitive-next Primitive-next => eax
11683       89/<- %ecx 0/r32/eax
11684       #
11685       e9/jump loop/disp32
11686     }
11687     # return null
11688     b8/copy-to-eax 0/imm32
11689 $has-primitive-name?:end:
11690     # . restore registers
11691     5e/pop-to-esi
11692     59/pop-to-ecx
11693     # . epilogue
11694     89/<- %esp 5/r32/ebp
11695     5d/pop-to-ebp
11696     c3/return
11697 
11698 check-mu-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11699     # . prologue
11700     55/push-ebp
11701     89/<- %ebp 4/r32/esp
11702     # . save registers
11703     50/push-eax
11704     51/push-ecx
11705     # var op/ecx: (addr array byte) = lookup(stmt->operation)
11706     8b/-> *(ebp+8) 0/r32/eax
11707     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
11708     89/<- %ecx 0/r32/eax
11709     # if (op == "copy") check-mu-copy-stmt
11710     {
11711       (string-equal? %ecx "copy")  # => eax
11712       3d/compare-eax-and 0/imm32/false
11713       74/jump-if-= break/disp8
11714       (check-mu-copy-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11715       e9/jump $check-mu-primitive:end/disp32
11716     }
11717     # if (op == "copy-to") check-mu-copy-to-stmt
11718     {
11719       (string-equal? %ecx "copy-to")  # => eax
11720       3d/compare-eax-and 0/imm32/false
11721       74/jump-if-= break/disp8
11722       (check-mu-copy-to-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11723       e9/jump $check-mu-primitive:end/disp32
11724     }
11725     # if (op == "compare") check-mu-compare-stmt
11726     {
11727       (string-equal? %ecx "compare")  # => eax
11728       3d/compare-eax-and 0/imm32/false
11729       74/jump-if-= break/disp8
11730       (check-mu-compare-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11731       e9/jump $check-mu-primitive:end/disp32
11732     }
11733     # if (op == "address") check-mu-address-stmt
11734     {
11735       (string-equal? %ecx "address")  # => eax
11736       3d/compare-eax-and 0/imm32/false
11737       74/jump-if-= break/disp8
11738       (check-mu-address-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11739       e9/jump $check-mu-primitive:end/disp32
11740     }
11741     # if (op == "get") check-mu-get-stmt
11742     {
11743       (string-equal? %ecx "get")  # => eax
11744       3d/compare-eax-and 0/imm32/false
11745       74/jump-if-= break/disp8
11746       (check-mu-get-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11747       e9/jump $check-mu-primitive:end/disp32
11748     }
11749     # if (op == "index") check-mu-index-stmt
11750     {
11751       (string-equal? %ecx "index")  # => eax
11752       3d/compare-eax-and 0/imm32/false
11753       74/jump-if-= break/disp8
11754       (check-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11755       e9/jump $check-mu-primitive:end/disp32
11756     }
11757     # if (op == "length") check-mu-length-stmt
11758     {
11759       (string-equal? %ecx "length")  # => eax
11760       3d/compare-eax-and 0/imm32/false
11761       74/jump-if-= break/disp8
11762       (check-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11763       e9/jump $check-mu-primitive:end/disp32
11764     }
11765     # if (op == "compute-offset") check-mu-compute-offset-stmt
11766     {
11767       (string-equal? %ecx "compute-offset")  # => eax
11768       3d/compare-eax-and 0/imm32/false
11769       74/jump-if-= break/disp8
11770       (check-mu-compute-offset-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11771       e9/jump $check-mu-primitive:end/disp32
11772     }
11773     # if (op == "lookup") check-mu-lookup-stmt
11774     {
11775       (string-equal? %ecx "lookup")  # => eax
11776       3d/compare-eax-and 0/imm32/false
11777       74/jump-if-= break/disp8
11778       (check-mu-lookup-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11779       e9/jump $check-mu-primitive:end/disp32
11780     }
11781     # if (op == "allocate") check-mu-allocate-stmt
11782     {
11783       (string-equal? %ecx "allocate")  # => eax
11784       3d/compare-eax-and 0/imm32/false
11785       74/jump-if-= break/disp8
11786       (check-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11787       e9/jump $check-mu-primitive:end/disp32
11788     }
11789     # if (op == "populate") check-mu-populate-stmt
11790     {
11791       (string-equal? %ecx "populate")  # => eax
11792       3d/compare-eax-and 0/imm32/false
11793       74/jump-if-= break/disp8
11794       (check-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11795       e9/jump $check-mu-primitive:end/disp32
11796     }
11797     # otherwise check-numberlike-stmt
11798     (check-mu-numberlike-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11799 $check-mu-primitive:end:
11800     # . restore registers
11801     59/pop-to-ecx
11802     58/pop-to-eax
11803     # . epilogue
11804     89/<- %esp 5/r32/ebp
11805     5d/pop-to-ebp
11806     c3/return
11807 
11808 # by default, Mu primitives should only operate on 'number-like' types
11809 check-mu-numberlike-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11810     # . prologue
11811     55/push-ebp
11812     89/<- %ebp 4/r32/esp
11813     # . save registers
11814     50/push-eax
11815     51/push-ecx
11816     56/push-esi
11817     # esi = stmt
11818     8b/-> *(ebp+8) 6/r32/esi
11819     # var gas/ecx: int = 2
11820     b9/copy-to-ecx 2/imm32
11821     # - check at most 1 output
11822     # var output/eax: (addr stmt-var) = stmt->outputs
11823     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
11824     {
11825       3d/compare-eax-and 0/imm32
11826       74/jump-if-= break/disp8
11827 $check-mu-numberlike-primitive:output:
11828       (check-mu-numberlike-output %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11829       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
11830       3d/compare-eax-and 0/imm32
11831       0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-outputs/disp32
11832       # check output is in a register
11833       # --gas
11834       49/decrement-ecx
11835     }
11836     # - check first inout
11837     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11838     {
11839       3d/compare-eax-and 0/imm32
11840       0f 84/jump-if-= $check-mu-numberlike-primitive:end/disp32
11841 $check-mu-numberlike-primitive:first-inout:
11842       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11843       # --gas
11844       49/decrement-ecx
11845     }
11846     # - check second inout
11847     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
11848     {
11849       3d/compare-eax-and 0/imm32
11850       74/jump-if-= $check-mu-numberlike-primitive:end/disp8
11851 $check-mu-numberlike-primitive:second-inout:
11852       # is a second inout allowed?
11853       81 7/subop/compare %ecx 0/imm32
11854       0f 84/jump-if-= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
11855 $check-mu-numberlike-primitive:second-inout-permitted:
11856       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11857     }
11858 $check-mu-numberlike-primitive:third-inout:
11859     # if there's a third arg, raise an error
11860     81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
11861     0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
11862 $check-mu-numberlike-primitive:end:
11863     # . restore registers
11864     5e/pop-to-esi
11865     59/pop-to-ecx
11866     58/pop-to-eax
11867     # . epilogue
11868     89/<- %esp 5/r32/ebp
11869     5d/pop-to-ebp
11870     c3/return
11871 
11872 $check-mu-numberlike-primitive:error-too-many-inouts:
11873     (write-buffered *(ebp+0x10) "fn ")
11874     8b/-> *(ebp+0xc) 0/r32/eax
11875     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11876     (write-buffered *(ebp+0x10) %eax)
11877     (write-buffered *(ebp+0x10) ": stmt ")
11878     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
11879     (write-buffered *(ebp+0x10) %eax)
11880     (write-buffered *(ebp+0x10) ": too many inouts; most primitives support at most two arguments, across inouts and outputs\n")
11881     (flush *(ebp+0x10))
11882     (stop *(ebp+0x14) 1)
11883     # never gets here
11884 
11885 $check-mu-numberlike-primitive:error-too-many-outputs:
11886     (write-buffered *(ebp+0x10) "fn ")
11887     8b/-> *(ebp+0xc) 0/r32/eax
11888     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11889     (write-buffered *(ebp+0x10) %eax)
11890     (write-buffered *(ebp+0x10) ": stmt ")
11891     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
11892     (write-buffered *(ebp+0x10) %eax)
11893     (write-buffered *(ebp+0x10) ": too many outputs; most primitives support at most one output\n")
11894     (flush *(ebp+0x10))
11895     (stop *(ebp+0x14) 1)
11896     # never gets here
11897 
11898 check-mu-numberlike-arg:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11899     # . prologue
11900     55/push-ebp
11901     89/<- %ebp 4/r32/esp
11902     # . save registers
11903     50/push-eax
11904     56/push-esi
11905     # var t/esi: (addr type-tree) = lookup(v->value->type)
11906     8b/-> *(ebp+8) 0/r32/eax
11907     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11908     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11909     89/<- %esi 0/r32/eax
11910 $check-mu-numberlike-arg:check-literal:
11911     # if t is an int, return
11912     (is-simple-mu-type? %esi 0)  # literal => eax
11913     3d/compare-eax-and 0/imm32/false
11914     75/jump-if-!= $check-mu-numberlike-arg:end/disp8
11915 $check-mu-numberlike-arg:check-addr:
11916     # if t is an addr and v is dereferenced, return
11917     {
11918       (is-mu-addr-type? %esi)  # => eax
11919       3d/compare-eax-and 0/imm32/false
11920       74/jump-if-= break/disp8
11921       8b/-> *(ebp+8) 0/r32/eax
11922       8b/-> *(eax+0x10) 0/r32/eax
11923       3d/compare-eax-and 0/imm32/false
11924       75/jump-if-!= $check-mu-numberlike-arg:end/disp8
11925     }
11926 $check-mu-numberlike-arg:output-checks:
11927     (check-mu-numberlike-output *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
11928 $check-mu-numberlike-arg:end:
11929     # . restore registers
11930     5e/pop-to-esi
11931     58/pop-to-eax
11932     # . epilogue
11933     89/<- %esp 5/r32/ebp
11934     5d/pop-to-ebp
11935     c3/return
11936 
11937 check-mu-numberlike-output:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11938     # . prologue
11939     55/push-ebp
11940     89/<- %ebp 4/r32/esp
11941     # . save registers
11942     50/push-eax
11943     56/push-esi
11944     # var t/esi: (addr type-tree) = lookup(v->value->type)
11945     8b/-> *(ebp+8) 0/r32/eax
11946     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11947     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11948     89/<- %esi 0/r32/eax
11949 $check-mu-numberlike-output:check-int:
11950     # if t is an int, return
11951     (is-simple-mu-type? %esi 1)  # int => eax
11952     3d/compare-eax-and 0/imm32/false
11953     75/jump-if-!= $check-mu-numberlike-output:end/disp8
11954 $check-mu-numberlike-output:check-boolean:
11955     # if t is a boolean, return
11956     (is-simple-mu-type? %esi 5)  # boolean => eax
11957     3d/compare-eax-and 0/imm32/false
11958     75/jump-if-!= $check-mu-numberlike-output:end/disp8
11959 $check-mu-numberlike-output:check-byte:
11960     # if t is a byte, return
11961     (is-simple-mu-type? %esi 8)  # byte => eax
11962     3d/compare-eax-and 0/imm32/false
11963     75/jump-if-!= $check-mu-numberlike-output:end/disp8
11964     e9/jump $check-mu-numberlike-output:fail/disp32
11965 $check-mu-numberlike-output:end:
11966     # . restore registers
11967     5e/pop-to-esi
11968     58/pop-to-eax
11969     # . epilogue
11970     89/<- %esp 5/r32/ebp
11971     5d/pop-to-ebp
11972     c3/return
11973 
11974 $check-mu-numberlike-output:fail:
11975     # otherwise raise an error
11976     (write-buffered *(ebp+0x14) "fn ")
11977     8b/-> *(ebp+0x10) 0/r32/eax
11978     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11979     (write-buffered *(ebp+0x14) %eax)
11980     (write-buffered *(ebp+0x14) ": stmt ")
11981     8b/-> *(ebp+0xc) 0/r32/eax
11982     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
11983     (write-buffered *(ebp+0x14) %eax)
11984     (write-buffered *(ebp+0x14) ": only non-addr scalar args permitted\n")
11985     (flush *(ebp+0x14))
11986     (stop *(ebp+0x18) 1)
11987     # never gets here
11988 
11989 check-mu-copy-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11990     # . prologue
11991     55/push-ebp
11992     89/<- %ebp 4/r32/esp
11993     # . save registers
11994 $check-mu-copy-stmt:end:
11995     # . restore registers
11996     # . epilogue
11997     89/<- %esp 5/r32/ebp
11998     5d/pop-to-ebp
11999     c3/return
12000 
12001 check-mu-copy-to-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12002     # . prologue
12003     55/push-ebp
12004     89/<- %ebp 4/r32/esp
12005     # . save registers
12006 $check-mu-copy-to-stmt:end:
12007     # . restore registers
12008     # . epilogue
12009     89/<- %esp 5/r32/ebp
12010     5d/pop-to-ebp
12011     c3/return
12012 
12013 check-mu-compare-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12014     # . prologue
12015     55/push-ebp
12016     89/<- %ebp 4/r32/esp
12017     # . save registers
12018 $check-mu-compare-stmt:end:
12019     # . restore registers
12020     # . epilogue
12021     89/<- %esp 5/r32/ebp
12022     5d/pop-to-ebp
12023     c3/return
12024 
12025 check-mu-address-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12026     # . prologue
12027     55/push-ebp
12028     89/<- %ebp 4/r32/esp
12029     # . save registers
12030 $check-mu-address-stmt:end:
12031     # . restore registers
12032     # . epilogue
12033     89/<- %esp 5/r32/ebp
12034     5d/pop-to-ebp
12035     c3/return
12036 
12037 check-mu-get-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12038     # . prologue
12039     55/push-ebp
12040     89/<- %ebp 4/r32/esp
12041     # . save registers
12042     50/push-eax
12043     51/push-ecx
12044     52/push-edx
12045     53/push-ebx
12046     56/push-esi
12047     57/push-edi
12048     # esi = stmt
12049     8b/-> *(ebp+8) 6/r32/esi
12050     # - check for 0 inouts
12051     # var base/ecx: (addr var) = stmt->inouts->value
12052     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12053     3d/compare-eax-and 0/imm32/false
12054     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
12055     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12056     89/<- %ecx 0/r32/eax
12057 $check-mu-get-stmt:check-base:
12058     # - check base type
12059     # if it's an 'addr', check that it's in a register
12060     # var base-type/ebx: (addr type-tree) = lookup(base->type)
12061     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
12062     89/<- %ebx 0/r32/eax
12063     {
12064       81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
12065       0f 85/jump-if-!= break/disp32
12066 $check-mu-get-stmt:base-is-compound:
12067       # if (type->left != addr) break
12068       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
12069       (is-simple-mu-type? %eax 2)  # => eax
12070       3d/compare-eax-and 0/imm32/false
12071       74/jump-if-= break/disp8
12072 $check-mu-get-stmt:base-is-addr:
12073       # now check for register
12074       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
12075       0f 84/jump-if-= $check-mu-get-stmt:error-base-type-addr-but-not-register/disp32
12076 $check-mu-get-stmt:base-is-addr-in-register:
12077       # type->left is now an addr; skip it
12078       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
12079       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
12080       0f 85/jump-if-!= $check-mu-get-stmt:error-bad-base/disp32
12081 $check-mu-get-stmt:base-is-addr-to-atom-in-register:
12082       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
12083       89/<- %ebx 0/r32/eax
12084     }
12085 $check-mu-get-stmt:check-base-typeinfo:
12086     # ensure type is a container
12087     # var base-type-id/ebx: type-id = base-type->value
12088     8b/-> *(ebx+4) 3/r32/ebx  # Type-tree-value
12089     (is-container? %ebx)  # => eax
12090     3d/compare-eax-and 0/imm32/false
12091     0f 84/jump-if-= $check-mu-get-stmt:error-bad-base/disp32
12092     # var base-typeinfo/edx: (addr typeinfo) = find-typeinfo(base-type-id)
12093     # . var container/ecx: (handle typeinfo)
12094     68/push 0/imm32
12095     68/push 0/imm32
12096     89/<- %ecx 4/r32/esp
12097     # .
12098     (find-typeinfo %ebx %ecx)
12099     (lookup *ecx *(ecx+4))  # => eax
12100     # . reclaim container
12101     81 0/subop/add %esp 8/imm32
12102     # .
12103     89/<- %edx 0/r32/eax
12104     # var offset/ecx: (addr stmt-var) = stmt->inouts->next
12105     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12106     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12107     89/<- %ecx 0/r32/eax
12108     # - check for 1 inout
12109     3d/compare-eax-and 0/imm32/false
12110     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
12111     # var offset/ecx: (addr var) = lookup(offset->value)
12112     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12113     89/<- %ecx 0/r32/eax
12114     # - check for valid field
12115     81 7/subop/compare *(ecx+0x14) -1/imm32/uninitialized  # Var-offset
12116     0f 84/jump-if-= $check-mu-get-stmt:error-bad-field/disp32
12117     # - check for too many inouts
12118     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12119     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12120     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12121     3d/compare-eax-and 0/imm32/false
12122     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-inouts/disp32
12123     # var output/edi: (addr var) = stmt->outputs->value
12124     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12125     # - check for 0 outputs
12126     3d/compare-eax-and 0/imm32/false
12127     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-outputs/disp32
12128     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12129     89/<- %edi 0/r32/eax
12130 $check-mu-get-stmt:check-output-type:
12131     # - check output type
12132     # must be in register
12133     (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
12134     3d/compare-eax-and 0/imm32
12135     0f 84/jump-if-= $check-mu-get-stmt:error-output-not-in-register/disp32
12136     # must have a non-atomic type
12137     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
12138     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
12139     0f 85/jump-if-!= $check-mu-get-stmt:error-output-type-not-address/disp32
12140     # type must start with (addr ...)
12141     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
12142     (is-simple-mu-type? %eax 2)  # => eax
12143     3d/compare-eax-and 0/imm32/false
12144     0f 84/jump-if-= $check-mu-get-stmt:error-output-type-not-address/disp32
12145 $check-mu-get-stmt:check-output-type-match:
12146     # payload of addr type must match 'type' definition
12147     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
12148     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
12149     # if (payload->right == null) payload = payload->left
12150     81 7/subop/compare *(eax+0xc) 0/imm32/null  # Type-tree-right
12151     {
12152       75/jump-if-!= break/disp8
12153       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
12154     }
12155     89/<- %edi 0/r32/eax
12156     # . var output-name/ecx: (addr array byte)
12157     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
12158     89/<- %ecx 0/r32/eax
12159     # . var base-typeinfo-entry/eax: (addr handle typeinfo-entry)
12160     (lookup *(edx+4) *(edx+8))  # Typeinfo-fields Typeinfo-fields => eax
12161     (get %eax %ecx 0x10)  # => eax
12162     # .
12163     (lookup *eax *(eax+4))  # => eax
12164     (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
12165     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12166     # .
12167     (type-equal? %edi %eax)  # => eax
12168     3d/compare-eax-and 0/imm32/false
12169     0f 84/jump-if-= $check-mu-get-stmt:error-bad-output-type/disp32
12170     # - check for too many outputs
12171     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12172     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12173     3d/compare-eax-and 0/imm32/false
12174     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-outputs/disp32
12175 $check-mu-get-stmt:end:
12176     # . restore registers
12177     5f/pop-to-edi
12178     5e/pop-to-esi
12179     5b/pop-to-ebx
12180     5a/pop-to-edx
12181     59/pop-to-ecx
12182     58/pop-to-eax
12183     # . epilogue
12184     89/<- %esp 5/r32/ebp
12185     5d/pop-to-ebp
12186     c3/return
12187 
12188 $check-mu-get-stmt:error-too-few-inouts:
12189     (write-buffered *(ebp+0x10) "fn ")
12190     8b/-> *(ebp+0xc) 0/r32/eax
12191     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12192     (write-buffered *(ebp+0x10) %eax)
12193     (write-buffered *(ebp+0x10) ": stmt get: too few inouts (2 required)\n")
12194     (flush *(ebp+0x10))
12195     (stop *(ebp+0x14) 1)
12196     # never gets here
12197 
12198 $check-mu-get-stmt:error-too-many-inouts:
12199     (write-buffered *(ebp+0x10) "fn ")
12200     8b/-> *(ebp+0xc) 0/r32/eax
12201     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12202     (write-buffered *(ebp+0x10) %eax)
12203     (write-buffered *(ebp+0x10) ": stmt get: too many inouts (2 required)\n")
12204     (flush *(ebp+0x10))
12205     (stop *(ebp+0x14) 1)
12206     # never gets here
12207 
12208 $check-mu-get-stmt:error-too-few-outputs:
12209     (write-buffered *(ebp+0x10) "fn ")
12210     8b/-> *(ebp+0xc) 0/r32/eax
12211     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12212     (write-buffered *(ebp+0x10) %eax)
12213     (write-buffered *(ebp+0x10) ": stmt get: must have an output\n")
12214     (flush *(ebp+0x10))
12215     (stop *(ebp+0x14) 1)
12216     # never gets here
12217 
12218 $check-mu-get-stmt:error-too-many-outputs:
12219     (write-buffered *(ebp+0x10) "fn ")
12220     8b/-> *(ebp+0xc) 0/r32/eax
12221     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12222     (write-buffered *(ebp+0x10) %eax)
12223     (write-buffered *(ebp+0x10) ": stmt get: too many outputs (1 required)\n")
12224     (flush *(ebp+0x10))
12225     (stop *(ebp+0x14) 1)
12226     # never gets here
12227 
12228 $check-mu-get-stmt:error-bad-base:
12229     # error("fn " fn ": stmt get: var '" base->name "' must have a 'type' definition\n")
12230     (write-buffered *(ebp+0x10) "fn ")
12231     8b/-> *(ebp+0xc) 0/r32/eax
12232     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12233     (write-buffered *(ebp+0x10) %eax)
12234     (write-buffered *(ebp+0x10) ": stmt get: var '")
12235     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12236     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12237     (lookup *eax *(eax+4))  # Var-name Var-name => eax
12238     (write-buffered *(ebp+0x10) %eax)
12239     (write-buffered *(ebp+0x10) "' must have a 'type' definition\n")
12240     (flush *(ebp+0x10))
12241     (stop *(ebp+0x14) 1)
12242     # never gets here
12243 
12244 $check-mu-get-stmt:error-base-type-addr-but-not-register:
12245     (write-buffered *(ebp+0x10) "fn ")
12246     8b/-> *(ebp+0xc) 0/r32/eax
12247     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12248     (write-buffered *(ebp+0x10) %eax)
12249     (write-buffered *(ebp+0x10) ": stmt get: var '")
12250     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12251     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12252     (lookup *eax *(eax+4))  # Var-name Var-name => eax
12253     (write-buffered *(ebp+0x10) %eax)
12254     (write-buffered *(ebp+0x10) "' is an 'addr' type, and so must live in a register\n")
12255     (flush *(ebp+0x10))
12256     (stop *(ebp+0x14) 1)
12257     # never gets here
12258 
12259 $check-mu-get-stmt:error-bad-field:
12260     # error("fn " fn ": stmt get: type " type " has no member called '" curr->name "'\n")
12261     (write-buffered *(ebp+0x10) "fn ")
12262     8b/-> *(ebp+0xc) 0/r32/eax
12263     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12264     (write-buffered *(ebp+0x10) %eax)
12265     (write-buffered *(ebp+0x10) ": stmt get: type '")
12266     # . write(Type-id->data[tmp])
12267     bf/copy-to-edi Type-id/imm32
12268     (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
12269     # .
12270     (write-buffered *(ebp+0x10) "' has no member called '")
12271     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
12272     (write-buffered *(ebp+0x10) %eax)
12273     (write-buffered *(ebp+0x10) "'\n")
12274     (flush *(ebp+0x10))
12275     (stop *(ebp+0x14) 1)
12276     # never gets here
12277 
12278 $check-mu-get-stmt:error-output-not-in-register:
12279     (write-buffered *(ebp+0x10) "fn ")
12280     8b/-> *(ebp+0xc) 0/r32/eax
12281     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12282     (write-buffered *(ebp+0x10) %eax)
12283     (write-buffered *(ebp+0x10) ": stmt get: output '")
12284     (lookup *edi *(edi+4))  # Var-name Var-name => eax
12285     (write-buffered *(ebp+0x10) %eax)
12286     (write-buffered *(ebp+0x10) "' is not in a register\n")
12287     (flush *(ebp+0x10))
12288     (stop *(ebp+0x14) 1)
12289     # never gets here
12290 
12291 $check-mu-get-stmt:error-output-type-not-address:
12292     (write-buffered *(ebp+0x10) "fn ")
12293     8b/-> *(ebp+0xc) 0/r32/eax
12294     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12295     (write-buffered *(ebp+0x10) %eax)
12296     (write-buffered *(ebp+0x10) ": stmt get: output must be an address\n")
12297     (flush *(ebp+0x10))
12298     (stop *(ebp+0x14) 1)
12299     # never gets here
12300 
12301 $check-mu-get-stmt:error-bad-output-type:
12302     (write-buffered *(ebp+0x10) "fn ")
12303     8b/-> *(ebp+0xc) 0/r32/eax
12304     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12305     (write-buffered *(ebp+0x10) %eax)
12306     (write-buffered *(ebp+0x10) ": stmt get: wrong output type for member '")
12307     (write-buffered *(ebp+0x10) %ecx)
12308     (write-buffered *(ebp+0x10) "' of type '")
12309     bf/copy-to-edi Type-id/imm32
12310     (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
12311     (write-buffered *(ebp+0x10) "'\n")
12312     (flush *(ebp+0x10))
12313     (stop *(ebp+0x14) 1)
12314     # never gets here
12315 
12316 check-mu-index-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12317     # . prologue
12318     55/push-ebp
12319     89/<- %ebp 4/r32/esp
12320     # . save registers
12321 $check-mu-index-stmt:end:
12322     # . restore registers
12323     # . epilogue
12324     89/<- %esp 5/r32/ebp
12325     5d/pop-to-ebp
12326     c3/return
12327 
12328 check-mu-length-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12329     # . prologue
12330     55/push-ebp
12331     89/<- %ebp 4/r32/esp
12332     # . save registers
12333 $check-mu-length-stmt:end:
12334     # . restore registers
12335     # . epilogue
12336     89/<- %esp 5/r32/ebp
12337     5d/pop-to-ebp
12338     c3/return
12339 
12340 check-mu-compute-offset-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12341     # . prologue
12342     55/push-ebp
12343     89/<- %ebp 4/r32/esp
12344     # . save registers
12345 $check-mu-compute-offset-stmt:end:
12346     # . restore registers
12347     # . epilogue
12348     89/<- %esp 5/r32/ebp
12349     5d/pop-to-ebp
12350     c3/return
12351 
12352 check-mu-lookup-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12353     # . prologue
12354     55/push-ebp
12355     89/<- %ebp 4/r32/esp
12356     # . save registers
12357 $check-mu-lookup-stmt:end:
12358     # . restore registers
12359     # . epilogue
12360     89/<- %esp 5/r32/ebp
12361     5d/pop-to-ebp
12362     c3/return
12363 
12364 check-mu-allocate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12365     # . prologue
12366     55/push-ebp
12367     89/<- %ebp 4/r32/esp
12368     # . save registers
12369 $check-mu-allocate-stmt:end:
12370     # . restore registers
12371     # . epilogue
12372     89/<- %esp 5/r32/ebp
12373     5d/pop-to-ebp
12374     c3/return
12375 
12376 check-mu-populate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12377     # . prologue
12378     55/push-ebp
12379     89/<- %ebp 4/r32/esp
12380     # . save registers
12381 $check-mu-populate-stmt:end:
12382     # . restore registers
12383     # . epilogue
12384     89/<- %esp 5/r32/ebp
12385     5d/pop-to-ebp
12386     c3/return
12387 
12388 check-mu-call:  # stmt: (addr stmt), callee: (addr function), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12389     # . prologue
12390     55/push-ebp
12391     89/<- %ebp 4/r32/esp
12392     # var type-parameters: (addr table (handle array byte) (addr type-tree) 8)
12393     68/push 0/imm32
12394     # var type-parameters-storage: (table (handle array byte) (addr type-tree) 8)
12395     81 5/subop/subtract %esp 0x60/imm32
12396     68/push 0x60/imm32/size
12397     68/push 0/imm32/read
12398     68/push 0/imm32/write
12399     # save a pointer to type-parameters-storage at type-parameters
12400     89/<- *(ebp-4) 4/r32/esp
12401     (clear-stream *(ebp-4))
12402     # . save registers
12403     50/push-eax
12404     51/push-ecx
12405     52/push-edx
12406     53/push-ebx
12407     56/push-esi
12408     57/push-edi
12409     # esi = stmt
12410     8b/-> *(ebp+8) 6/r32/esi
12411     # edi = callee
12412     8b/-> *(ebp+0xc) 7/r32/edi
12413     # var inouts/ecx: (addr stmt-var) = lookup(stmt->inouts)
12414     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12415     89/<- %ecx 0/r32/eax
12416     # var expected/edx: (addr list var) = lookup(f->inouts)
12417     (lookup *(edi+8) *(edi+0xc))  # Function-inouts Function-inouts => eax
12418     89/<- %edx 0/r32/eax
12419     {
12420 $check-mu-call:check-for-inouts:
12421       # if (inouts == 0) break
12422       81 7/subop/compare %ecx 0/imm32
12423       0f 84/jump-if-= break/disp32
12424       # if (expected == 0) error
12425       81 7/subop/compare %edx 0/imm32
12426       0f 84/jump-if-= break/disp32
12427 $check-mu-call:check-inout-type:
12428       # var v/eax: (addr v) = lookup(inouts->value)
12429       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12430       # var t/ebx: (addr type-tree) = lookup(v->type)
12431       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12432       89/<- %ebx 0/r32/eax
12433       # if (inouts->is-deref?) t = t->right  # TODO: check that t->left is an addr
12434       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
12435       {
12436         74/jump-if-= break/disp8
12437         (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
12438         89/<- %ebx 0/r32/eax
12439         # if t->right is null, t = t->left
12440         81 7/subop/compare *(ebx+0xc) 0/imm32  # Type-tree-right
12441         75/jump-if-!= break/disp8
12442         (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
12443         89/<- %ebx 0/r32/eax
12444       }
12445       # var v2/eax: (addr v) = lookup(expected->value)
12446       (lookup *edx *(edx+4))  # List-value List-value => eax
12447       # var t2/eax: (addr type-tree) = lookup(v2->type)
12448       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12449       # if (t != t2) error
12450       (type-match? %eax %ebx *(ebp-4))  # => eax
12451       3d/compare-eax-and 0/imm32/false
12452       {
12453         0f 85/jump-if-!= break/disp32
12454         (write-buffered *(ebp+0x14) "fn ")
12455         8b/-> *(ebp+0x10) 0/r32/eax
12456         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12457         (write-buffered *(ebp+0x14) %eax)
12458         (write-buffered *(ebp+0x14) ": call ")
12459         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12460         (write-buffered *(ebp+0x14) %eax)
12461         (write-buffered *(ebp+0x14) ": type for inout '")
12462         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12463         (lookup *eax *(eax+4))  # Var-name Var-name => eax
12464         (write-buffered *(ebp+0x14) %eax)
12465         (write-buffered *(ebp+0x14) "' is not right\n")
12466         (flush *(ebp+0x14))
12467         (stop *(ebp+0x18) 1)
12468       }
12469 $check-mu-call:continue-to-next-inout:
12470       # inouts = lookup(inouts->next)
12471       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
12472       89/<- %ecx 0/r32/eax
12473       # expected = lookup(expected->next)
12474       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
12475       89/<- %edx 0/r32/eax
12476       #
12477       e9/jump loop/disp32
12478     }
12479 $check-mu-call:check-inout-count:
12480     # if (inouts == expected) proceed
12481     39/compare %ecx 2/r32/edx
12482     {
12483       0f 84/jump-if-= break/disp32
12484       # exactly one of the two is null
12485       # if (inouts == 0) error("too many inouts")
12486       {
12487         81 7/subop/compare %ecx 0/imm32
12488         0f 84/jump-if-= break/disp32
12489         (write-buffered *(ebp+0x14) "fn ")
12490         8b/-> *(ebp+0x10) 0/r32/eax
12491         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12492         (write-buffered *(ebp+0x14) %eax)
12493         (write-buffered *(ebp+0x14) ": call ")
12494         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12495         (write-buffered *(ebp+0x14) %eax)
12496         (write-buffered *(ebp+0x14) ": too many inouts\n")
12497         (flush *(ebp+0x14))
12498         (stop *(ebp+0x18) 1)
12499       }
12500       # if (expected == 0) error("too few inouts")
12501       {
12502         81 7/subop/compare %edx 0/imm32
12503         0f 84/jump-if-= break/disp32
12504         (write-buffered *(ebp+0x14) "fn ")
12505         8b/-> *(ebp+0x10) 0/r32/eax
12506         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12507         (write-buffered *(ebp+0x14) %eax)
12508         (write-buffered *(ebp+0x14) ": call ")
12509         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12510         (write-buffered *(ebp+0x14) %eax)
12511         (write-buffered *(ebp+0x14) ": too few inouts\n")
12512         (flush *(ebp+0x14))
12513         (stop *(ebp+0x18) 1)
12514       }
12515     }
12516 $check-mu-call:check-outputs:
12517     # var outputs/ecx: (addr stmt-var) = lookup(stmt->outputs)
12518     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12519     89/<- %ecx 0/r32/eax
12520     # var expected/edx: (addr list var) = lookup(f->outputs)
12521     (lookup *(edi+0x10) *(edi+0x14))  # Function-outputs Function-outputs => eax
12522     89/<- %edx 0/r32/eax
12523     {
12524 $check-mu-call:check-for-outputs:
12525       # if (outputs == 0) break
12526       81 7/subop/compare %ecx 0/imm32
12527       0f 84/jump-if-= break/disp32
12528       # if (expected == 0) error
12529       81 7/subop/compare %edx 0/imm32
12530       0f 84/jump-if-= break/disp32
12531 $check-mu-call:check-output-type:
12532       # var v/eax: (addr v) = lookup(outputs->value)
12533       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12534       # var t/ebx: (addr type-tree) = lookup(v->type)
12535       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12536       89/<- %ebx 0/r32/eax
12537       # if (outputs->is-deref?) t = t->right  # TODO: check that t->left is an addr
12538       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
12539       {
12540         74/jump-if-= break/disp8
12541         (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
12542         89/<- %ebx 0/r32/eax
12543       }
12544       # var v2/eax: (addr v) = lookup(expected->value)
12545       (lookup *edx *(edx+4))  # List-value List-value => eax
12546       # var t2/eax: (addr type-tree) = lookup(v2->type)
12547       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12548       # if (t != t2) error
12549       (type-match? %eax %ebx *(ebp-4))  # => eax
12550       3d/compare-eax-and 0/imm32/false
12551       {
12552         0f 85/jump-if-!= break/disp32
12553         (write-buffered *(ebp+0x14) "fn ")
12554         8b/-> *(ebp+0x10) 0/r32/eax
12555         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12556         (write-buffered *(ebp+0x14) %eax)
12557         (write-buffered *(ebp+0x14) ": call ")
12558         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12559         (write-buffered *(ebp+0x14) %eax)
12560         (write-buffered *(ebp+0x14) ": type for output '")
12561         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12562         (lookup *eax *(eax+4))  # Var-name Var-name => eax
12563         (write-buffered *(ebp+0x14) %eax)
12564         (write-buffered *(ebp+0x14) "' is not right\n")
12565         (flush *(ebp+0x14))
12566         (stop *(ebp+0x18) 1)
12567       }
12568 $check-mu-call:check-output-register:
12569       # var v/eax: (addr v) = lookup(outputs->value)
12570       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12571       # var r/ebx: (addr array byte) = lookup(v->register)
12572       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
12573       89/<- %ebx 0/r32/eax
12574       # var v2/eax: (addr v) = lookup(expected->value)
12575       (lookup *edx *(edx+4))  # Stmt-var-value Stmt-var-value => eax
12576       # var r2/eax: (addr array byte) = lookup(v2->register)
12577       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
12578       # if (r != r2) error
12579       (string-equal? %eax %ebx)  # => eax
12580       3d/compare-eax-and 0/imm32/false
12581       {
12582         0f 85/jump-if-!= break/disp32
12583         (write-buffered *(ebp+0x14) "fn ")
12584         8b/-> *(ebp+0x10) 0/r32/eax
12585         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12586         (write-buffered *(ebp+0x14) %eax)
12587         (write-buffered *(ebp+0x14) ": call ")
12588         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12589         (write-buffered *(ebp+0x14) %eax)
12590         (write-buffered *(ebp+0x14) ": register for output '")
12591         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12592         (lookup *eax *(eax+4))  # Var-name Var-name => eax
12593         (write-buffered *(ebp+0x14) %eax)
12594         (write-buffered *(ebp+0x14) "' is not right\n")
12595         (flush *(ebp+0x14))
12596         (stop *(ebp+0x18) 1)
12597       }
12598 $check-mu-call:continue-to-next-output:
12599       # outputs = lookup(outputs->next)
12600       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
12601       89/<- %ecx 0/r32/eax
12602       # expected = lookup(expected->next)
12603       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
12604       89/<- %edx 0/r32/eax
12605       #
12606       e9/jump loop/disp32
12607     }
12608 $check-mu-call:check-output-count:
12609     # if (outputs == expected) proceed
12610     39/compare %ecx 2/r32/edx
12611     {
12612       0f 84/jump-if-= break/disp32
12613       # exactly one of the two is null
12614       # if (outputs == 0) error("too many outputs")
12615       {
12616         81 7/subop/compare %ecx 0/imm32
12617         0f 84/jump-if-= break/disp32
12618         (write-buffered *(ebp+0x14) "fn ")
12619         8b/-> *(ebp+0x10) 0/r32/eax
12620         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12621         (write-buffered *(ebp+0x14) %eax)
12622         (write-buffered *(ebp+0x14) ": call ")
12623         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12624         (write-buffered *(ebp+0x14) %eax)
12625         (write-buffered *(ebp+0x14) ": too many outputs\n")
12626         (flush *(ebp+0x14))
12627         (stop *(ebp+0x18) 1)
12628       }
12629       # if (expected == 0) error("too few outputs")
12630       {
12631         81 7/subop/compare %edx 0/imm32
12632         0f 84/jump-if-= break/disp32
12633         (write-buffered *(ebp+0x14) "fn ")
12634         8b/-> *(ebp+0x10) 0/r32/eax
12635         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12636         (write-buffered *(ebp+0x14) %eax)
12637         (write-buffered *(ebp+0x14) ": call ")
12638         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12639         (write-buffered *(ebp+0x14) %eax)
12640         (write-buffered *(ebp+0x14) ": too few outputs\n")
12641         (flush *(ebp+0x14))
12642         (stop *(ebp+0x18) 1)
12643       }
12644     }
12645 $check-mu-call:end:
12646     # . restore registers
12647     5f/pop-to-edi
12648     5e/pop-to-esi
12649     5b/pop-to-ebx
12650     5a/pop-to-edx
12651     59/pop-to-ecx
12652     58/pop-to-eax
12653     # . reclaim locals exclusively on the stack
12654     81 0/subop/add %esp 0x70/imm32
12655     # . epilogue
12656     89/<- %esp 5/r32/ebp
12657     5d/pop-to-ebp
12658     c3/return
12659 
12660 # like type-equal? but takes literals into account
12661 type-match?:  # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
12662     # . prologue
12663     55/push-ebp
12664     89/<- %ebp 4/r32/esp
12665     # if (call == literal) return true  # TODO: more precise
12666     (is-simple-mu-type? *(ebp+0xc) 0)  # literal => eax
12667     3d/compare-eax-and 0/imm32/false
12668     b8/copy-to-eax 1/imm32/true
12669     75/jump-if-!= $type-match?:end/disp8
12670 $type-match?:baseline:
12671     # otherwise fall back
12672     (type-component-match? *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
12673 $type-match?:end:
12674     # . epilogue
12675     89/<- %esp 5/r32/ebp
12676     5d/pop-to-ebp
12677     c3/return
12678 
12679 type-component-match?:  # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
12680     # . prologue
12681     55/push-ebp
12682     89/<- %ebp 4/r32/esp
12683     # . save registers
12684     51/push-ecx
12685     52/push-edx
12686     53/push-ebx
12687     # ecx = def
12688     8b/-> *(ebp+8) 1/r32/ecx
12689     # edx = call
12690     8b/-> *(ebp+0xc) 2/r32/edx
12691 $type-component-match?:compare-addr:
12692     # if (def == call) return true
12693     8b/-> %ecx 0/r32/eax  # Var-type
12694     39/compare %edx 0/r32/eax  # Var-type
12695     b8/copy-to-eax 1/imm32/true
12696     0f 84/jump-if-= $type-component-match?:end/disp32
12697     # if def is a type parameter, return true
12698     {
12699 $type-component-match?:check-type-parameter:
12700       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
12701       74/jump-if-= break/disp8
12702       81 7/subop/compare *(ecx+4) 0xa/imm32/type-parameter  # Type-tree-value
12703       75/jump-if-!= break/disp8
12704 $type-component-match?:type-parameter:
12705       (type-parameter-match? *(ecx+8) *(ecx+0xc)  %edx  *(ebp+0x10))  # => eax
12706       e9/jump $type-component-match?:end/disp32
12707     }
12708 $type-component-match?:compare-atom-state:
12709     # if (def->is-atom? != call->is-atom?) return false
12710     8b/-> *ecx 3/r32/ebx  # Type-tree-is-atom
12711     39/compare *edx 3/r32/ebx  # Type-tree-is-atom
12712     b8/copy-to-eax 0/imm32/false
12713     0f 85/jump-if-!= $type-component-match?:end/disp32
12714     # if def->is-atom? return (def->value == call->value)
12715     {
12716 $type-component-match?:check-atom:
12717       81 7/subop/compare %ebx 0/imm32/false
12718       74/jump-if-= break/disp8
12719 $type-component-match?:is-atom:
12720       8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
12721       39/compare *(edx+4) 0/r32/eax  # Type-tree-value
12722       0f 94/set-if-= %al
12723       81 4/subop/and %eax 0xff/imm32
12724       e9/jump $type-component-match?:end/disp32
12725     }
12726 $type-component-match?:check-left:
12727     # if (!type-component-match?(def->left, call->left)) return false
12728     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12729     89/<- %ebx 0/r32/eax
12730     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
12731     (type-component-match? %ebx %eax *(ebp+0x10))  # => eax
12732     3d/compare-eax-and 0/imm32/false
12733     74/jump-if-= $type-component-match?:end/disp8
12734 $type-component-match?:check-right:
12735     # return type-component-match?(def->right, call->right)
12736     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
12737     89/<- %ebx 0/r32/eax
12738     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
12739     (type-component-match? %ebx %eax *(ebp+0x10))  # => eax
12740 $type-component-match?:end:
12741     # . restore registers
12742     5b/pop-to-ebx
12743     5a/pop-to-edx
12744     59/pop-to-ecx
12745     # . epilogue
12746     89/<- %esp 5/r32/ebp
12747     5d/pop-to-ebp
12748     c3/return
12749 
12750 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
12751     # . prologue
12752     55/push-ebp
12753     89/<- %ebp 4/r32/esp
12754     # . save registers
12755     51/push-ecx
12756     #
12757     (get-or-insert-handle *(ebp+0x14)  *(ebp+8) *(ebp+0xc)  0xc)  # => eax
12758     # if parameter wasn't saved, save it
12759     {
12760       81 7/subop/compare *eax 0/imm32
12761       75/jump-if-!= break/disp8
12762       8b/-> *(ebp+0x10) 1/r32/ecx
12763       89/<- *eax 1/r32/ecx
12764     }
12765     #
12766     (type-equal? *(ebp+0x10) *eax)  # => eax
12767 $type-parameter-match?:end:
12768     # . restore registers
12769     59/pop-to-ecx
12770     # . epilogue
12771     89/<- %esp 5/r32/ebp
12772     5d/pop-to-ebp
12773     c3/return
12774 
12775 size-of:  # v: (addr var) -> result/eax: int
12776     # . prologue
12777     55/push-ebp
12778     89/<- %ebp 4/r32/esp
12779     # . save registers
12780     51/push-ecx
12781     # var t/ecx: (addr type-tree) = lookup(v->type)
12782     8b/-> *(ebp+8) 1/r32/ecx
12783 #?     (write-buffered Stderr "size-of ")
12784 #?     (write-int32-hex-buffered Stderr %ecx)
12785 #?     (write-buffered Stderr Newline)
12786 #?     (write-buffered Stderr "type allocid: ")
12787 #?     (write-int32-hex-buffered Stderr *(ecx+8))
12788 #?     (write-buffered Stderr Newline)
12789 #?     (flush Stderr)
12790     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
12791     89/<- %ecx 0/r32/eax
12792     # if is-mu-array?(t) return size-of-array(t)
12793     {
12794       (is-mu-array? %ecx)  # => eax
12795       3d/compare-eax-and 0/imm32/false
12796       74/jump-if-= break/disp8
12797       (size-of-array %ecx)  # => eax
12798       eb/jump $size-of:end/disp8
12799     }
12800     # if (!t->is-atom?) t = lookup(t->left)
12801     {
12802       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
12803       75/jump-if-!= break/disp8
12804       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12805       89/<- %ecx 0/r32/eax
12806     }
12807     # TODO: assert t->is-atom?
12808     (size-of-type-id *(ecx+4))  # Type-tree-value => eax
12809 $size-of:end:
12810     # . restore registers
12811     59/pop-to-ecx
12812     # . epilogue
12813     89/<- %esp 5/r32/ebp
12814     5d/pop-to-ebp
12815     c3/return
12816 
12817 size-of-deref:  # v: (addr var) -> result/eax: int
12818     # . prologue
12819     55/push-ebp
12820     89/<- %ebp 4/r32/esp
12821     # . save registers
12822     51/push-ecx
12823     # var t/ecx: (addr type-tree) = lookup(v->type)
12824     8b/-> *(ebp+8) 1/r32/ecx
12825     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
12826     89/<- %ecx 0/r32/eax
12827     # TODO: assert(t is an addr)
12828     # t = lookup(t->right)
12829     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
12830     89/<- %ecx 0/r32/eax
12831     # if is-mu-array?(t) return size-of-array(t)
12832     {
12833       (is-mu-array? %ecx)  # => eax
12834       3d/compare-eax-and 0/imm32/false
12835       74/jump-if-= break/disp8
12836       (size-of-array %ecx)  # => eax
12837       eb/jump $size-of:end/disp8
12838     }
12839     # if (!t->is-atom?) t = lookup(t->left)
12840     {
12841       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
12842       75/jump-if-!= break/disp8
12843       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12844       89/<- %ecx 0/r32/eax
12845     }
12846     # TODO: assert t->is-atom?
12847     (size-of-type-id *(ecx+4))  # Type-tree-value => eax
12848 $size-of-deref:end:
12849     # . restore registers
12850     59/pop-to-ecx
12851     # . epilogue
12852     89/<- %esp 5/r32/ebp
12853     5d/pop-to-ebp
12854     c3/return
12855 
12856 is-mu-array?:  # t: (addr type-tree) -> result/eax: boolean
12857     # . prologue
12858     55/push-ebp
12859     89/<- %ebp 4/r32/esp
12860     # . save registers
12861     51/push-ecx
12862     # ecx = t
12863     8b/-> *(ebp+8) 1/r32/ecx
12864     # if t->is-atom?, return false
12865     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
12866     75/jump-if-!= $is-mu-array?:return-false/disp8
12867     # if !t->left->is-atom?, return false
12868     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12869     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
12870     74/jump-if-= $is-mu-array?:return-false/disp8
12871     # return t->left->value == array
12872     81 7/subop/compare *(eax+4) 3/imm32/array-type-id  # Type-tree-value
12873     0f 94/set-if-= %al
12874     81 4/subop/and %eax 0xff/imm32
12875     eb/jump $is-mu-array?:end/disp8
12876 $is-mu-array?:return-false:
12877     b8/copy-to-eax 0/imm32/false
12878 $is-mu-array?:end:
12879     # . restore registers
12880     59/pop-to-ecx
12881     # . epilogue
12882     89/<- %esp 5/r32/ebp
12883     5d/pop-to-ebp
12884     c3/return
12885 
12886 size-of-array:  # a: (addr type-tree) -> result/eax: int
12887     # . prologue
12888     55/push-ebp
12889     89/<- %ebp 4/r32/esp
12890     # . save registers
12891     51/push-ecx
12892     52/push-edx
12893     #
12894     8b/-> *(ebp+8) 1/r32/ecx
12895     # TODO: assert that a->left is 'array'
12896     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
12897     89/<- %ecx 0/r32/eax
12898     # var elem-type/edx: type-id = a->right->left->value
12899     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12900     8b/-> *(eax+4) 2/r32/edx  # Type-tree-value
12901     # TODO: assert that a->right->right->left->value == size
12902     # var array-size/ecx: int = a->right->right->left->value-size
12903     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
12904     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
12905     8b/-> *(eax+8) 1/r32/ecx  # Type-tree-value-size
12906     # return array-size * size-of(elem-type)
12907     (size-of-type-id-as-array-element %edx)  # => eax
12908     f7 4/subop/multiply-into-eax %ecx
12909     05/add-to-eax 4/imm32  # for array size
12910 $size-of-array:end:
12911     # . restore registers
12912     5a/pop-to-edx
12913     59/pop-to-ecx
12914     # . epilogue
12915     89/<- %esp 5/r32/ebp
12916     5d/pop-to-ebp
12917     c3/return
12918 
12919 size-of-type-id:  # t: type-id -> result/eax: int
12920     # . prologue
12921     55/push-ebp
12922     89/<- %ebp 4/r32/esp
12923     # . save registers
12924     51/push-ecx
12925     # var out/ecx: (handle typeinfo)
12926     68/push 0/imm32
12927     68/push 0/imm32
12928     89/<- %ecx 4/r32/esp
12929     # eax = t
12930     8b/-> *(ebp+8) 0/r32/eax
12931     # if t is a literal, return 0
12932     3d/compare-eax-and 0/imm32
12933     0f 84/jump-if-= $size-of-type-id:end/disp32  # eax changes type from type-id to int
12934     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
12935     3d/compare-eax-and 8/imm32/byte
12936     {
12937       75/jump-if-!= break/disp8
12938       b8/copy-to-eax 4/imm32
12939       eb/jump $size-of-type-id:end/disp8
12940     }
12941     # if t is a handle, return 8
12942     3d/compare-eax-and 4/imm32/handle
12943     {
12944       75/jump-if-!= break/disp8
12945       b8/copy-to-eax 8/imm32
12946       eb/jump $size-of-type-id:end/disp8  # eax changes type from type-id to int
12947     }
12948     # if t is a user-defined type, return its size
12949     # TODO: support non-atom type
12950     (find-typeinfo %eax %ecx)
12951     {
12952       81 7/subop/compare *ecx 0/imm32
12953       74/jump-if-= break/disp8
12954 $size-of-type-id:user-defined:
12955       (lookup *ecx *(ecx+4))  # => eax
12956       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
12957       eb/jump $size-of-type-id:end/disp8
12958     }
12959     # otherwise return the word size
12960     b8/copy-to-eax 4/imm32
12961 $size-of-type-id:end:
12962     # . reclaim locals
12963     81 0/subop/add %esp 8/imm32
12964     # . restore registers
12965     59/pop-to-ecx
12966     # . epilogue
12967     89/<- %esp 5/r32/ebp
12968     5d/pop-to-ebp
12969     c3/return
12970 
12971 type-equal?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
12972     # . prologue
12973     55/push-ebp
12974     89/<- %ebp 4/r32/esp
12975     # . save registers
12976     51/push-ecx
12977     52/push-edx
12978     53/push-ebx
12979     # ecx = a
12980     8b/-> *(ebp+8) 1/r32/ecx
12981     # edx = b
12982     8b/-> *(ebp+0xc) 2/r32/edx
12983 $type-equal?:compare-addr:
12984     # if (a == b) return true
12985     8b/-> %ecx 0/r32/eax  # Var-type
12986     39/compare %edx 0/r32/eax  # Var-type
12987     b8/copy-to-eax 1/imm32/true
12988     0f 84/jump-if-= $type-equal?:end/disp32
12989 $type-equal?:compare-atom-state:
12990     # if (a->is-atom? != b->is-atom?) return false
12991     8b/-> *ecx 3/r32/ebx  # Type-tree-is-atom
12992     39/compare *edx 3/r32/ebx  # Type-tree-is-atom
12993     b8/copy-to-eax 0/imm32/false
12994     0f 85/jump-if-!= $type-equal?:end/disp32
12995     # if a->is-atom? return (a->value == b->value)
12996     {
12997 $type-equal?:check-atom:
12998       81 7/subop/compare %ebx 0/imm32/false
12999       74/jump-if-= break/disp8
13000 $type-equal?:is-atom:
13001       8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
13002       39/compare *(edx+4) 0/r32/eax  # Type-tree-value
13003       0f 94/set-if-= %al
13004       81 4/subop/and %eax 0xff/imm32
13005       e9/jump $type-equal?:end/disp32
13006     }
13007 $type-equal?:check-left:
13008     # if (!type-equal?(a->left, b->left)) return false
13009     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
13010     89/<- %ebx 0/r32/eax
13011     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
13012     (type-equal? %eax %ebx)  # => eax
13013     3d/compare-eax-and 0/imm32/false
13014     74/jump-if-= $type-equal?:end/disp8
13015 $type-equal?:check-right:
13016     # return type-equal?(a->right, b->right)
13017     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
13018     89/<- %ebx 0/r32/eax
13019     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
13020     (type-equal? %eax %ebx)  # => eax
13021 $type-equal?:end:
13022     # . restore registers
13023     5b/pop-to-ebx
13024     5a/pop-to-edx
13025     59/pop-to-ecx
13026     # . epilogue
13027     89/<- %esp 5/r32/ebp
13028     5d/pop-to-ebp
13029     c3/return
13030 
13031 #######################################################
13032 # Code-generation
13033 #######################################################
13034 
13035 == data
13036 
13037 # Global state added to each var record when performing code-generation.
13038 Curr-local-stack-offset:  # (addr int)
13039     0/imm32
13040 
13041 == code
13042 
13043 emit-subx:  # out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
13044     # . prologue
13045     55/push-ebp
13046     89/<- %ebp 4/r32/esp
13047     # . save registers
13048     50/push-eax
13049     # var curr/eax: (addr function) = *Program->functions
13050     (lookup *_Program-functions *_Program-functions->payload)  # => eax
13051     {
13052       # if (curr == null) break
13053       3d/compare-eax-and 0/imm32
13054       0f 84/jump-if-= break/disp32
13055       (emit-subx-function *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))
13056       # curr = lookup(curr->next)
13057       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
13058       e9/jump loop/disp32
13059     }
13060 $emit-subx:end:
13061     # . restore registers
13062     58/pop-to-eax
13063     # . epilogue
13064     89/<- %esp 5/r32/ebp
13065     5d/pop-to-ebp
13066     c3/return
13067 
13068 emit-subx-function:  # out: (addr buffered-file), f: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13069     # . prologue
13070     55/push-ebp
13071     89/<- %ebp 4/r32/esp
13072     # some preprocessing
13073     (populate-mu-type-offsets-in-inouts *(ebp+0xc))
13074     # . save registers
13075     50/push-eax
13076     51/push-ecx
13077     52/push-edx
13078     # initialize some global state
13079     c7 0/subop/copy *Curr-block-depth 1/imm32  # Important: keep this in sync with the parse phase
13080     c7 0/subop/copy *Curr-local-stack-offset 0/imm32
13081     # ecx = f
13082     8b/-> *(ebp+0xc) 1/r32/ecx
13083     # var vars/edx: (stack (addr var) 256)
13084     81 5/subop/subtract %esp 0xc00/imm32
13085     68/push 0xc00/imm32/size
13086     68/push 0/imm32/top
13087     89/<- %edx 4/r32/esp
13088     # var name/eax: (addr array byte) = lookup(f->name)
13089     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
13090     #
13091     (write-buffered *(ebp+8) %eax)
13092     (write-buffered *(ebp+8) ":\n")
13093     (emit-subx-prologue *(ebp+8))
13094     # var body/eax: (addr block) = lookup(f->body)
13095     (lookup *(ecx+0x18) *(ecx+0x1c))  # Function-body Function-body => eax
13096     #
13097     (emit-subx-block *(ebp+8) %eax %edx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13098     (emit-subx-epilogue *(ebp+8))
13099     # TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have
13100     # been cleaned up
13101 $emit-subx-function:end:
13102     # . reclaim locals
13103     81 0/subop/add %esp 0xc08/imm32
13104     # . restore registers
13105     5a/pop-to-edx
13106     59/pop-to-ecx
13107     58/pop-to-eax
13108     # . epilogue
13109     89/<- %esp 5/r32/ebp
13110     5d/pop-to-ebp
13111     c3/return
13112 
13113 populate-mu-type-offsets-in-inouts:  # f: (addr function)
13114     # . prologue
13115     55/push-ebp
13116     89/<- %ebp 4/r32/esp
13117     # . save registers
13118     50/push-eax
13119     51/push-ecx
13120     52/push-edx
13121     53/push-ebx
13122     57/push-edi
13123     # var next-offset/edx: int = 8
13124     ba/copy-to-edx 8/imm32
13125     # var curr/ecx: (addr list var) = lookup(f->inouts)
13126     8b/-> *(ebp+8) 1/r32/ecx
13127     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
13128     89/<- %ecx 0/r32/eax
13129     {
13130 $populate-mu-type-offsets-in-inouts:loop:
13131       81 7/subop/compare %ecx 0/imm32
13132       74/jump-if-= break/disp8
13133       # var v/ebx: (addr var) = lookup(curr->value)
13134       (lookup *ecx *(ecx+4))  # List-value List-value => eax
13135       89/<- %ebx 0/r32/eax
13136 #?       (lookup *ebx *(ebx+4))
13137 #?       (write-buffered Stderr "setting offset of fn inout ")
13138 #?       (write-buffered Stderr %eax)
13139 #?       (write-buffered Stderr "@")
13140 #?       (write-int32-hex-buffered Stderr %ebx)
13141 #?       (write-buffered Stderr " to ")
13142 #?       (write-int32-hex-buffered Stderr %edx)
13143 #?       (write-buffered Stderr Newline)
13144 #?       (flush Stderr)
13145       # v->offset = next-offset
13146       89/<- *(ebx+0x14) 2/r32/edx  # Var-offset
13147       # next-offset += size-of(v)
13148       (size-of %ebx)  # => eax
13149       01/add-to %edx 0/r32/eax
13150       # curr = lookup(curr->next)
13151       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
13152       89/<- %ecx 0/r32/eax
13153       #
13154       eb/jump loop/disp8
13155     }
13156 $populate-mu-type-offsets-in-inouts:end:
13157     # . restore registers
13158     5f/pop-to-edi
13159     5b/pop-to-ebx
13160     5a/pop-to-edx
13161     59/pop-to-ecx
13162     58/pop-to-eax
13163     # . epilogue
13164     89/<- %esp 5/r32/ebp
13165     5d/pop-to-ebp
13166     c3/return
13167 
13168 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)
13169     # . prologue
13170     55/push-ebp
13171     89/<- %ebp 4/r32/esp
13172     # . save registers
13173     50/push-eax
13174     51/push-ecx
13175     53/push-ebx
13176     56/push-esi
13177     # esi = stmts
13178     8b/-> *(ebp+0xc) 6/r32/esi
13179     #
13180     {
13181 $emit-subx-stmt-list:loop:
13182       81 7/subop/compare %esi 0/imm32
13183       0f 84/jump-if-= break/disp32
13184       # var curr-stmt/ecx: (addr stmt) = lookup(stmts->value)
13185       (lookup *esi *(esi+4))  # List-value List-value => eax
13186       89/<- %ecx 0/r32/eax
13187       {
13188 $emit-subx-stmt-list:check-for-block:
13189         81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
13190         75/jump-if-!= break/disp8
13191 $emit-subx-stmt-list:block:
13192         (emit-subx-block *(ebp+8) %ecx *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
13193       }
13194       {
13195 $emit-subx-stmt-list:check-for-stmt:
13196         81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
13197         0f 85/jump-if-!= break/disp32
13198 $emit-subx-stmt-list:stmt1:
13199         {
13200           (is-mu-branch? %ecx)  # => eax
13201           3d/compare-eax-and 0/imm32/false
13202           0f 84/jump-if-= break/disp32
13203 $emit-subx-stmt-list:branch-stmt:
13204 +-- 27 lines: # unconditional loops -----------------------------------------------------------------------------------------------------------------------------------------------------
13231 +-- 16 lines: # unconditional breaks ----------------------------------------------------------------------------------------------------------------------------------------------------
13247 +-- 38 lines: # simple conditional branches without a target ----------------------------------------------------------------------------------------------------------------------------
13285 +-- 19 lines: # conditional branches with an explicit target ----------------------------------------------------------------------------------------------------------------------------
13304         }
13305 $emit-subx-stmt-list:1-to-1:
13306         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
13307         e9/jump $emit-subx-stmt-list:continue/disp32
13308       }
13309       {
13310 $emit-subx-stmt-list:check-for-var-def:
13311         81 7/subop/compare *ecx 2/imm32/var-def  # Stmt-tag
13312         75/jump-if-!= break/disp8
13313 $emit-subx-stmt-list:var-def:
13314         (emit-subx-var-def *(ebp+8) %ecx)
13315         (push *(ebp+0x10) *(ecx+4))  # Vardef-var
13316         (push *(ebp+0x10) *(ecx+8))  # Vardef-var
13317         (push *(ebp+0x10) 0)  # Live-var-register-spilled = 0 for vars on the stack
13318         #
13319         eb/jump $emit-subx-stmt-list:continue/disp8
13320       }
13321       {
13322 $emit-subx-stmt-list:check-for-reg-var-def:
13323         81 7/subop/compare *ecx 3/imm32/reg-var-def  # Stmt-tag
13324         0f 85/jump-if-!= break/disp32
13325 $emit-subx-stmt-list:reg-var-def:
13326         # TODO: ensure that there's exactly one output
13327         (push-output-and-maybe-emit-spill *(ebp+8) %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
13328         # emit the instruction as usual
13329         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
13330         #
13331         eb/jump $emit-subx-stmt-list:continue/disp8
13332       }
13333 $emit-subx-stmt-list:continue:
13334       # TODO: raise an error on unrecognized Stmt-tag
13335       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
13336       89/<- %esi 0/r32/eax
13337       e9/jump loop/disp32
13338     }
13339 $emit-subx-stmt-list:emit-cleanup:
13340     (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
13341 $emit-subx-stmt-list:clean-up:
13342     (clean-up-blocks *(ebp+0x10) *Curr-block-depth *(ebp+0x14))
13343 $emit-subx-stmt-list:end:
13344     # . restore registers
13345     5e/pop-to-esi
13346     5b/pop-to-ebx
13347     59/pop-to-ecx
13348     58/pop-to-eax
13349     # . epilogue
13350     89/<- %esp 5/r32/ebp
13351     5d/pop-to-ebp
13352     c3/return
13353 
13354 # 'later-stmts' includes 'stmt', but will behave the same even without it; reg-var-def stmts are guaranteed not to write to function outputs.
13355 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)
13356     # . prologue
13357     55/push-ebp
13358     89/<- %ebp 4/r32/esp
13359     # . save registers
13360     50/push-eax
13361     51/push-ecx
13362     52/push-edx
13363     # ecx = stmt
13364     8b/-> *(ebp+0xc) 1/r32/ecx
13365     # var sv/eax: (addr stmt-var) = lookup(curr-stmt->outputs)
13366     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
13367     # TODO: assert !sv->is-deref?
13368     # var v/ecx: (addr var) = lookup(sv->value)
13369     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13370     89/<- %ecx 0/r32/eax
13371     # v->block-depth = *Curr-block-depth
13372     8b/-> *Curr-block-depth 0/r32/eax
13373     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
13374 #?     (write-buffered Stderr "var ")
13375 #?     (lookup *ecx *(ecx+4))
13376 #?     (write-buffered Stderr %eax)
13377 #?     (write-buffered Stderr " at depth ")
13378 #?     (write-int32-hex-buffered Stderr *(ecx+0x10))
13379 #?     (write-buffered Stderr Newline)
13380 #?     (flush Stderr)
13381     # ensure that v is in a register
13382     81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13383     0f 84/jump-if-= $push-output-and-maybe-emit-spill:abort/disp32
13384     # var emit-spill?/edx: boolean = not-yet-spilled-this-block? && will-not-write-some-register?(fn)
13385     (not-yet-spilled-this-block? %ecx *(ebp+0x10))  # => eax
13386     89/<- %edx 0/r32/eax
13387     3d/compare-eax-and 0/imm32/false
13388     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
13389     (will-not-write-some-register? %ecx *(ebp+0x14) *(ebp+0x18))  # => eax
13390     89/<- %edx 0/r32/eax
13391     # check emit-spill?
13392     3d/compare-eax-and 0/imm32/false
13393     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
13394     # TODO: assert(size-of(output) == 4)
13395     # *Curr-local-stack-offset -= 4
13396     81 5/subop/subtract *Curr-local-stack-offset 4/imm32
13397     # emit spill
13398     (emit-indent *(ebp+8) *Curr-block-depth)
13399     (write-buffered *(ebp+8) "ff 6/subop/push %")
13400     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
13401     (write-buffered *(ebp+8) %eax)
13402     (write-buffered *(ebp+8) Newline)
13403 $push-output-and-maybe-emit-spill:push:
13404     8b/-> *(ebp+0xc) 1/r32/ecx
13405     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
13406     # push(vars, {sv->value, emit-spill?})
13407     (push *(ebp+0x10) *eax)  # Stmt-var-value
13408     (push *(ebp+0x10) *(eax+4))  # Stmt-var-value
13409     (push *(ebp+0x10) %edx)
13410 $push-output-and-maybe-emit-spill:end:
13411     # . restore registers
13412     5a/pop-to-edx
13413     59/pop-to-ecx
13414     58/pop-to-eax
13415     # . epilogue
13416     89/<- %esp 5/r32/ebp
13417     5d/pop-to-ebp
13418     c3/return
13419 
13420 $push-output-and-maybe-emit-spill:abort:
13421     # error("var '" var->name "' initialized from an instruction must live in a register\n")
13422     (write-buffered *(ebp+0x1c) "var '")
13423     (write-buffered *(ebp+0x1c) *eax)  # Var-name
13424     (write-buffered *(ebp+0x1c) "' initialized from an instruction must live in a register\n")
13425     (flush *(ebp+0x1c))
13426     (stop *(ebp+0x20) 1)
13427     # never gets here
13428 
13429 emit-subx-cleanup-and-unconditional-nonlocal-branch:  # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack live-var)
13430     # . prologue
13431     55/push-ebp
13432     89/<- %ebp 4/r32/esp
13433     # . save registers
13434     50/push-eax
13435     51/push-ecx
13436     # ecx = stmt
13437     8b/-> *(ebp+0xc) 1/r32/ecx
13438     # var target/eax: (addr array byte) = curr-stmt->inouts->value->name
13439     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13440     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13441     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13442     # clean up until target block
13443     (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %eax)
13444     # emit jump to target block
13445     (emit-indent *(ebp+8) *Curr-block-depth)
13446     (write-buffered *(ebp+8) "e9/jump ")
13447     (write-buffered *(ebp+8) %eax)
13448     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
13449     (string-starts-with? %eax "break")
13450     3d/compare-eax-and 0/imm32/false
13451     {
13452       74/jump-if-= break/disp8
13453       (write-buffered *(ebp+8) ":break/disp32\n")
13454     }
13455     3d/compare-eax-and 0/imm32/false  # just in case the function call modified flags
13456     {
13457       75/jump-if-!= break/disp8
13458       (write-buffered *(ebp+8) ":loop/disp32\n")
13459     }
13460 $emit-subx-cleanup-and-unconditional-nonlocal-branch:end:
13461     # . restore registers
13462     59/pop-to-ecx
13463     58/pop-to-eax
13464     # . epilogue
13465     89/<- %esp 5/r32/ebp
13466     5d/pop-to-ebp
13467     c3/return
13468 
13469 is-mu-branch?:  # stmt: (addr stmt1) -> result/eax: boolean
13470     # . prologue
13471     55/push-ebp
13472     89/<- %ebp 4/r32/esp
13473     # . save registers
13474     51/push-ecx
13475     # ecx = lookup(stmt->operation)
13476     8b/-> *(ebp+8) 1/r32/ecx
13477     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
13478     89/<- %ecx 0/r32/eax
13479     # if (stmt->operation starts with "loop") return true
13480     (string-starts-with? %ecx "loop")  # => eax
13481     3d/compare-eax-and 0/imm32/false
13482     75/jump-if-not-equal $is-mu-branch?:end/disp8
13483     # otherwise return (stmt->operation starts with "break")
13484     (string-starts-with? %ecx "break")  # => eax
13485 $is-mu-branch?:end:
13486     # . restore registers
13487     59/pop-to-ecx
13488     # . epilogue
13489     89/<- %esp 5/r32/ebp
13490     5d/pop-to-ebp
13491     c3/return
13492 
13493 emit-reverse-break:  # out: (addr buffered-file), stmt: (addr stmt1)
13494     # . prologue
13495     55/push-ebp
13496     89/<- %ebp 4/r32/esp
13497     # . save registers
13498     50/push-eax
13499     # eax = stmt
13500     8b/-> *(ebp+0xc) 0/r32/eax
13501     #
13502     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
13503     (get Reverse-branch %eax 0x10 "reverse-branch: ")  # => eax: (addr handle array byte)
13504     (emit-indent *(ebp+8) *Curr-block-depth)
13505     (lookup *eax *(eax+4))  # => eax
13506     (write-buffered *(ebp+8) %eax)
13507     (write-buffered *(ebp+8) " break/disp32\n")
13508 $emit-reverse-break:end:
13509     # . restore registers
13510     58/pop-to-eax
13511     # . epilogue
13512     89/<- %esp 5/r32/ebp
13513     5d/pop-to-ebp
13514     c3/return
13515 
13516 == data
13517 
13518 # Table from Mu branch instructions to the reverse SubX opcodes for them.
13519 Reverse-branch:  # (table (handle array byte) (handle array byte))
13520   # a table is a stream
13521   0x140/imm32/write
13522   0/imm32/read
13523   0x140/imm32/size
13524   # data
13525   0x11/imm32/alloc-id   _string-break-if-=/imm32                0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
13526   0x11/imm32/alloc-id   _string-loop-if-=/imm32                 0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
13527   0x11/imm32/alloc-id   _string-break-if-!=/imm32               0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
13528   0x11/imm32/alloc-id   _string-loop-if-!=/imm32                0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
13529   0x11/imm32/alloc-id   _string-break-if-</imm32                0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
13530   0x11/imm32/alloc-id   _string-loop-if-</imm32                 0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
13531   0x11/imm32/alloc-id   _string-break-if->/imm32                0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
13532   0x11/imm32/alloc-id   _string-loop-if->/imm32                 0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
13533   0x11/imm32/alloc-id   _string-break-if-<=/imm32               0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
13534   0x11/imm32/alloc-id   _string-loop-if-<=/imm32                0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
13535   0x11/imm32/alloc-id   _string-break-if->=/imm32               0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
13536   0x11/imm32/alloc-id   _string-loop-if->=/imm32                0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
13537   0x11/imm32/alloc-id   _string-break-if-addr</imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
13538   0x11/imm32/alloc-id   _string-loop-if-addr</imm32             0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
13539   0x11/imm32/alloc-id   _string-break-if-addr>/imm32            0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
13540   0x11/imm32/alloc-id   _string-loop-if-addr>/imm32             0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
13541   0x11/imm32/alloc-id   _string-break-if-addr<=/imm32           0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
13542   0x11/imm32/alloc-id   _string-loop-if-addr<=/imm32            0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
13543   0x11/imm32/alloc-id   _string-break-if-addr>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
13544   0x11/imm32/alloc-id   _string-loop-if-addr>=/imm32            0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
13545 
13546 == code
13547 
13548 emit-unconditional-jump-to-depth:  # out: (addr buffered-file), vars: (addr stack live-var), depth: int, label-suffix: (addr array byte)
13549     # . prologue
13550     55/push-ebp
13551     89/<- %ebp 4/r32/esp
13552     # . save registers
13553     50/push-eax
13554     51/push-ecx
13555     52/push-edx
13556     53/push-ebx
13557     56/push-esi
13558     # ecx = vars
13559     8b/-> *(ebp+0xc) 1/r32/ecx
13560     # var eax: int = vars->top
13561     8b/-> *ecx 0/r32/eax
13562     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
13563     8d/copy-address *(ecx+eax-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
13564     # var min/ecx: (addr handle var) = vars->data
13565     8d/copy-address *(ecx+8) 1/r32/ecx
13566     # edx = depth
13567     8b/-> *(ebp+0x10) 2/r32/edx
13568     {
13569 $emit-unconditional-jump-to-depth:loop:
13570       # if (curr < min) break
13571       39/compare %esi 1/r32/ecx
13572       0f 82/jump-if-addr< break/disp32
13573       # var v/ebx: (addr var) = lookup(*curr)
13574       (lookup *esi *(esi+4))  # => eax
13575       89/<- %ebx 0/r32/eax
13576       # if (v->block-depth < until-block-depth) break
13577       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
13578       0f 8c/jump-if-< break/disp32
13579       {
13580 $emit-unconditional-jump-to-depth:check:
13581         # if v->block-depth != until-block-depth, continue
13582         39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
13583         0f 85/jump-if-!= break/disp32
13584 $emit-unconditional-jump-to-depth:depth-found:
13585         # if v is not a literal, continue
13586         (size-of %ebx)  # => eax
13587         3d/compare-eax-and 0/imm32
13588         0f 85/jump-if-!= break/disp32
13589 $emit-unconditional-jump-to-depth:label-found:
13590         # emit unconditional jump, then return
13591         (emit-indent *(ebp+8) *Curr-block-depth)
13592         (write-buffered *(ebp+8) "e9/jump ")
13593         (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
13594         (write-buffered *(ebp+8) %eax)
13595         (write-buffered *(ebp+8) ":")
13596         (write-buffered *(ebp+8) *(ebp+0x14))
13597         (write-buffered *(ebp+8) "/disp32\n")
13598         eb/jump $emit-unconditional-jump-to-depth:end/disp8
13599       }
13600       # curr -= 12
13601       81 5/subop/subtract %esi 0xc/imm32
13602       e9/jump loop/disp32
13603     }
13604     # TODO: error if no label at 'depth' was found
13605 $emit-unconditional-jump-to-depth:end:
13606     # . restore registers
13607     5e/pop-to-esi
13608     5b/pop-to-ebx
13609     5a/pop-to-edx
13610     59/pop-to-ecx
13611     58/pop-to-eax
13612     # . epilogue
13613     89/<- %esp 5/r32/ebp
13614     5d/pop-to-ebp
13615     c3/return
13616 
13617 # emit clean-up code for 'vars' until some block depth
13618 # doesn't actually modify 'vars' so we need traverse manually inside the stack
13619 emit-cleanup-code-until-depth:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-depth: int
13620     # . prologue
13621     55/push-ebp
13622     89/<- %ebp 4/r32/esp
13623     # . save registers
13624     50/push-eax
13625     51/push-ecx
13626     52/push-edx
13627     53/push-ebx
13628     56/push-esi
13629 #?     (write-buffered Stderr "--- cleanup\n")
13630 #?     (flush Stderr)
13631     # ecx = vars
13632     8b/-> *(ebp+0xc) 1/r32/ecx
13633     # var esi: int = vars->top
13634     8b/-> *ecx 6/r32/esi
13635     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
13636     8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
13637     # var min/ecx: (addr handle var) = vars->data
13638     81 0/subop/add %ecx 8/imm32
13639     # edx = until-block-depth
13640     8b/-> *(ebp+0x10) 2/r32/edx
13641     {
13642 $emit-cleanup-code-until-depth:loop:
13643       # if (curr < min) break
13644       39/compare %esi 1/r32/ecx
13645       0f 82/jump-if-addr< break/disp32
13646       # var v/ebx: (addr var) = lookup(*curr)
13647       (lookup *esi *(esi+4))  # => eax
13648       89/<- %ebx 0/r32/eax
13649 #?       (lookup *ebx *(ebx+4))  # Var-name
13650 #?       (write-buffered Stderr "var ")
13651 #?       (write-buffered Stderr %eax)
13652 #?       (write-buffered Stderr Newline)
13653 #?       (flush Stderr)
13654       # if (v->block-depth < until-block-depth) break
13655       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
13656       0f 8c/jump-if-< break/disp32
13657       # if v is in a register
13658       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
13659       {
13660         0f 84/jump-if-= break/disp32
13661         {
13662 $emit-cleanup-code-until-depth:check-for-previous-spill:
13663           8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
13664           3d/compare-eax-and 0/imm32/false
13665           74/jump-if-= break/disp8
13666 $emit-cleanup-code-until-depth:reclaim-var-in-register:
13667           (emit-indent *(ebp+8) *Curr-block-depth)
13668           (write-buffered *(ebp+8) "8f 0/subop/pop %")
13669           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
13670           (write-buffered *(ebp+8) %eax)
13671           (write-buffered *(ebp+8) Newline)
13672         }
13673         eb/jump $emit-cleanup-code-until-depth:continue/disp8
13674       }
13675       # otherwise v is on the stack
13676       {
13677         75/jump-if-!= break/disp8
13678 $emit-cleanup-code-until-depth:var-on-stack:
13679         (size-of %ebx)  # => eax
13680         # don't emit code for labels
13681         3d/compare-eax-and 0/imm32
13682         74/jump-if-= break/disp8
13683 $emit-cleanup-code-until-depth:reclaim-var-on-stack:
13684         (emit-indent *(ebp+8) *Curr-block-depth)
13685         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
13686         (write-int32-hex-buffered *(ebp+8) %eax)
13687         (write-buffered *(ebp+8) "/imm32\n")
13688       }
13689 $emit-cleanup-code-until-depth:continue:
13690       # curr -= 12
13691       81 5/subop/subtract %esi 0xc/imm32
13692       e9/jump loop/disp32
13693     }
13694 $emit-cleanup-code-until-depth:end:
13695     # . restore registers
13696     5e/pop-to-esi
13697     5b/pop-to-ebx
13698     5a/pop-to-edx
13699     59/pop-to-ecx
13700     58/pop-to-eax
13701     # . epilogue
13702     89/<- %esp 5/r32/ebp
13703     5d/pop-to-ebp
13704     c3/return
13705 
13706 # emit clean-up code for 'vars' until a given label is encountered
13707 # doesn't actually modify 'vars' so we need traverse manually inside the stack
13708 emit-cleanup-code-until-target:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-label: (addr array byte)
13709     # . prologue
13710     55/push-ebp
13711     89/<- %ebp 4/r32/esp
13712     # . save registers
13713     50/push-eax
13714     51/push-ecx
13715     52/push-edx
13716     53/push-ebx
13717     # ecx = vars
13718     8b/-> *(ebp+0xc) 1/r32/ecx
13719     # var eax: int = vars->top
13720     8b/-> *ecx 0/r32/eax
13721     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
13722     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
13723     # var min/ecx: (addr handle var) = vars->data
13724     81 0/subop/add %ecx 8/imm32
13725     {
13726 $emit-cleanup-code-until-target:loop:
13727       # if (curr < min) break
13728       39/compare %edx 1/r32/ecx
13729       0f 82/jump-if-addr< break/disp32
13730       # var v/ebx: (handle var) = lookup(*curr)
13731       (lookup *edx *(edx+4))  # => eax
13732       89/<- %ebx 0/r32/eax
13733       # if (v->name == until-block-label) break
13734       (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
13735       (string-equal? %eax *(ebp+0x10))  # => eax
13736       3d/compare-eax-and 0/imm32/false
13737       0f 85/jump-if-!= break/disp32
13738       # if v is in a register
13739       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
13740       {
13741         0f 84/jump-if-= break/disp32
13742         {
13743 $emit-cleanup-code-until-target:check-for-previous-spill:
13744           8b/-> *(edx+8) 0/r32/eax  # Live-var-register-spilled
13745           3d/compare-eax-and 0/imm32/false
13746           74/jump-if-= break/disp8
13747 $emit-cleanup-code-until-target:reclaim-var-in-register:
13748           (emit-indent *(ebp+8) *Curr-block-depth)
13749           (write-buffered *(ebp+8) "8f 0/subop/pop %")
13750           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
13751           (write-buffered *(ebp+8) %eax)
13752           (write-buffered *(ebp+8) Newline)
13753         }
13754         eb/jump $emit-cleanup-code-until-target:continue/disp8
13755       }
13756       # otherwise v is on the stack
13757       {
13758         75/jump-if-!= break/disp8
13759 $emit-cleanup-code-until-target:reclaim-var-on-stack:
13760         (size-of %ebx)  # => eax
13761         # don't emit code for labels
13762         3d/compare-eax-and 0/imm32
13763         74/jump-if-= break/disp8
13764         #
13765         (emit-indent *(ebp+8) *Curr-block-depth)
13766         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
13767         (write-int32-hex-buffered *(ebp+8) %eax)
13768         (write-buffered *(ebp+8) "/imm32\n")
13769       }
13770 $emit-cleanup-code-until-target:continue:
13771       # curr -= 12
13772       81 5/subop/subtract %edx 0xc/imm32
13773       e9/jump loop/disp32
13774     }
13775 $emit-cleanup-code-until-target:end:
13776     # . restore registers
13777     5b/pop-to-ebx
13778     5a/pop-to-edx
13779     59/pop-to-ecx
13780     58/pop-to-eax
13781     # . epilogue
13782     89/<- %esp 5/r32/ebp
13783     5d/pop-to-ebp
13784     c3/return
13785 
13786 # Return true if there isn't a variable in 'vars' with the same block-depth
13787 # and register as 'v'.
13788 # 'v' is guaranteed not to be within 'vars'.
13789 not-yet-spilled-this-block?:  # v: (addr var), vars: (addr stack live-var) -> result/eax: boolean
13790     # . prologue
13791     55/push-ebp
13792     89/<- %ebp 4/r32/esp
13793     # . save registers
13794     51/push-ecx
13795     52/push-edx
13796     53/push-ebx
13797     56/push-esi
13798     57/push-edi
13799     # ecx = vars
13800     8b/-> *(ebp+0xc) 1/r32/ecx
13801     # var eax: int = vars->top
13802     8b/-> *ecx 0/r32/eax
13803     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
13804     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
13805     # var min/ecx: (addr handle var) = vars->data
13806     8d/copy-address *(ecx+8) 1/r32/ecx
13807     # var depth/ebx: int = v->block-depth
13808     8b/-> *(ebp+8) 3/r32/ebx
13809     8b/-> *(ebx+0x10) 3/r32/ebx  # Var-block-depth
13810     # var needle/esi: (addr array byte) = v->register
13811     8b/-> *(ebp+8) 6/r32/esi
13812     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
13813     89/<- %esi 0/r32/eax
13814     {
13815 $not-yet-spilled-this-block?:loop:
13816       # if (curr < min) break
13817       39/compare %edx 1/r32/ecx
13818       0f 82/jump-if-addr< break/disp32
13819       # var cand/edi: (addr var) = lookup(*curr)
13820       (lookup *edx *(edx+4))  # => eax
13821       89/<- %edi 0/r32/eax
13822       # if (cand->block-depth < depth) break
13823       39/compare *(edi+0x10) 3/r32/ebx  # Var-block-depth
13824       0f 8c/jump-if-< break/disp32
13825       # var cand-reg/edi: (array array byte) = cand->reg
13826       (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
13827       89/<- %edi 0/r32/eax
13828       # if (cand-reg == null) continue
13829       {
13830 $not-yet-spilled-this-block?:check-reg:
13831         81 7/subop/compare %edi 0/imm32
13832         0f 84/jump-if-= break/disp32
13833         # if (cand-reg == needle) return true
13834         (string-equal? %esi %edi)  # => eax
13835         3d/compare-eax-and 0/imm32/false
13836         74/jump-if-= break/disp8
13837 $not-yet-spilled-this-block?:return-false:
13838         b8/copy-to-eax 0/imm32/false
13839         eb/jump $not-yet-spilled-this-block?:end/disp8
13840       }
13841 $not-yet-spilled-this-block?:continue:
13842       # curr -= 12
13843       81 5/subop/subtract %edx 0xc/imm32
13844       e9/jump loop/disp32
13845     }
13846 $not-yet-spilled-this-block?:return-true:
13847     # return true
13848     b8/copy-to-eax 1/imm32/true
13849 $not-yet-spilled-this-block?:end:
13850     # . restore registers
13851     5f/pop-to-edi
13852     5e/pop-to-esi
13853     5b/pop-to-ebx
13854     5a/pop-to-edx
13855     59/pop-to-ecx
13856     # . epilogue
13857     89/<- %esp 5/r32/ebp
13858     5d/pop-to-ebp
13859     c3/return
13860 
13861 # could the register of 'v' ever be written to by one of the vars in fn-outputs?
13862 will-not-write-some-register?:  # v: (addr var), stmts: (addr list stmt), fn: (addr function) -> result/eax: boolean
13863     # . prologue
13864     55/push-ebp
13865     89/<- %ebp 4/r32/esp
13866     # eax = v
13867     8b/-> *(ebp+8) 0/r32/eax
13868     # var reg/eax: (addr array byte) = lookup(v->register)
13869     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
13870     # var target/eax: (addr var) = find-register(fn-outputs, reg)
13871     (find-register *(ebp+0x10) %eax)  # => eax
13872     # if (target == 0) return true
13873     {
13874       3d/compare-eax-and 0/imm32
13875       75/jump-if-!= break/disp8
13876       b8/copy-to-eax 1/imm32/true
13877       eb/jump $will-not-write-some-register?:end/disp8
13878     }
13879     # return !assigns-in-stmts?(stmts, target)
13880     (assigns-in-stmts? *(ebp+0xc) %eax)  # => eax
13881     3d/compare-eax-and 0/imm32/false
13882     # assume: true = 1, so no need to mask with 0x000000ff
13883     0f 94/set-if-= %al
13884 $will-not-write-some-register?:end:
13885     # . epilogue
13886     89/<- %esp 5/r32/ebp
13887     5d/pop-to-ebp
13888     c3/return
13889 
13890 # return fn output with matching register
13891 # always returns false if 'reg' is null
13892 find-register:  # fn: (addr function), reg: (addr array byte) -> result/eax: (addr var)
13893     # . prologue
13894     55/push-ebp
13895     89/<- %ebp 4/r32/esp
13896     # . save registers
13897     51/push-ecx
13898     # var curr/ecx: (addr list var) = lookup(fn->outputs)
13899     8b/-> *(ebp+8) 1/r32/ecx
13900     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
13901     89/<- %ecx 0/r32/eax
13902     {
13903 $find-register:loop:
13904       # if (curr == 0) break
13905       81 7/subop/compare %ecx 0/imm32
13906       74/jump-if-= break/disp8
13907       # eax = curr->value->register
13908       (lookup *ecx *(ecx+4))  # List-value List-value => eax
13909       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
13910       # if (eax == reg) return curr->value
13911 $find-register:compare:
13912       (string-equal? *(ebp+0xc) %eax)  # => eax
13913       {
13914         3d/compare-eax-and 0/imm32/false
13915         74/jump-if-= break/disp8
13916 $find-register:found:
13917         (lookup *ecx *(ecx+4))  # List-value List-value => eax
13918         eb/jump $find-register:end/disp8
13919       }
13920       # curr = lookup(curr->next)
13921       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
13922       89/<- %ecx 0/r32/eax
13923       #
13924       eb/jump loop/disp8
13925     }
13926 $find-register:end:
13927     # . restore registers
13928     59/pop-to-ecx
13929     # . epilogue
13930     89/<- %esp 5/r32/ebp
13931     5d/pop-to-ebp
13932     c3/return
13933 
13934 assigns-in-stmts?:  # stmts: (addr list stmt), v: (addr var) -> result/eax: boolean
13935     # . prologue
13936     55/push-ebp
13937     89/<- %ebp 4/r32/esp
13938     # . save registers
13939     51/push-ecx
13940     # var curr/ecx: (addr list stmt) = stmts
13941     8b/-> *(ebp+8) 1/r32/ecx
13942     {
13943       # if (curr == 0) break
13944       81 7/subop/compare %ecx 0/imm32
13945       74/jump-if-= break/disp8
13946       # if assigns-in-stmt?(curr->value, v) return true
13947       (lookup *ecx *(ecx+4))  # List-value List-value => eax
13948       (assigns-in-stmt? %eax *(ebp+0xc))  # => eax
13949       3d/compare-eax-and 0/imm32/false
13950       75/jump-if-!= break/disp8
13951       # curr = lookup(curr->next)
13952       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
13953       89/<- %ecx 0/r32/eax
13954       #
13955       eb/jump loop/disp8
13956     }
13957 $assigns-in-stmts?:end:
13958     # . restore registers
13959     59/pop-to-ecx
13960     # . epilogue
13961     89/<- %esp 5/r32/ebp
13962     5d/pop-to-ebp
13963     c3/return
13964 
13965 assigns-in-stmt?:  # stmt: (addr stmt), v: (addr var) -> result/eax: boolean
13966     # . prologue
13967     55/push-ebp
13968     89/<- %ebp 4/r32/esp
13969     # . save registers
13970     51/push-ecx
13971     # ecx = stmt
13972     8b/-> *(ebp+8) 1/r32/ecx
13973     # if stmt is a stmt1, return assigns-in-stmt-vars?(stmt->outputs, v)
13974     {
13975       81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
13976       75/jump-if-!= break/disp8
13977       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13978       (assigns-in-stmt-vars? %eax *(ebp+0xc))  # => eax
13979       eb/jump $assigns-in-stmt?:end/disp8
13980     }
13981     # if stmt is a block, return assigns-in-stmts?(stmt->stmts, v)
13982     {
13983       81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
13984       75/jump-if-!= break/disp8
13985       (lookup *(ecx+4) *(ecx+8))  # Block-stmts Block-stmts => eax
13986       (assigns-in-stmts? %eax *(ebp+0xc))  # => eax
13987       eb/jump $assigns-in-stmt?:end/disp8
13988     }
13989     # otherwise return false
13990     b8/copy 0/imm32/false
13991 $assigns-in-stmt?:end:
13992     # . restore registers
13993     59/pop-to-ecx
13994     # . epilogue
13995     89/<- %esp 5/r32/ebp
13996     5d/pop-to-ebp
13997     c3/return
13998 
13999 assigns-in-stmt-vars?:  # stmt-var: (addr stmt-var), v: (addr var) -> result/eax: boolean
14000     # . prologue
14001     55/push-ebp
14002     89/<- %ebp 4/r32/esp
14003     # . save registers
14004     51/push-ecx
14005     # var curr/ecx: (addr stmt-var) = stmt-var
14006     8b/-> *(ebp+8) 1/r32/ecx
14007     {
14008       # if (curr == 0) break
14009       81 7/subop/compare %ecx 0/imm32
14010       74/jump-if-= break/disp8
14011       # eax = lookup(curr->value)
14012       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14013       # if (eax == v  &&  curr->is-deref? == false) return true
14014       {
14015         39/compare *(ebp+0xc) 0/r32/eax
14016         75/jump-if-!= break/disp8
14017         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
14018         75/jump-if-!= break/disp8
14019         b8/copy-to-eax 1/imm32/true
14020         eb/jump $assigns-in-stmt-vars?:end/disp8
14021       }
14022       # curr = lookup(curr->next)
14023       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
14024       89/<- %ecx 0/r32/eax
14025       #
14026       eb/jump loop/disp8
14027     }
14028 $assigns-in-stmt-vars?:end:
14029     # . restore registers
14030     59/pop-to-ecx
14031     # . epilogue
14032     89/<- %esp 5/r32/ebp
14033     5d/pop-to-ebp
14034     c3/return
14035 
14036 # is there a var before 'v' with the same block-depth and register on the 'vars' stack?
14037 # v is guaranteed to be within vars
14038 # 'start' is provided as an optimization, a pointer within vars
14039 # *start == v
14040 same-register-spilled-before?:  # v: (addr var), vars: (addr stack (handle var)), start: (addr var) -> result/eax: boolean
14041     # . prologue
14042     55/push-ebp
14043     89/<- %ebp 4/r32/esp
14044     # . save registers
14045     51/push-ecx
14046     52/push-edx
14047     53/push-ebx
14048     56/push-esi
14049     57/push-edi
14050     # ecx = v
14051     8b/-> *(ebp+8) 1/r32/ecx
14052     # var reg/edx: (addr array byte) = lookup(v->register)
14053     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
14054     89/<- %edx 0/r32/eax
14055     # var depth/ebx: int = v->block-depth
14056     8b/-> *(ecx+0x10) 3/r32/ebx  # Var-block-depth
14057     # var min/ecx: (addr handle var) = vars->data
14058     8b/-> *(ebp+0xc) 1/r32/ecx
14059     81 0/subop/add %ecx 8/imm32
14060     # TODO: check that start >= min and start < &vars->data[top]
14061     # TODO: check that *start == v
14062     # var curr/esi: (addr handle var) = start
14063     8b/-> *(ebp+0x10) 6/r32/esi
14064     # curr -= 8
14065     81 5/subop/subtract %esi 8/imm32
14066     {
14067 $same-register-spilled-before?:loop:
14068       # if (curr < min) break
14069       39/compare %esi 1/r32/ecx
14070       0f 82/jump-if-addr< break/disp32
14071       # var x/eax: (addr var) = lookup(*curr)
14072       (lookup *esi *(esi+4))  # => eax
14073       # if (x->block-depth < depth) break
14074       39/compare *(eax+0x10) 3/r32/ebx  # Var-block-depth
14075       0f 8c/jump-if-< break/disp32
14076       # if (x->register == 0) continue
14077       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
14078       74/jump-if-= $same-register-spilled-before?:continue/disp8
14079       # if (x->register == reg) return true
14080       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
14081       (string-equal? %eax %edx)  # => eax
14082       3d/compare-eax-and 0/imm32/false
14083       b8/copy-to-eax 1/imm32/true
14084       75/jump-if-!= $same-register-spilled-before?:end/disp8
14085 $same-register-spilled-before?:continue:
14086       # curr -= 8
14087       81 5/subop/subtract %esi 8/imm32
14088       e9/jump loop/disp32
14089     }
14090 $same-register-spilled-before?:false:
14091     b8/copy-to-eax 0/imm32/false
14092 $same-register-spilled-before?:end:
14093     # . restore registers
14094     5f/pop-to-edi
14095     5e/pop-to-esi
14096     5b/pop-to-ebx
14097     5a/pop-to-edx
14098     59/pop-to-ecx
14099     # . epilogue
14100     89/<- %esp 5/r32/ebp
14101     5d/pop-to-ebp
14102     c3/return
14103 
14104 # Clean up global state for 'vars' until some block depth (inclusive).
14105 #
14106 # This would be a simple series of pops, if it wasn't for fn outputs, which
14107 # can occur anywhere in the stack.
14108 # So we have to _compact_ the entire array underlying the stack.
14109 #
14110 # We want to allow a fn output register to be written to by locals before the
14111 # output is set.
14112 # So fn outputs can't just be pushed at the start of the function.
14113 #
14114 # We want to allow other locals to shadow a fn output register after the
14115 # output is set.
14116 # So the output can't just always override anything in the stack. Sequence matters.
14117 clean-up-blocks:  # vars: (addr stack live-var), until-block-depth: int, fn: (addr function)
14118     # pseudocode:
14119     #   to = vars->top  (which points outside the stack)
14120     #   while true
14121     #     if to <= 0
14122     #       break
14123     #     var v = vars->data[to-1]
14124     #     if v.depth < until and !in-function-outputs?(fn, v)
14125     #       break
14126     #     --to
14127     #   from = to
14128     #   while true
14129     #     if from >= vars->top
14130     #       break
14131     #     assert(from >= to)
14132     #     v = vars->data[from]
14133     #     if in-function-outputs?(fn, v)
14134     #       if from > to
14135     #         vars->data[to] = vars->data[from]
14136     #       ++to
14137     #     ++from
14138     #   vars->top = to
14139     #
14140     # . prologue
14141     55/push-ebp
14142     89/<- %ebp 4/r32/esp
14143     # . save registers
14144     50/push-eax
14145     52/push-edx
14146     53/push-ebx
14147     56/push-esi
14148     57/push-edi
14149     # ebx = vars
14150     8b/-> *(ebp+8) 3/r32/ebx
14151     # edx = until-block-depth
14152     8b/-> *(ebp+0xc) 2/r32/edx
14153 $clean-up-blocks:phase1:
14154     # var to/edi: int = vars->top
14155     8b/-> *ebx 7/r32/edi
14156     {
14157 $clean-up-blocks:loop1:
14158       # if (to <= 0) break
14159       81 7/subop/compare %edi 0/imm32
14160       7e/jump-if-<= break/disp8
14161       # var v/eax: (addr var) = lookup(vars->data[to-1]->var)
14162       8d/copy-address *(ebx+edi-4) 0/r32/eax  # vars + 8 + to - 12
14163       (lookup *eax *(eax+4))  # => eax
14164       # if (v->block-depth >= until-block-depth) continue
14165       39/compare *(eax+0x10) 2/r32/edx  # Var-block-depth
14166       {
14167         7d/jump-if->= break/disp8
14168         # if (!in-function-outputs?(fn, v)) break
14169         (in-function-outputs? *(ebp+0x10) %eax)  # => eax
14170         3d/compare-eax-and 0/imm32/false
14171         74/jump-if-= $clean-up-blocks:phase2/disp8
14172       }
14173 $clean-up-blocks:loop1-continue:
14174       # --to
14175       81 5/subop/subtract %edi 0xc/imm32
14176       #
14177       eb/jump loop/disp8
14178     }
14179 $clean-up-blocks:phase2:
14180     # var from/esi: int = to
14181     89/<- %esi 7/r32/edi
14182     {
14183 $clean-up-blocks:loop2:
14184       # if (from >= vars->top) break
14185       3b/compare 6/r32/esi *ebx
14186       7d/jump-if->= break/disp8
14187       # var v/eax: (addr var) = lookup(vars->data[from]->var)
14188       8d/copy-address *(ebx+esi+8) 0/r32/eax
14189       (lookup *eax *(eax+4))  # => eax
14190       # if !in-function-outputs?(fn, v) continue
14191       (in-function-outputs? *(ebp+0x10) %eax)  # => eax
14192       3d/compare-eax-and 0/imm32/false
14193       74/jump-if-= $clean-up-blocks:loop2-continue/disp8
14194       # invariant: from >= to
14195       # if (from > to) vars->data[to] = vars->data[from]
14196       {
14197         39/compare %esi 7/r32/edi
14198         7e/jump-if-<= break/disp8
14199         56/push-esi
14200         57/push-edi
14201         # . var from/esi: (addr byte) = &vars->data[from]
14202         8d/copy-address *(ebx+esi+8) 6/r32/esi
14203         # . var to/edi: (addr byte) = &vars->data[to]
14204         8d/copy-address *(ebx+edi+8) 7/r32/edi
14205         # .
14206         8b/-> *esi 0/r32/eax
14207         89/<- *edi 0/r32/eax
14208         8b/-> *(esi+4) 0/r32/eax
14209         89/<- *(edi+4) 0/r32/eax
14210         8b/-> *(esi+8) 0/r32/eax
14211         89/<- *(edi+8) 0/r32/eax
14212         5f/pop-to-edi
14213         5e/pop-to-esi
14214       }
14215       # ++to
14216       81 0/subop/add %edi 0xc/imm32
14217 $clean-up-blocks:loop2-continue:
14218       # ++from
14219       81 0/subop/add %esi 0xc/imm32
14220       #
14221       eb/jump loop/disp8
14222     }
14223     89/<- *ebx 7/r32/edi
14224 $clean-up-blocks:end:
14225     # . restore registers
14226     5f/pop-to-edi
14227     5e/pop-to-esi
14228     5b/pop-to-ebx
14229     5a/pop-to-edx
14230     58/pop-to-eax
14231     # . epilogue
14232     89/<- %esp 5/r32/ebp
14233     5d/pop-to-ebp
14234     c3/return
14235 
14236 in-function-outputs?:  # fn: (addr function), target: (addr var) -> result/eax: boolean
14237     # . prologue
14238     55/push-ebp
14239     89/<- %ebp 4/r32/esp
14240     # . save registers
14241     51/push-ecx
14242     # var curr/ecx: (addr list var) = lookup(fn->outputs)
14243     8b/-> *(ebp+8) 1/r32/ecx
14244     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
14245     89/<- %ecx 0/r32/eax
14246     # while curr != null
14247     {
14248       81 7/subop/compare %ecx 0/imm32
14249       74/jump-if-= break/disp8
14250       # var v/eax: (addr var) = lookup(curr->value)
14251       (lookup *ecx *(ecx+4))  # List-value List-value => eax
14252       # if (v == target) return true
14253       39/compare *(ebp+0xc) 0/r32/eax
14254       b8/copy-to-eax 1/imm32/true
14255       74/jump-if-= $in-function-outputs?:end/disp8
14256       # curr = curr->next
14257       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
14258       89/<- %ecx 0/r32/eax
14259       #
14260       eb/jump loop/disp8
14261     }
14262     b8/copy-to-eax 0/imm32
14263 $in-function-outputs?:end:
14264     # . restore registers
14265     59/pop-to-ecx
14266     # . epilogue
14267     89/<- %esp 5/r32/ebp
14268     5d/pop-to-ebp
14269     c3/return
14270 
14271 emit-subx-var-def:  # out: (addr buffered-file), stmt: (addr stmt)
14272     # . prologue
14273     55/push-ebp
14274     89/<- %ebp 4/r32/esp
14275     # . save registers
14276     50/push-eax
14277     51/push-ecx
14278     52/push-edx
14279     # eax = stmt
14280     8b/-> *(ebp+0xc) 0/r32/eax
14281     # var v/ecx: (addr var)
14282     (lookup *(eax+4) *(eax+8))  # Vardef-var Vardef-var => eax
14283     89/<- %ecx 0/r32/eax
14284     # v->block-depth = *Curr-block-depth
14285     8b/-> *Curr-block-depth 0/r32/eax
14286     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
14287     # var n/edx: int = size-of(stmt->var)
14288     (size-of %ecx)  # => eax
14289     89/<- %edx 0/r32/eax
14290     # *Curr-local-stack-offset -= n
14291     29/subtract-from *Curr-local-stack-offset 2/r32/edx
14292     # v->offset = *Curr-local-stack-offset
14293     8b/-> *Curr-local-stack-offset 0/r32/eax
14294     89/<- *(ecx+0x14) 0/r32/eax  # Var-offset
14295     # if v is an array, do something special
14296     {
14297       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
14298       (is-mu-array? %eax)  # => eax
14299       3d/compare-eax-and 0/imm32/false
14300       0f 84/jump-if-= break/disp32
14301       # var array-size-without-size/edx: int = n-4
14302       81 5/subop/subtract %edx 4/imm32
14303       (emit-indent *(ebp+8) *Curr-block-depth)
14304       (write-buffered *(ebp+8) "(push-n-zero-bytes ")
14305       (write-int32-hex-buffered *(ebp+8) %edx)
14306       (write-buffered *(ebp+8) ")\n")
14307       (emit-indent *(ebp+8) *Curr-block-depth)
14308       (write-buffered *(ebp+8) "68/push ")
14309       (write-int32-hex-buffered *(ebp+8) %edx)
14310       (write-buffered *(ebp+8) "/imm32\n")
14311       eb/jump $emit-subx-var-def:end/disp8
14312     }
14313     # while n > 0
14314     {
14315       81 7/subop/compare %edx 0/imm32
14316       7e/jump-if-<= break/disp8
14317       (emit-indent *(ebp+8) *Curr-block-depth)
14318       (write-buffered *(ebp+8) "68/push 0/imm32\n")
14319       # n -= 4
14320       81 5/subop/subtract %edx 4/imm32
14321       #
14322       eb/jump loop/disp8
14323     }
14324 $emit-subx-var-def:end:
14325     # . restore registers
14326     5a/pop-to-edx
14327     59/pop-to-ecx
14328     58/pop-to-eax
14329     # . epilogue
14330     89/<- %esp 5/r32/ebp
14331     5d/pop-to-ebp
14332     c3/return
14333 
14334 emit-subx-stmt:  # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
14335     # . prologue
14336     55/push-ebp
14337     89/<- %ebp 4/r32/esp
14338     # . save registers
14339     50/push-eax
14340     51/push-ecx
14341     # - some special-case primitives that don't actually use the 'primitives' data structure
14342     # var op/ecx: (addr array byte) = lookup(stmt->operation)
14343     8b/-> *(ebp+0xc) 1/r32/ecx
14344     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
14345     89/<- %ecx 0/r32/eax
14346     # array size
14347     {
14348       # if (!string-equal?(stmt->operation, "length")) break
14349       (string-equal? %ecx "length")  # => eax
14350       3d/compare-eax-and 0/imm32
14351       0f 84/jump-if-= break/disp32
14352       (translate-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14353       e9/jump $emit-subx-stmt:end/disp32
14354     }
14355     # index into array
14356     {
14357       # if (!string-equal?(stmt->operation, "index")) break
14358       (string-equal? %ecx "index")  # => eax
14359       3d/compare-eax-and 0/imm32
14360       0f 84/jump-if-= break/disp32
14361       (translate-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14362       e9/jump $emit-subx-stmt:end/disp32
14363     }
14364     # compute-offset for index into array
14365     {
14366       # if (!string-equal?(stmt->operation, "compute-offset")) break
14367       (string-equal? %ecx "compute-offset")  # => eax
14368       3d/compare-eax-and 0/imm32
14369       0f 84/jump-if-= break/disp32
14370       (translate-mu-compute-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14371       e9/jump $emit-subx-stmt:end/disp32
14372     }
14373     # get field from record
14374     {
14375       # if (!string-equal?(stmt->operation, "get")) break
14376       (string-equal? %ecx "get")  # => eax
14377       3d/compare-eax-and 0/imm32
14378       0f 84/jump-if-= break/disp32
14379       (translate-mu-get-stmt *(ebp+8) *(ebp+0xc))
14380       e9/jump $emit-subx-stmt:end/disp32
14381     }
14382     # allocate scalar
14383     {
14384       # if (!string-equal?(stmt->operation, "allocate")) break
14385       (string-equal? %ecx "allocate")  # => eax
14386       3d/compare-eax-and 0/imm32
14387       0f 84/jump-if-= break/disp32
14388       (translate-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14389       e9/jump $emit-subx-stmt:end/disp32
14390     }
14391     # allocate array
14392     {
14393       # if (!string-equal?(stmt->operation, "populate")) break
14394       (string-equal? %ecx "populate")  # => eax
14395       3d/compare-eax-and 0/imm32
14396       0f 84/jump-if-= break/disp32
14397       (translate-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14398       e9/jump $emit-subx-stmt:end/disp32
14399     }
14400     # - if stmt matches a primitive, emit it
14401     {
14402 $emit-subx-stmt:check-for-primitive:
14403       # var curr/eax: (addr primitive)
14404       (find-matching-primitive *(ebp+0x10) *(ebp+0xc))  # primitives, stmt => eax
14405       3d/compare-eax-and 0/imm32
14406       74/jump-if-= break/disp8
14407 $emit-subx-stmt:primitive:
14408       (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax)  # out, stmt, curr
14409       e9/jump $emit-subx-stmt:end/disp32
14410     }
14411     # - otherwise emit a call
14412     # TODO: type-checking
14413 $emit-subx-stmt:call:
14414     (emit-call *(ebp+8) *(ebp+0xc))
14415 $emit-subx-stmt:end:
14416     # . restore registers
14417     59/pop-to-ecx
14418     58/pop-to-eax
14419     # . epilogue
14420     89/<- %esp 5/r32/ebp
14421     5d/pop-to-ebp
14422     c3/return
14423 
14424 translate-mu-length-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
14425     # . prologue
14426     55/push-ebp
14427     89/<- %ebp 4/r32/esp
14428     # . save registers
14429     50/push-eax
14430     51/push-ecx
14431     52/push-edx
14432     53/push-ebx
14433     56/push-esi
14434     # esi = stmt
14435     8b/-> *(ebp+0xc) 6/r32/esi
14436     # var base/ebx: (addr var) = stmt->inouts[0]->value
14437     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
14438     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14439     89/<- %ebx 0/r32/eax
14440     # var elemsize/ecx: int = array-element-size(base)
14441     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
14442     89/<- %ecx 0/r32/eax
14443     # var outreg/edx: (addr array byte) = stmt->outputs[0]->value->register
14444     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
14445     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14446     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
14447     89/<- %edx 0/r32/eax
14448     # if elemsize == 1
14449     {
14450       81 7/subop/compare %ecx 1/imm32
14451       75/jump-if-!= break/disp8
14452 $translate-mu-length-stmt:size-1:
14453       (emit-save-size-to *(ebp+8) %ebx %edx)
14454       e9/jump $translate-mu-length-stmt:end/disp32
14455     }
14456     # if elemsize is a power of 2 less than 256
14457     {
14458       (power-of-2? %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
14459       3d/compare-eax-and 0/imm32/false
14460       74/jump-if-= break/disp8
14461       81 7/subop/compare %ecx 0xff/imm32
14462       7f/jump-if-> break/disp8
14463 $translate-mu-length-stmt:size-power-of-2:
14464       (emit-save-size-to *(ebp+8) %ebx %edx)
14465       (emit-divide-by-shift-right *(ebp+8) %edx %ecx)
14466       e9/jump $translate-mu-length-stmt:end/disp32
14467     }
14468     # otherwise, the complex case
14469     # . emit register spills
14470     {
14471 $translate-mu-length-stmt:complex:
14472       (string-equal? %edx "eax")  # => eax
14473       3d/compare-eax-and 0/imm32/false
14474       75/break-if-!= break/disp8
14475       (emit-indent *(ebp+8) *Curr-block-depth)
14476       (write-buffered *(ebp+8) "50/push-eax\n")
14477     }
14478     {
14479       (string-equal? %edx "ecx")  # => eax
14480       3d/compare-eax-and 0/imm32/false
14481       75/break-if-!= break/disp8
14482       (emit-indent *(ebp+8) *Curr-block-depth)
14483       (write-buffered *(ebp+8) "51/push-ecx\n")
14484     }
14485     {
14486       (string-equal? %edx "edx")  # => eax
14487       3d/compare-eax-and 0/imm32/false
14488       75/break-if-!= break/disp8
14489       (emit-indent *(ebp+8) *Curr-block-depth)
14490       (write-buffered *(ebp+8) "52/push-edx\n")
14491     }
14492     # .
14493     (emit-save-size-to *(ebp+8) %ebx "eax")
14494     (emit-indent *(ebp+8) *Curr-block-depth)
14495     (write-buffered *(ebp+8) "31/xor %edx 2/r32/edx\n")
14496     (emit-indent *(ebp+8) *Curr-block-depth)
14497     (write-buffered *(ebp+8) "b9/copy-to-ecx ")
14498     (write-int32-hex-buffered *(ebp+8) %ecx)
14499     (write-buffered *(ebp+8) "/imm32\n")
14500     (emit-indent *(ebp+8) *Curr-block-depth)
14501     (write-buffered *(ebp+8) "f7 7/subop/idiv-eax-edx-by %ecx\n")
14502     {
14503       (string-equal? %edx "eax")  # => eax
14504       3d/compare-eax-and 0/imm32/false
14505       75/break-if-!= break/disp8
14506       (emit-indent *(ebp+8) *Curr-block-depth)
14507       (write-buffered *(ebp+8) "89/<- %")
14508       (write-buffered *(ebp+8) %edx)
14509       (write-buffered *(ebp+8) " 0/r32/eax\n")
14510     }
14511     # . emit register restores
14512     {
14513       (string-equal? %edx "edx")  # => eax
14514       3d/compare-eax-and 0/imm32/false
14515       75/break-if-!= break/disp8
14516       (emit-indent *(ebp+8) *Curr-block-depth)
14517       (write-buffered *(ebp+8) "5a/pop-to-edx\n")
14518     }
14519     {
14520       (string-equal? %edx "ecx")  # => eax
14521       3d/compare-eax-and 0/imm32/false
14522       75/break-if-!= break/disp8
14523       (emit-indent *(ebp+8) *Curr-block-depth)
14524       (write-buffered *(ebp+8) "59/pop-to-ecx\n")
14525     }
14526     {
14527       (string-equal? %edx "eax")  # => eax
14528       3d/compare-eax-and 0/imm32/false
14529       75/break-if-!= break/disp8
14530       (emit-indent *(ebp+8) *Curr-block-depth)
14531       (write-buffered *(ebp+8) "58/pop-to-eax\n")
14532     }
14533 $translate-mu-length-stmt:end:
14534     # . restore registers
14535     5e/pop-to-esi
14536     5b/pop-to-ebx
14537     5a/pop-to-edx
14538     59/pop-to-ecx
14539     58/pop-to-eax
14540     # . epilogue
14541     89/<- %esp 5/r32/ebp
14542     5d/pop-to-ebp
14543     c3/return
14544 
14545 array-element-size:  # arr: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
14546     # . prologue
14547     55/push-ebp
14548     89/<- %ebp 4/r32/esp
14549     #
14550     (array-element-type-id *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
14551     (size-of-type-id-as-array-element %eax)  # => eax
14552 $array-element-size:end:
14553     # . epilogue
14554     89/<- %esp 5/r32/ebp
14555     5d/pop-to-ebp
14556     c3/return
14557 
14558 array-element-type-id:  # v: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: type-id
14559     # precondition: n is positive
14560     # . prologue
14561     55/push-ebp
14562     89/<- %ebp 4/r32/esp
14563     #
14564     8b/-> *(ebp+8) 0/r32/eax
14565     # var t/eax: (addr type-tree)
14566     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
14567     # if t == 0 abort
14568     3d/compare-eax-with 0/imm32
14569     0f 84/jump-if-== $array-element-type-id:error0/disp32
14570     # if t->is-atom? abort
14571     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14572     0f 85/jump-if-!= $array-element-type-id:error1/disp32
14573     # if (t->left == addr) t = t->right
14574     {
14575       50/push-eax
14576       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14577       (is-simple-mu-type? %eax 2)  # addr => eax
14578       3d/compare-eax-with 0/imm32/false
14579       58/pop-to-eax
14580       74/jump-if-= break/disp8
14581 $array-element-type-id:skip-addr:
14582       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
14583     }
14584     # if t == 0 abort
14585     3d/compare-eax-with 0/imm32
14586     0f 84/jump-if-= $array-element-type-id:error2/disp32
14587     # if t->is-atom? abort
14588     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14589     0f 85/jump-if-!= $array-element-type-id:error2/disp32
14590     # if t->left != array abort
14591     {
14592       50/push-eax
14593       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14594       (is-simple-mu-type? %eax 3)  # array => eax
14595       3d/compare-eax-with 0/imm32/false
14596       58/pop-to-eax
14597 $array-element-type-id:no-array:
14598       0f 84/jump-if-= $array-element-type-id:error2/disp32
14599     }
14600 $array-element-type-id:skip-array:
14601     # t = t->right
14602     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
14603     # if t == 0 abort
14604     3d/compare-eax-with 0/imm32
14605     0f 84/jump-if-= $array-element-type-id:error2/disp32
14606     # if t->is-atom? abort
14607     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14608     0f 85/jump-if-!= $array-element-type-id:error2/disp32
14609     # return t->left->value
14610     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14611     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
14612 $array-element-type-id:end:
14613     # . epilogue
14614     89/<- %esp 5/r32/ebp
14615     5d/pop-to-ebp
14616     c3/return
14617 
14618 $array-element-type-id:error0:
14619     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
14620     50/push-eax
14621     8b/-> *(ebp+8) 0/r32/eax
14622     (lookup *eax *(eax+4))  # Var-name Var-name => eax
14623     (write-buffered *(ebp+0xc) %eax)
14624     58/pop-to-eax
14625     (write-buffered *(ebp+0xc) "' has no type\n")
14626     (flush *(ebp+0xc))
14627     (stop *(ebp+0x10) 1)
14628     # never gets here
14629 
14630 $array-element-type-id:error1:
14631     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
14632     50/push-eax
14633     8b/-> *(ebp+8) 0/r32/eax
14634     (lookup *eax *(eax+4))  # Var-name Var-name => eax
14635     (write-buffered *(ebp+0xc) %eax)
14636     58/pop-to-eax
14637     (write-buffered *(ebp+0xc) "' has atomic type ")
14638     (write-int32-hex-buffered *(ebp+0xc) *(eax+4))  # Type-tree-value
14639     (write-buffered *(ebp+0xc) Newline)
14640     (flush *(ebp+0xc))
14641     (stop *(ebp+0x10) 1)
14642     # never gets here
14643 
14644 $array-element-type-id:error2:
14645     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
14646     50/push-eax
14647     8b/-> *(ebp+8) 0/r32/eax
14648     (lookup *eax *(eax+4))  # Var-name Var-name => eax
14649     (write-buffered *(ebp+0xc) %eax)
14650     58/pop-to-eax
14651     (write-buffered *(ebp+0xc) "' has non-array type\n")
14652     (flush *(ebp+0xc))
14653     (stop *(ebp+0x10) 1)
14654     # never gets here
14655 
14656 size-of-type-id-as-array-element:  # t: type-id -> result/eax: int
14657     # . prologue
14658     55/push-ebp
14659     89/<- %ebp 4/r32/esp
14660     # eax = t
14661     8b/-> *(ebp+8) 0/r32/eax
14662     # if t is 'byte', size is 1
14663     3d/compare-eax-and 8/imm32/byte
14664     {
14665       75/jump-if-!= break/disp8
14666       b8/copy-to-eax 1/imm32
14667       eb/jump $size-of-type-id-as-array-element:end/disp8
14668     }
14669     # otherwise proceed as usual
14670     (size-of-type-id %eax)  # => eax
14671 $size-of-type-id-as-array-element:end:
14672     # . epilogue
14673     89/<- %esp 5/r32/ebp
14674     5d/pop-to-ebp
14675     c3/return
14676 
14677 emit-save-size-to:  # out: (addr buffered-file), base: (addr var), outreg: (addr array byte)
14678     # . prologue
14679     55/push-ebp
14680     89/<- %ebp 4/r32/esp
14681     # . save registers
14682     50/push-eax
14683     53/push-ebx
14684     # ebx = base
14685     8b/-> *(ebp+0xc) 3/r32/ebx
14686     (emit-indent *(ebp+8) *Curr-block-depth)
14687     (write-buffered *(ebp+8) "8b/-> *")
14688     # if base is an (addr array ...) in a register
14689     {
14690       81 7/subop/compare *(ebx+0x18)) 0/imm32  # Var-register
14691       74/jump-if-= break/disp8
14692 $emit-save-size-to:emit-base-from-register:
14693       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
14694       (write-buffered *(ebp+8) %eax)
14695       eb/jump $emit-save-size-to:emit-output/disp8
14696     }
14697     # otherwise if base is an (array ...) on the stack
14698     {
14699       81 7/subop/compare *(ebx+0x14)) 0/imm32  # Var-offset
14700       74/jump-if-= break/disp8
14701 $emit-save-size-to:emit-base-from-stack:
14702       (write-buffered *(ebp+8) "(ebp+")
14703       (write-int32-hex-buffered *(ebp+8) *(ebx+0x14))  # Var-offset
14704       (write-buffered *(ebp+8) ")")
14705     }
14706 $emit-save-size-to:emit-output:
14707     (write-buffered *(ebp+8) " ")
14708     (get Mu-registers *(ebp+0x10) 0xc "Mu-registers")  # => eax
14709     (write-int32-hex-buffered *(ebp+8) *eax)
14710     (write-buffered *(ebp+8) "/r32\n")
14711 $emit-save-size-to:end:
14712     # . restore registers
14713     5b/pop-to-ebx
14714     58/pop-to-eax
14715     # . epilogue
14716     89/<- %esp 5/r32/ebp
14717     5d/pop-to-ebp
14718     c3/return
14719 
14720 emit-divide-by-shift-right:  # out: (addr buffered-file), reg: (addr array byte), size: int
14721     # . prologue
14722     55/push-ebp
14723     89/<- %ebp 4/r32/esp
14724     # . save registers
14725     50/push-eax
14726     #
14727     (emit-indent *(ebp+8) *Curr-block-depth)
14728     (write-buffered *(ebp+8) "c1/shift 5/subop/>> %")
14729     (write-buffered *(ebp+8) *(ebp+0xc))
14730     (write-buffered *(ebp+8) Space)
14731     (num-shift-rights *(ebp+0x10))  # => eax
14732     (write-int32-hex-buffered *(ebp+8) %eax)
14733     (write-buffered *(ebp+8) "/imm8\n")
14734 $emit-divide-by-shift-right:end:
14735     # . restore registers
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-index-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     51/push-ecx
14748     # ecx = stmt
14749     8b/-> *(ebp+0xc) 1/r32/ecx
14750     # var base/ecx: (addr var) = stmt->inouts[0]
14751     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
14752     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14753     89/<- %ecx 0/r32/eax
14754     # if (var->register) do one thing
14755     {
14756       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
14757       74/jump-if-= break/disp8
14758       # TODO: ensure there's no dereference
14759       (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
14760       eb/jump $translate-mu-index-stmt:end/disp8
14761     }
14762     # if (var->offset) do a different thing
14763     {
14764       81 7/subop/compare *(ecx+0x14) 0/imm32  # Var-offset
14765       74/jump-if-= break/disp8
14766       # TODO: ensure there's no dereference
14767       (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
14768       eb/jump $translate-mu-index-stmt:end/disp8
14769     }
14770 $translate-mu-index-stmt:end:
14771     # . restore registers
14772     59/pop-to-ecx
14773     # . epilogue
14774     89/<- %esp 5/r32/ebp
14775     5d/pop-to-ebp
14776     c3/return
14777 
14778 $translate-mu-index-stmt-with-array:error1:
14779     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
14780     (flush *(ebp+0x10))
14781     (stop *(ebp+0x14) 1)
14782     # never gets here
14783 
14784 $translate-mu-index-stmt-with-array:error2:
14785     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
14786     (flush *(ebp+0x10))
14787     (stop *(ebp+0x14) 1)
14788     # never gets here
14789 
14790 translate-mu-index-stmt-with-array-in-register:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
14791     # . prologue
14792     55/push-ebp
14793     89/<- %ebp 4/r32/esp
14794     # . save registers
14795     50/push-eax
14796     51/push-ecx
14797     52/push-edx
14798     53/push-ebx
14799     #
14800     (emit-indent *(ebp+8) *Curr-block-depth)
14801     (write-buffered *(ebp+8) "8d/copy-address *(")
14802     # TODO: ensure inouts[0] is in a register and not dereferenced
14803 $translate-mu-index-stmt-with-array-in-register:emit-base:
14804     # ecx = stmt
14805     8b/-> *(ebp+0xc) 1/r32/ecx
14806     # var base/ebx: (addr var) = inouts[0]
14807     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
14808     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14809     89/<- %ebx 0/r32/eax
14810     # print base->register " + "
14811     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
14812     (write-buffered *(ebp+8) %eax)
14813     (write-buffered *(ebp+8) " + ")
14814     # var index/edx: (addr var) = inouts[1]
14815     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
14816     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
14817     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14818     89/<- %edx 0/r32/eax
14819     # if index->register
14820     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
14821     {
14822       0f 84/jump-if-= break/disp32
14823 $translate-mu-index-stmt-with-array-in-register:emit-register-index:
14824       # if index is an int
14825       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
14826       (is-simple-mu-type? %eax 1)  # int => eax
14827       3d/compare-eax-and 0/imm32/false
14828       {
14829         0f 84/jump-if-= break/disp32
14830 $translate-mu-index-stmt-with-array-in-register:emit-int-register-index:
14831         # print index->register "<<" log2(array-element-size(base)) " + 4) "
14832         # . index->register "<<"
14833         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
14834         (write-buffered *(ebp+8) %eax)
14835         (write-buffered *(ebp+8) "<<")
14836         # . log2(array-element-size(base->type))
14837         # TODO: ensure size is a power of 2
14838         (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
14839         (num-shift-rights %eax)  # => eax
14840         (write-int32-hex-buffered *(ebp+8) %eax)
14841         e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32
14842       }
14843       # if index->type is any other atom, abort
14844       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
14845       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14846       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
14847       # if index has type (offset ...)
14848       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14849       (is-simple-mu-type? %eax 7)  # => eax
14850       3d/compare-eax-and 0/imm32/false
14851       {
14852         0f 84/jump-if-= break/disp32
14853         # print index->register
14854 $translate-mu-index-stmt-with-array-in-register:emit-offset-register-index:
14855         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
14856         (write-buffered *(ebp+8) %eax)
14857       }
14858 $translate-mu-index-stmt-with-array-in-register:emit-register-index-done:
14859       (write-buffered *(ebp+8) " + 4) ")
14860       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
14861     }
14862     # otherwise if index is a literal
14863     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
14864     (is-simple-mu-type? %eax 0)  # => eax
14865     3d/compare-eax-and 0/imm32/false
14866     {
14867       0f 84/jump-if-= break/disp32
14868 $translate-mu-index-stmt-with-array-in-register:emit-literal-index:
14869       # var index-value/edx: int = parse-hex-int(index->name)
14870       (lookup *edx *(edx+4))  # Var-name Var-name => eax
14871       (parse-hex-int %eax)  # => eax
14872       89/<- %edx 0/r32/eax
14873       # offset = idx-value * array-element-size(base->type)
14874       (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
14875       f7 4/subop/multiply-into-eax %edx  # clobbers edx
14876       # offset += 4 for array size
14877       05/add-to-eax 4/imm32
14878       # TODO: check edx for overflow
14879       # print offset
14880       (write-int32-hex-buffered *(ebp+8) %eax)
14881       (write-buffered *(ebp+8) ") ")
14882       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
14883     }
14884     # otherwise abort
14885     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
14886 $translate-mu-index-stmt-with-array-in-register:emit-output:
14887     # outputs[0] "/r32"
14888     8b/-> *(ebp+0xc) 1/r32/ecx
14889     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
14890     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14891     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
14892     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
14893     (write-int32-hex-buffered *(ebp+8) *eax)
14894     (write-buffered *(ebp+8) "/r32\n")
14895 $translate-mu-index-stmt-with-array-in-register:end:
14896     # . restore registers
14897     5b/pop-to-ebx
14898     5a/pop-to-edx
14899     59/pop-to-ecx
14900     58/pop-to-eax
14901     # . epilogue
14902     89/<- %esp 5/r32/ebp
14903     5d/pop-to-ebp
14904     c3/return
14905 
14906 translate-mu-index-stmt-with-array-on-stack:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
14907     # . prologue
14908     55/push-ebp
14909     89/<- %ebp 4/r32/esp
14910     # . save registers
14911     50/push-eax
14912     51/push-ecx
14913     52/push-edx
14914     53/push-ebx
14915     #
14916     (emit-indent *(ebp+8) *Curr-block-depth)
14917     (write-buffered *(ebp+8) "8d/copy-address *(ebp + ")
14918     # var curr/edx: (addr stmt-var) = lookup(stmt->inouts)
14919     8b/-> *(ebp+0xc) 0/r32/eax
14920     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
14921     89/<- %edx 0/r32/eax
14922     # var base/ecx: (addr var) = lookup(curr->value)
14923     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14924     89/<- %ecx 0/r32/eax
14925     # var curr2/eax: (addr stmt-var) = lookup(curr->next)
14926     (lookup *(edx+8) *(edx+0xc))  # Stmt-var-next Stmt-var-next => eax
14927     # var index/edx: (handle var) = curr2->value
14928     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14929     89/<- %edx 0/r32/eax
14930     # if index->register
14931     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
14932     {
14933       0f 84/jump-if-= break/disp32
14934 $translate-mu-index-stmt-with-array-on-stack:emit-register-index:
14935       # if index is an int
14936       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
14937       (is-simple-mu-type? %eax 1)  # int => eax
14938       3d/compare-eax-and 0/imm32/false
14939       {
14940         0f 84/jump-if-= break/disp32
14941 $translate-mu-index-stmt-with-array-on-stack:emit-int-register-index:
14942         # print index->register "<<" log2(array-element-size(base)) " + " base->offset+4
14943         # . inouts[1]->register "<<"
14944         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
14945         (write-buffered *(ebp+8) %eax)
14946         (write-buffered *(ebp+8) "<<")
14947         # . log2(array-element-size(base))
14948         # TODO: ensure size is a power of 2
14949         (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
14950         (num-shift-rights %eax)  # => eax
14951         (write-int32-hex-buffered *(ebp+8) %eax)
14952         #
14953         (write-buffered *(ebp+8) " + ")
14954         #
14955         8b/-> *(ecx+0x14) 0/r32/eax  # Var-offset
14956         05/add-to-eax 4/imm32  # for array length
14957         (write-int32-hex-buffered *(ebp+8) %eax)
14958         e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32
14959       }
14960       # if index->type is any other atom, abort
14961       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
14962       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14963       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
14964       # if index has type (offset ...)
14965       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14966       (is-simple-mu-type? %eax 7)  # => eax
14967       3d/compare-eax-and 0/imm32/false
14968       {
14969         0f 84/jump-if-= break/disp32
14970         # print index->register
14971 $translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index:
14972         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
14973         (write-buffered *(ebp+8) %eax)
14974       }
14975 $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done:
14976       (write-buffered *(ebp+8) ") ")
14977       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
14978     }
14979     # otherwise if index is a literal
14980     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
14981     (is-simple-mu-type? %eax 0)  # => eax
14982     3d/compare-eax-and 0/imm32/false
14983     {
14984       0f 84/jump-if-= break/disp32
14985 $translate-mu-index-stmt-with-array-on-stack:emit-literal-index:
14986       # var idx-value/edx: int = parse-hex-int(index->name)
14987       (lookup *edx *(edx+4))  # Var-name Var-name => eax
14988       (parse-hex-int %eax)  # Var-name => eax
14989       89/<- %edx 0/r32/eax
14990       # offset = idx-value * array-element-size(base)
14991       (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
14992       f7 4/subop/multiply-into-eax %edx  # clobbers edx
14993       # offset += base->offset
14994       03/add *(ecx+0x14) 0/r32/eax  # Var-offset
14995       # offset += 4 for array size
14996       05/add-to-eax 4/imm32
14997       # TODO: check edx for overflow
14998       # print offset
14999       (write-int32-hex-buffered *(ebp+8) %eax)
15000       (write-buffered *(ebp+8) ") ")
15001       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
15002     }
15003     # otherwise abort
15004     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
15005 $translate-mu-index-stmt-with-array-on-stack:emit-output:
15006     # outputs[0] "/r32"
15007     8b/-> *(ebp+0xc) 0/r32/eax
15008     (lookup *(eax+0x14) *(eax+0x18))  # Stmt1-outputs Stmt1-outputs => eax
15009     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15010     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15011     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
15012     (write-int32-hex-buffered *(ebp+8) *eax)
15013     (write-buffered *(ebp+8) "/r32\n")
15014 $translate-mu-index-stmt-with-array-on-stack:end:
15015     # . restore registers
15016     5b/pop-to-ebx
15017     5a/pop-to-edx
15018     59/pop-to-ecx
15019     58/pop-to-eax
15020     # . epilogue
15021     89/<- %esp 5/r32/ebp
15022     5d/pop-to-ebp
15023     c3/return
15024 
15025 translate-mu-compute-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15026     # . prologue
15027     55/push-ebp
15028     89/<- %ebp 4/r32/esp
15029     # . save registers
15030     50/push-eax
15031     51/push-ecx
15032     52/push-edx
15033     53/push-ebx
15034     #
15035     (emit-indent *(ebp+8) *Curr-block-depth)
15036     (write-buffered *(ebp+8) "69/multiply")
15037     # ecx = stmt
15038     8b/-> *(ebp+0xc) 1/r32/ecx
15039     # var first-inout/ebx: (addr stmt-var) = stmt->inouts[0]
15040     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15041     89/<- %ebx 0/r32/eax
15042 $translate-mu-compute-index-stmt:emit-index:
15043     (lookup *(ebx+8) *(ebx+0xc))  # Stmt-var-next Stmt-var-next => eax
15044     (emit-subx-var-as-rm32 *(ebp+8) %eax)
15045     (write-buffered *(ebp+8) Space)
15046 $translate-mu-compute-index-stmt:emit-elem-size:
15047     # var base/ebx: (addr var)
15048     (lookup *ebx *(ebx+4))  # Stmt-var-value Stmt-var-value => eax
15049     89/<- %ebx 0/r32/eax
15050     # print array-element-size(base)
15051     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
15052     (write-int32-hex-buffered *(ebp+8) %eax)
15053     (write-buffered *(ebp+8) "/imm32 ")
15054 $translate-mu-compute-index-stmt:emit-output:
15055     # outputs[0] "/r32"
15056     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
15057     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15058     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15059     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
15060     (write-int32-hex-buffered *(ebp+8) *eax)
15061     (write-buffered *(ebp+8) "/r32\n")
15062 $translate-mu-compute-index-stmt:end:
15063     # . restore registers
15064     5b/pop-to-ebx
15065     5a/pop-to-edx
15066     59/pop-to-ecx
15067     58/pop-to-eax
15068     # . epilogue
15069     89/<- %esp 5/r32/ebp
15070     5d/pop-to-ebp
15071     c3/return
15072 
15073 translate-mu-get-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
15074     # . prologue
15075     55/push-ebp
15076     89/<- %ebp 4/r32/esp
15077     # . save registers
15078     50/push-eax
15079     51/push-ecx
15080     52/push-edx
15081     #
15082     (emit-indent *(ebp+8) *Curr-block-depth)
15083     (write-buffered *(ebp+8) "8d/copy-address ")
15084     # ecx = stmt
15085     8b/-> *(ebp+0xc) 1/r32/ecx
15086     # var offset/edx: int = get offset of stmt
15087     (mu-get-offset %ecx)  # => eax
15088     89/<- %edx 0/r32/eax
15089     # var base/eax: (addr var) = stmt->inouts->value
15090     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15091     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15092     # if base is in a register
15093     81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
15094     {
15095       0f 84/jump-if-= break/disp32
15096 $translate-mu-get-stmt:emit-register-input:
15097       # emit "*(" base->register " + " offset ") "
15098       (write-buffered *(ebp+8) "*(")
15099       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15100       (write-buffered *(ebp+8) %eax)
15101       (write-buffered *(ebp+8) " + ")
15102       (write-int32-hex-buffered *(ebp+8) %edx)
15103       (write-buffered *(ebp+8) ") ")
15104       e9/jump $translate-mu-get-stmt:emit-output/disp32
15105     }
15106     # otherwise base is on the stack
15107     {
15108 $translate-mu-get-stmt:emit-stack-input:
15109       # emit "*(ebp + " inouts[0]->stack-offset + offset ") "
15110       (write-buffered *(ebp+8) "*(ebp+")
15111       03/add *(eax+0x14) 2/r32/edx  # Var-offset
15112       (write-int32-hex-buffered *(ebp+8) %edx)
15113       (write-buffered *(ebp+8) ") ")
15114       eb/jump $translate-mu-get-stmt:emit-output/disp8
15115     }
15116 $translate-mu-get-stmt:emit-output:
15117     # var output/eax: (addr var) = stmt->outputs->value
15118     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
15119     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15120     # emit offset->register "/r32"
15121     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15122     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
15123     (write-int32-hex-buffered *(ebp+8) *eax)
15124     (write-buffered *(ebp+8) "/r32\n")
15125 $translate-mu-get-stmt:end:
15126     # . restore registers
15127     5a/pop-to-edx
15128     59/pop-to-ecx
15129     58/pop-to-eax
15130     # . epilogue
15131     89/<- %esp 5/r32/ebp
15132     5d/pop-to-ebp
15133     c3/return
15134 
15135 translate-mu-allocate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15136     # . prologue
15137     55/push-ebp
15138     89/<- %ebp 4/r32/esp
15139     # . save registers
15140     50/push-eax
15141     56/push-esi
15142     57/push-edi
15143     # esi = stmt
15144     8b/-> *(ebp+0xc) 6/r32/esi
15145     # var target/edi: (addr stmt-var) = stmt->inouts[0]
15146     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15147     89/<- %edi 0/r32/eax
15148     #
15149     (emit-indent *(ebp+8) *Curr-block-depth)
15150     (write-buffered *(ebp+8) "(allocate Heap ")
15151     (addr-handle-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
15152     (write-int32-hex-buffered *(ebp+8) %eax)
15153     (emit-subx-call-operand *(ebp+8) %edi)
15154     (write-buffered *(ebp+8) ")\n")
15155 $translate-mu-allocate-stmt:end:
15156     # . restore registers
15157     5f/pop-to-edi
15158     5e/pop-to-esi
15159     58/pop-to-eax
15160     # . epilogue
15161     89/<- %esp 5/r32/ebp
15162     5d/pop-to-ebp
15163     c3/return
15164 
15165 addr-handle-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
15166     # . prologue
15167     55/push-ebp
15168     89/<- %ebp 4/r32/esp
15169     # var t/eax: (addr type-tree) = s->value->type
15170     8b/-> *(ebp+8) 0/r32/eax
15171     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15172     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
15173     # TODO: check eax != 0
15174     # TODO: check !t->is-atom?
15175     # TODO: check t->left == addr
15176     # t = t->right
15177 $addr-handle-payload-size:skip-addr:
15178     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15179     # TODO: check eax != 0
15180     # TODO: check !t->is-atom?
15181     # TODO: check t->left == handle
15182     # t = t->right
15183 $addr-handle-payload-size:skip-handle:
15184     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15185     # TODO: check eax != 0
15186     # if !t->is-atom? t = t->left
15187     81 7/subop/compare *eax 0/imm32/false
15188     {
15189       75/jump-if-!= break/disp8
15190       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
15191     }
15192     # TODO: check t->is-atom?
15193     # return size(t->value)
15194     (size-of-type-id *(eax+4))  # Type-tree-value => eax
15195 $addr-handle-payload-size:end:
15196     # . epilogue
15197     89/<- %esp 5/r32/ebp
15198     5d/pop-to-ebp
15199     c3/return
15200 
15201 translate-mu-populate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15202     # . prologue
15203     55/push-ebp
15204     89/<- %ebp 4/r32/esp
15205     # . save registers
15206     50/push-eax
15207     51/push-ecx
15208     56/push-esi
15209     57/push-edi
15210     # esi = stmt
15211     8b/-> *(ebp+0xc) 6/r32/esi
15212     # var target/edi: (addr stmt-var) = stmt->inouts[0]
15213     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15214     89/<- %edi 0/r32/eax
15215     # var len/ecx: (addr stmt-var) = stmt->inouts[1]
15216     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
15217     89/<- %ecx 0/r32/eax
15218     #
15219     (emit-indent *(ebp+8) *Curr-block-depth)
15220     (write-buffered *(ebp+8) "(allocate-array2 Heap ")
15221     (addr-handle-array-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
15222     (write-int32-hex-buffered *(ebp+8) %eax)
15223     (emit-subx-call-operand *(ebp+8) %ecx)
15224     (emit-subx-call-operand *(ebp+8) %edi)
15225     (write-buffered *(ebp+8) ")\n")
15226 $translate-mu-populate-stmt:end:
15227     # . restore registers
15228     5f/pop-to-edi
15229     5e/pop-to-esi
15230     59/pop-to-ecx
15231     58/pop-to-eax
15232     # . epilogue
15233     89/<- %esp 5/r32/ebp
15234     5d/pop-to-ebp
15235     c3/return
15236 
15237 addr-handle-array-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
15238     # . prologue
15239     55/push-ebp
15240     89/<- %ebp 4/r32/esp
15241     # var t/eax: (addr type-tree) = s->value->type
15242     8b/-> *(ebp+8) 0/r32/eax
15243     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15244     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
15245     # TODO: check eax != 0
15246     # TODO: check !t->is-atom?
15247     # TODO: check t->left == addr
15248     # t = t->right
15249 $addr-handle-array-payload-size:skip-addr:
15250     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15251     # TODO: check eax != 0
15252     # TODO: check !t->is-atom?
15253     # TODO: check t->left == handle
15254     # t = t->right
15255 $addr-handle-array-payload-size:skip-handle:
15256     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15257     # TODO: check eax != 0
15258     # TODO: check !t->is-atom?
15259     # TODO: check t->left == array
15260     # t = t->right
15261 $addr-handle-array-payload-size:skip-array:
15262     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15263     # TODO: check eax != 0
15264     # if !t->is-atom? t = t->left
15265     81 7/subop/compare *eax 0/imm32/false
15266     {
15267       75/jump-if-!= break/disp8
15268       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
15269     }
15270 $addr-handle-array-payload-size:compute-size:
15271     # TODO: check t->is-atom?
15272     # return size(t->value)
15273     (size-of-type-id-as-array-element *(eax+4))  # Type-tree-value => eax
15274 $addr-handle-array-payload-size:end:
15275     # . epilogue
15276     89/<- %esp 5/r32/ebp
15277     5d/pop-to-ebp
15278     c3/return
15279 
15280 power-of-2?:  # n: int, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: boolean
15281     # precondition: n is positive
15282     # . prologue
15283     55/push-ebp
15284     89/<- %ebp 4/r32/esp
15285     # eax = n
15286     8b/-> *(ebp+8) 0/r32/eax
15287     # if (n < 0) abort
15288     3d/compare-eax-with 0/imm32
15289     0f 8c/jump-if-< $power-of-2?:abort/disp32
15290     # var tmp/eax: int = n-1
15291     48/decrement-eax
15292     # var tmp2/eax: int = n & tmp
15293     23/and-> *(ebp+8) 0/r32/eax
15294     # return (tmp2 == 0)
15295     3d/compare-eax-and 0/imm32
15296     0f 94/set-byte-if-= %al
15297     81 4/subop/and %eax 0xff/imm32
15298 $power-of-2?:end:
15299     # . epilogue
15300     89/<- %esp 5/r32/ebp
15301     5d/pop-to-ebp
15302     c3/return
15303 
15304 $power-of-2?:abort:
15305     (write-buffered *(ebp+0xc) "power-of-2?: negative number\n")
15306     (flush *(ebp+0xc))
15307     (stop *(ebp+0x10) 1)
15308     # never gets here
15309 
15310 num-shift-rights:  # n: int -> result/eax: int
15311     # precondition: n is a positive power of 2
15312     # . prologue
15313     55/push-ebp
15314     89/<- %ebp 4/r32/esp
15315     # . save registers
15316     51/push-ecx
15317     # var curr/ecx: int = n
15318     8b/-> *(ebp+8) 1/r32/ecx
15319     # result = 0
15320     b8/copy-to-eax 0/imm32
15321     {
15322       # if (curr <= 1) break
15323       81 7/subop/compare %ecx 1/imm32
15324       7e/jump-if-<= break/disp8
15325       40/increment-eax
15326       c1/shift 5/subop/arithmetic-right %ecx 1/imm8
15327       eb/jump loop/disp8
15328     }
15329 $num-shift-rights:end:
15330     # . restore registers
15331     59/pop-to-ecx
15332     # . epilogue
15333     89/<- %esp 5/r32/ebp
15334     5d/pop-to-ebp
15335     c3/return
15336 
15337 mu-get-offset:  # stmt: (addr stmt) -> result/eax: int
15338     # . prologue
15339     55/push-ebp
15340     89/<- %ebp 4/r32/esp
15341     # var second-inout/eax: (addr stmt-var) = stmt->inouts->next
15342     8b/-> *(ebp+8) 0/r32/eax
15343     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15344     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
15345     # var output-var/eax: (addr var) = second-inout->value
15346     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15347 #?     (write-buffered Stderr "mu-get-offset: ")
15348 #?     (write-int32-hex-buffered Stderr %eax)
15349 #?     (write-buffered Stderr " name: ")
15350 #?     50/push-eax
15351 #?     (lookup *eax *(eax+4))  # Var-name
15352 #?     (write-buffered Stderr %eax)
15353 #?     58/pop-to-eax
15354 #?     (write-buffered Stderr Newline)
15355 #?     (flush Stderr)
15356     # return output-var->stack-offset
15357     8b/-> *(eax+0x14) 0/r32/eax  # Var-offset
15358 #?     (write-buffered Stderr "=> ")
15359 #?     (write-int32-hex-buffered Stderr %eax)
15360 #?     (write-buffered Stderr Newline)
15361 #?     (flush Stderr)
15362 $emit-get-offset:end:
15363     # . epilogue
15364     89/<- %esp 5/r32/ebp
15365     5d/pop-to-ebp
15366     c3/return
15367 
15368 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)
15369     # . prologue
15370     55/push-ebp
15371     89/<- %ebp 4/r32/esp
15372     # . save registers
15373     50/push-eax
15374     51/push-ecx
15375     56/push-esi
15376     # esi = block
15377     8b/-> *(ebp+0xc) 6/r32/esi
15378     # block->var->block-depth = *Curr-block-depth
15379     (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
15380     8b/-> *Curr-block-depth 1/r32/ecx
15381     89/<- *(eax+0x10) 1/r32/ecx  # Var-block-depth
15382     # var stmts/eax: (addr list stmt) = lookup(block->statements)
15383     (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
15384     #
15385     {
15386 $emit-subx-block:check-empty:
15387       3d/compare-eax-and 0/imm32
15388       0f 84/jump-if-= break/disp32
15389       (emit-indent *(ebp+8) *Curr-block-depth)
15390       (write-buffered *(ebp+8) "{\n")
15391       # var v/ecx: (addr var) = lookup(block->var)
15392       (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
15393       89/<- %ecx 0/r32/eax
15394       #
15395       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
15396       (write-buffered *(ebp+8) %eax)
15397       (write-buffered *(ebp+8) ":loop:\n")
15398       ff 0/subop/increment *Curr-block-depth
15399       (push *(ebp+0x10) *(esi+0xc))  # Block-var
15400       (push *(ebp+0x10) *(esi+0x10))  # Block-var
15401       (push *(ebp+0x10) 0)  # false
15402       # emit block->statements
15403       (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
15404       (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
15405       (pop *(ebp+0x10))  # => eax
15406       (pop *(ebp+0x10))  # => eax
15407       (pop *(ebp+0x10))  # => eax
15408       ff 1/subop/decrement *Curr-block-depth
15409       (emit-indent *(ebp+8) *Curr-block-depth)
15410       (write-buffered *(ebp+8) "}\n")
15411       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
15412       (write-buffered *(ebp+8) %eax)
15413       (write-buffered *(ebp+8) ":break:\n")
15414     }
15415 $emit-subx-block:end:
15416     # . restore registers
15417     5e/pop-to-esi
15418     59/pop-to-ecx
15419     58/pop-to-eax
15420     # . epilogue
15421     89/<- %esp 5/r32/ebp
15422     5d/pop-to-ebp
15423     c3/return
15424 
15425 # Primitives supported
15426 # See mu_instructions for a summary of this linked-list data structure.
15427 #
15428 # For each operation, put variants with hard-coded registers before flexible ones.
15429 #
15430 # Unfortunately, our restrictions on addresses require that various fields in
15431 # primitives be handles, which complicates these definitions.
15432 #   - we need to insert dummy fields all over the place for fake alloc-ids
15433 #   - we can't use our syntax sugar of quoted literals for string fields
15434 #
15435 # Fake alloc-ids are needed because our type definitions up top require
15436 # handles but it's clearer to statically allocate these long-lived objects.
15437 # Fake alloc-ids are perfectly safe, but they can't be reclaimed.
15438 #
15439 # Every 'object' below starts with a fake alloc-id. It may also contain other
15440 # fake alloc-ids for various handle fields.
15441 #
15442 # I think of objects starting with a fake alloc-id as having type 'payload'.
15443 # It's not really intended to be created dynamically; for that use `allocate`
15444 # as usual.
15445 #
15446 # Idea for a notation to simplify such definitions:
15447 #   _Primitive-increment-eax:  # (payload primitive)
15448 #     0x11/alloc-id:fake:payload
15449 #     0x11 @(0x11 "increment")  # name
15450 #     0 0                       # inouts
15451 #     0x11 @(0x11/payload
15452 #            0x11 @(0x11/payload  # List-value
15453 #                   0 0             # Var-name
15454 #                   0x11 @(0x11     # Var-type
15455 #                          1/is-atom
15456 #                          1/value 0/unused   # Type-tree-left
15457 #                          0 0                # Type-tree-right
15458 #                         )
15459 #                   1               # block-depth
15460 #                   0               # stack-offset
15461 #                   0x11 @(0x11 "eax")  # Var-register
15462 #                  )
15463 #            0 0)                 # List-next
15464 #     ...
15465 #     _Primitive-increment-ecx/imm32/next
15466 #   ...
15467 # Awfully complex and non-obvious. But also clearly signals there's something
15468 # to learn here, so may be worth trying.
15469 #
15470 # '@' is just an initial thought. Punctuation used so far in Mu: () * % # / "
15471 #
15472 # For now we'll continue to just use comments and manually ensure they stay up
15473 # to date.
15474 == data
15475 Primitives:  # (addr primitive)
15476 # - increment/decrement
15477 _Primitive-increment-eax:  # (addr primitive)
15478     # var/eax <- increment => 40/increment-eax
15479     0x11/imm32/alloc-id:fake
15480     _string-increment/imm32/name
15481     0/imm32/no-inouts
15482     0/imm32/no-inouts
15483     0x11/imm32/alloc-id:fake
15484     Single-int-var-in-eax/imm32/outputs
15485     0x11/imm32/alloc-id:fake
15486     _string_40_increment_eax/imm32/subx-name
15487     0/imm32/no-rm32
15488     0/imm32/no-r32
15489     0/imm32/no-imm32
15490     0/imm32/no-imm8
15491     0/imm32/no-disp32
15492     0/imm32/output-is-write-only
15493     0x11/imm32/alloc-id:fake
15494     _Primitive-increment-ecx/imm32/next
15495 _Primitive-increment-ecx:  # (payload primitive)
15496     0x11/imm32/alloc-id:fake:payload
15497     # var/ecx <- increment => 41/increment-ecx
15498     0x11/imm32/alloc-id:fake
15499     _string-increment/imm32/name
15500     0/imm32/no-inouts
15501     0/imm32/no-inouts
15502     0x11/imm32/alloc-id:fake
15503     Single-int-var-in-ecx/imm32/outputs
15504     0x11/imm32/alloc-id:fake
15505     _string_41_increment_ecx/imm32/subx-name
15506     0/imm32/no-rm32
15507     0/imm32/no-r32
15508     0/imm32/no-imm32
15509     0/imm32/no-imm8
15510     0/imm32/no-disp32
15511     0/imm32/output-is-write-only
15512     0x11/imm32/alloc-id:fake
15513     _Primitive-increment-edx/imm32/next
15514 _Primitive-increment-edx:  # (payload primitive)
15515     0x11/imm32/alloc-id:fake:payload
15516     # var/edx <- increment => 42/increment-edx
15517     0x11/imm32/alloc-id:fake
15518     _string-increment/imm32/name
15519     0/imm32/no-inouts
15520     0/imm32/no-inouts
15521     0x11/imm32/alloc-id:fake
15522     Single-int-var-in-edx/imm32/outputs
15523     0x11/imm32/alloc-id:fake
15524     _string_42_increment_edx/imm32/subx-name
15525     0/imm32/no-rm32
15526     0/imm32/no-r32
15527     0/imm32/no-imm32
15528     0/imm32/no-imm8
15529     0/imm32/no-disp32
15530     0/imm32/output-is-write-only
15531     0x11/imm32/alloc-id:fake
15532     _Primitive-increment-ebx/imm32/next
15533 _Primitive-increment-ebx:  # (payload primitive)
15534     0x11/imm32/alloc-id:fake:payload
15535     # var/ebx <- increment => 43/increment-ebx
15536     0x11/imm32/alloc-id:fake
15537     _string-increment/imm32/name
15538     0/imm32/no-inouts
15539     0/imm32/no-inouts
15540     0x11/imm32/alloc-id:fake
15541     Single-int-var-in-ebx/imm32/outputs
15542     0x11/imm32/alloc-id:fake
15543     _string_43_increment_ebx/imm32/subx-name
15544     0/imm32/no-rm32
15545     0/imm32/no-r32
15546     0/imm32/no-imm32
15547     0/imm32/no-imm8
15548     0/imm32/no-disp32
15549     0/imm32/output-is-write-only
15550     0x11/imm32/alloc-id:fake
15551     _Primitive-increment-esi/imm32/next
15552 _Primitive-increment-esi:  # (payload primitive)
15553     0x11/imm32/alloc-id:fake:payload
15554     # var/esi <- increment => 46/increment-esi
15555     0x11/imm32/alloc-id:fake
15556     _string-increment/imm32/name
15557     0/imm32/no-inouts
15558     0/imm32/no-inouts
15559     0x11/imm32/alloc-id:fake
15560     Single-int-var-in-esi/imm32/outputs
15561     0x11/imm32/alloc-id:fake
15562     _string_46_increment_esi/imm32/subx-name
15563     0/imm32/no-rm32
15564     0/imm32/no-r32
15565     0/imm32/no-imm32
15566     0/imm32/no-imm8
15567     0/imm32/no-disp32
15568     0/imm32/output-is-write-only
15569     0x11/imm32/alloc-id:fake
15570     _Primitive-increment-edi/imm32/next
15571 _Primitive-increment-edi:  # (payload primitive)
15572     0x11/imm32/alloc-id:fake:payload
15573     # var/edi <- increment => 47/increment-edi
15574     0x11/imm32/alloc-id:fake
15575     _string-increment/imm32/name
15576     0/imm32/no-inouts
15577     0/imm32/no-inouts
15578     0x11/imm32/alloc-id:fake
15579     Single-int-var-in-edi/imm32/outputs
15580     0x11/imm32/alloc-id:fake
15581     _string_47_increment_edi/imm32/subx-name
15582     0/imm32/no-rm32
15583     0/imm32/no-r32
15584     0/imm32/no-imm32
15585     0/imm32/no-imm8
15586     0/imm32/no-disp32
15587     0/imm32/output-is-write-only
15588     0x11/imm32/alloc-id:fake
15589     _Primitive-decrement-eax/imm32/next
15590 _Primitive-decrement-eax:  # (payload primitive)
15591     0x11/imm32/alloc-id:fake:payload
15592     # var/eax <- decrement => 48/decrement-eax
15593     0x11/imm32/alloc-id:fake
15594     _string-decrement/imm32/name
15595     0/imm32/no-inouts
15596     0/imm32/no-inouts
15597     0x11/imm32/alloc-id:fake
15598     Single-int-var-in-eax/imm32/outputs
15599     0x11/imm32/alloc-id:fake
15600     _string_48_decrement_eax/imm32/subx-name
15601     0/imm32/no-rm32
15602     0/imm32/no-r32
15603     0/imm32/no-imm32
15604     0/imm32/no-imm8
15605     0/imm32/no-disp32
15606     0/imm32/output-is-write-only
15607     0x11/imm32/alloc-id:fake
15608     _Primitive-decrement-ecx/imm32/next
15609 _Primitive-decrement-ecx:  # (payload primitive)
15610     0x11/imm32/alloc-id:fake:payload
15611     # var/ecx <- decrement => 49/decrement-ecx
15612     0x11/imm32/alloc-id:fake
15613     _string-decrement/imm32/name
15614     0/imm32/no-inouts
15615     0/imm32/no-inouts
15616     0x11/imm32/alloc-id:fake
15617     Single-int-var-in-ecx/imm32/outputs
15618     0x11/imm32/alloc-id:fake
15619     _string_49_decrement_ecx/imm32/subx-name
15620     0/imm32/no-rm32
15621     0/imm32/no-r32
15622     0/imm32/no-imm32
15623     0/imm32/no-imm8
15624     0/imm32/no-disp32
15625     0/imm32/output-is-write-only
15626     0x11/imm32/alloc-id:fake
15627     _Primitive-decrement-edx/imm32/next
15628 _Primitive-decrement-edx:  # (payload primitive)
15629     0x11/imm32/alloc-id:fake:payload
15630     # var/edx <- decrement => 4a/decrement-edx
15631     0x11/imm32/alloc-id:fake
15632     _string-decrement/imm32/name
15633     0/imm32/no-inouts
15634     0/imm32/no-inouts
15635     0x11/imm32/alloc-id:fake
15636     Single-int-var-in-edx/imm32/outputs
15637     0x11/imm32/alloc-id:fake
15638     _string_4a_decrement_edx/imm32/subx-name
15639     0/imm32/no-rm32
15640     0/imm32/no-r32
15641     0/imm32/no-imm32
15642     0/imm32/no-imm8
15643     0/imm32/no-disp32
15644     0/imm32/output-is-write-only
15645     0x11/imm32/alloc-id:fake
15646     _Primitive-decrement-ebx/imm32/next
15647 _Primitive-decrement-ebx:  # (payload primitive)
15648     0x11/imm32/alloc-id:fake:payload
15649     # var/ebx <- decrement => 4b/decrement-ebx
15650     0x11/imm32/alloc-id:fake
15651     _string-decrement/imm32/name
15652     0/imm32/no-inouts
15653     0/imm32/no-inouts
15654     0x11/imm32/alloc-id:fake
15655     Single-int-var-in-ebx/imm32/outputs
15656     0x11/imm32/alloc-id:fake
15657     _string_4b_decrement_ebx/imm32/subx-name
15658     0/imm32/no-rm32
15659     0/imm32/no-r32
15660     0/imm32/no-imm32
15661     0/imm32/no-imm8
15662     0/imm32/no-disp32
15663     0/imm32/output-is-write-only
15664     0x11/imm32/alloc-id:fake
15665     _Primitive-decrement-esi/imm32/next
15666 _Primitive-decrement-esi:  # (payload primitive)
15667     0x11/imm32/alloc-id:fake:payload
15668     # var/esi <- decrement => 4e/decrement-esi
15669     0x11/imm32/alloc-id:fake
15670     _string-decrement/imm32/name
15671     0/imm32/no-inouts
15672     0/imm32/no-inouts
15673     0x11/imm32/alloc-id:fake
15674     Single-int-var-in-esi/imm32/outputs
15675     0x11/imm32/alloc-id:fake
15676     _string_4e_decrement_esi/imm32/subx-name
15677     0/imm32/no-rm32
15678     0/imm32/no-r32
15679     0/imm32/no-imm32
15680     0/imm32/no-imm8
15681     0/imm32/no-disp32
15682     0/imm32/output-is-write-only
15683     0x11/imm32/alloc-id:fake
15684     _Primitive-decrement-edi/imm32/next
15685 _Primitive-decrement-edi:  # (payload primitive)
15686     0x11/imm32/alloc-id:fake:payload
15687     # var/edi <- decrement => 4f/decrement-edi
15688     0x11/imm32/alloc-id:fake
15689     _string-decrement/imm32/name
15690     0/imm32/no-inouts
15691     0/imm32/no-inouts
15692     0x11/imm32/alloc-id:fake
15693     Single-int-var-in-edi/imm32/outputs
15694     0x11/imm32/alloc-id:fake
15695     _string_4f_decrement_edi/imm32/subx-name
15696     0/imm32/no-rm32
15697     0/imm32/no-r32
15698     0/imm32/no-imm32
15699     0/imm32/no-imm8
15700     0/imm32/no-disp32
15701     0/imm32/output-is-write-only
15702     0x11/imm32/alloc-id:fake
15703     _Primitive-increment-mem/imm32/next
15704 _Primitive-increment-mem:  # (payload primitive)
15705     0x11/imm32/alloc-id:fake:payload
15706     # increment var => ff 0/subop/increment *(ebp+__)
15707     0x11/imm32/alloc-id:fake
15708     _string-increment/imm32/name
15709     0x11/imm32/alloc-id:fake
15710     Single-int-var-in-mem/imm32/inouts
15711     0/imm32/no-outputs
15712     0/imm32/no-outputs
15713     0x11/imm32/alloc-id:fake
15714     _string_ff_subop_increment/imm32/subx-name
15715     1/imm32/rm32-is-first-inout
15716     0/imm32/no-r32
15717     0/imm32/no-imm32
15718     0/imm32/no-imm8
15719     0/imm32/no-disp32
15720     0/imm32/output-is-write-only
15721     0x11/imm32/alloc-id:fake
15722     _Primitive-increment-reg/imm32/next
15723 _Primitive-increment-reg:  # (payload primitive)
15724     0x11/imm32/alloc-id:fake:payload
15725     # var/reg <- increment => ff 0/subop/increment %__
15726     0x11/imm32/alloc-id:fake
15727     _string-increment/imm32/name
15728     0/imm32/no-inouts
15729     0/imm32/no-inouts
15730     0x11/imm32/alloc-id:fake
15731     Single-int-var-in-some-register/imm32/outputs
15732     0x11/imm32/alloc-id:fake
15733     _string_ff_subop_increment/imm32/subx-name
15734     3/imm32/rm32-is-first-output
15735     0/imm32/no-r32
15736     0/imm32/no-imm32
15737     0/imm32/no-imm8
15738     0/imm32/no-disp32
15739     0/imm32/output-is-write-only
15740     0x11/imm32/alloc-id:fake
15741     _Primitive-decrement-mem/imm32/next
15742 _Primitive-decrement-mem:  # (payload primitive)
15743     0x11/imm32/alloc-id:fake:payload
15744     # decrement var => ff 1/subop/decrement *(ebp+__)
15745     0x11/imm32/alloc-id:fake
15746     _string-decrement/imm32/name
15747     0x11/imm32/alloc-id:fake
15748     Single-int-var-in-mem/imm32/inouts
15749     0/imm32/no-outputs
15750     0/imm32/no-outputs
15751     0x11/imm32/alloc-id:fake
15752     _string_ff_subop_decrement/imm32/subx-name
15753     1/imm32/rm32-is-first-inout
15754     0/imm32/no-r32
15755     0/imm32/no-imm32
15756     0/imm32/no-imm8
15757     0/imm32/no-disp32
15758     0/imm32/output-is-write-only
15759     0x11/imm32/alloc-id:fake
15760     _Primitive-decrement-reg/imm32/next
15761 _Primitive-decrement-reg:  # (payload primitive)
15762     0x11/imm32/alloc-id:fake:payload
15763     # var/reg <- decrement => ff 1/subop/decrement %__
15764     0x11/imm32/alloc-id:fake
15765     _string-decrement/imm32/name
15766     0/imm32/no-inouts
15767     0/imm32/no-inouts
15768     0x11/imm32/alloc-id:fake
15769     Single-int-var-in-some-register/imm32/outputs
15770     0x11/imm32/alloc-id:fake
15771     _string_ff_subop_decrement/imm32/subx-name
15772     3/imm32/rm32-is-first-output
15773     0/imm32/no-r32
15774     0/imm32/no-imm32
15775     0/imm32/no-imm8
15776     0/imm32/no-disp32
15777     0/imm32/output-is-write-only
15778     0x11/imm32/alloc-id:fake
15779     _Primitive-add-to-eax/imm32/next
15780 # - add
15781 _Primitive-add-to-eax:  # (payload primitive)
15782     0x11/imm32/alloc-id:fake:payload
15783     # var/eax <- add lit => 05/add-to-eax lit/imm32
15784     0x11/imm32/alloc-id:fake
15785     _string-add/imm32/name
15786     0x11/imm32/alloc-id:fake
15787     Single-lit-var/imm32/inouts
15788     0x11/imm32/alloc-id:fake
15789     Single-int-var-in-eax/imm32/outputs
15790     0x11/imm32/alloc-id:fake
15791     _string_05_add_to_eax/imm32/subx-name
15792     0/imm32/no-rm32
15793     0/imm32/no-r32
15794     1/imm32/imm32-is-first-inout
15795     0/imm32/no-imm8
15796     0/imm32/no-disp32
15797     0/imm32/output-is-write-only
15798     0x11/imm32/alloc-id:fake
15799     _Primitive-add-reg-to-reg/imm32/next
15800 _Primitive-add-reg-to-reg:  # (payload primitive)
15801     0x11/imm32/alloc-id:fake:payload
15802     # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32
15803     0x11/imm32/alloc-id:fake
15804     _string-add/imm32/name
15805     0x11/imm32/alloc-id:fake
15806     Single-int-var-in-some-register/imm32/inouts
15807     0x11/imm32/alloc-id:fake
15808     Single-int-var-in-some-register/imm32/outputs
15809     0x11/imm32/alloc-id:fake
15810     _string_01_add_to/imm32/subx-name
15811     3/imm32/rm32-is-first-output
15812     1/imm32/r32-is-first-inout
15813     0/imm32/no-imm32
15814     0/imm32/no-imm8
15815     0/imm32/no-disp32
15816     0/imm32/output-is-write-only
15817     0x11/imm32/alloc-id:fake
15818     _Primitive-add-reg-to-mem/imm32/next
15819 _Primitive-add-reg-to-mem:  # (payload primitive)
15820     0x11/imm32/alloc-id:fake:payload
15821     # add-to var1 var2/reg => 01/add-to var1 var2/r32
15822     0x11/imm32/alloc-id:fake
15823     _string-add-to/imm32/name
15824     0x11/imm32/alloc-id:fake
15825     Two-args-int-stack-int-reg/imm32/inouts
15826     0/imm32/no-outputs
15827     0/imm32/no-outputs
15828     0x11/imm32/alloc-id:fake
15829     _string_01_add_to/imm32/subx-name
15830     1/imm32/rm32-is-first-inout
15831     2/imm32/r32-is-second-inout
15832     0/imm32/no-imm32
15833     0/imm32/no-imm8
15834     0/imm32/no-disp32
15835     0/imm32/output-is-write-only
15836     0x11/imm32/alloc-id:fake
15837     _Primitive-add-mem-to-reg/imm32/next
15838 _Primitive-add-mem-to-reg:  # (payload primitive)
15839     0x11/imm32/alloc-id:fake:payload
15840     # var1/reg <- add var2 => 03/add var2/rm32 var1/r32
15841     0x11/imm32/alloc-id:fake
15842     _string-add/imm32/name
15843     0x11/imm32/alloc-id:fake
15844     Single-int-var-in-mem/imm32/inouts
15845     0x11/imm32/alloc-id:fake
15846     Single-int-var-in-some-register/imm32/outputs
15847     0x11/imm32/alloc-id:fake
15848     _string_03_add/imm32/subx-name
15849     1/imm32/rm32-is-first-inout
15850     3/imm32/r32-is-first-output
15851     0/imm32/no-imm32
15852     0/imm32/no-imm8
15853     0/imm32/no-disp32
15854     0/imm32/output-is-write-only
15855     0x11/imm32/alloc-id:fake
15856     _Primitive-add-lit-to-reg/imm32/next
15857 _Primitive-add-lit-to-reg:  # (payload primitive)
15858     0x11/imm32/alloc-id:fake:payload
15859     # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32
15860     0x11/imm32/alloc-id:fake
15861     _string-add/imm32/name
15862     0x11/imm32/alloc-id:fake
15863     Single-lit-var/imm32/inouts
15864     0x11/imm32/alloc-id:fake
15865     Single-int-var-in-some-register/imm32/outputs
15866     0x11/imm32/alloc-id:fake
15867     _string_81_subop_add/imm32/subx-name
15868     3/imm32/rm32-is-first-output
15869     0/imm32/no-r32
15870     1/imm32/imm32-is-first-inout
15871     0/imm32/no-imm8
15872     0/imm32/no-disp32
15873     0/imm32/output-is-write-only
15874     0x11/imm32/alloc-id:fake
15875     _Primitive-add-lit-to-mem/imm32/next
15876 _Primitive-add-lit-to-mem:  # (payload primitive)
15877     0x11/imm32/alloc-id:fake:payload
15878     # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32
15879     0x11/imm32/alloc-id:fake
15880     _string-add-to/imm32/name
15881     0x11/imm32/alloc-id:fake
15882     Int-var-and-literal/imm32/inouts
15883     0/imm32/no-outputs
15884     0/imm32/no-outputs
15885     0x11/imm32/alloc-id:fake
15886     _string_81_subop_add/imm32/subx-name
15887     1/imm32/rm32-is-first-inout
15888     0/imm32/no-r32
15889     2/imm32/imm32-is-second-inout
15890     0/imm32/no-imm8
15891     0/imm32/no-disp32
15892     0/imm32/output-is-write-only
15893     0x11/imm32/alloc-id:fake
15894     _Primitive-subtract-from-eax/imm32/next
15895 # - subtract
15896 _Primitive-subtract-from-eax:  # (payload primitive)
15897     0x11/imm32/alloc-id:fake:payload
15898     # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32
15899     0x11/imm32/alloc-id:fake
15900     _string-subtract/imm32/name
15901     0x11/imm32/alloc-id:fake
15902     Single-lit-var/imm32/inouts
15903     0x11/imm32/alloc-id:fake
15904     Single-int-var-in-eax/imm32/outputs
15905     0x11/imm32/alloc-id:fake
15906     _string_2d_subtract_from_eax/imm32/subx-name
15907     0/imm32/no-rm32
15908     0/imm32/no-r32
15909     1/imm32/imm32-is-first-inout
15910     0/imm32/no-imm8
15911     0/imm32/no-disp32
15912     0/imm32/output-is-write-only
15913     0x11/imm32/alloc-id:fake
15914     _Primitive-subtract-reg-from-reg/imm32/next
15915 _Primitive-subtract-reg-from-reg:  # (payload primitive)
15916     0x11/imm32/alloc-id:fake:payload
15917     # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32
15918     0x11/imm32/alloc-id:fake
15919     _string-subtract/imm32/name
15920     0x11/imm32/alloc-id:fake
15921     Single-int-var-in-some-register/imm32/inouts
15922     0x11/imm32/alloc-id:fake
15923     Single-int-var-in-some-register/imm32/outputs
15924     0x11/imm32/alloc-id:fake
15925     _string_29_subtract_from/imm32/subx-name
15926     3/imm32/rm32-is-first-output
15927     1/imm32/r32-is-first-inout
15928     0/imm32/no-imm32
15929     0/imm32/no-imm8
15930     0/imm32/no-disp32
15931     0/imm32/output-is-write-only
15932     0x11/imm32/alloc-id:fake
15933     _Primitive-subtract-reg-from-mem/imm32/next
15934 _Primitive-subtract-reg-from-mem:  # (payload primitive)
15935     0x11/imm32/alloc-id:fake:payload
15936     # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32
15937     0x11/imm32/alloc-id:fake
15938     _string-subtract-from/imm32/name
15939     0x11/imm32/alloc-id:fake
15940     Two-args-int-stack-int-reg/imm32/inouts
15941     0/imm32/no-outputs
15942     0/imm32/no-outputs
15943     0x11/imm32/alloc-id:fake
15944     _string_29_subtract_from/imm32/subx-name
15945     1/imm32/rm32-is-first-inout
15946     2/imm32/r32-is-second-inout
15947     0/imm32/no-imm32
15948     0/imm32/no-imm8
15949     0/imm32/no-disp32
15950     0/imm32/output-is-write-only
15951     0x11/imm32/alloc-id:fake
15952     _Primitive-subtract-mem-from-reg/imm32/next
15953 _Primitive-subtract-mem-from-reg:  # (payload primitive)
15954     0x11/imm32/alloc-id:fake:payload
15955     # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32
15956     0x11/imm32/alloc-id:fake
15957     _string-subtract/imm32/name
15958     0x11/imm32/alloc-id:fake
15959     Single-int-var-in-mem/imm32/inouts
15960     0x11/imm32/alloc-id:fake
15961     Single-int-var-in-some-register/imm32/outputs
15962     0x11/imm32/alloc-id:fake
15963     _string_2b_subtract/imm32/subx-name
15964     1/imm32/rm32-is-first-inout
15965     3/imm32/r32-is-first-output
15966     0/imm32/no-imm32
15967     0/imm32/no-imm8
15968     0/imm32/no-disp32
15969     0/imm32/output-is-write-only
15970     0x11/imm32/alloc-id:fake
15971     _Primitive-subtract-lit-from-reg/imm32/next
15972 _Primitive-subtract-lit-from-reg:  # (payload primitive)
15973     0x11/imm32/alloc-id:fake:payload
15974     # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32
15975     0x11/imm32/alloc-id:fake
15976     _string-subtract/imm32/name
15977     0x11/imm32/alloc-id:fake
15978     Single-lit-var/imm32/inouts
15979     0x11/imm32/alloc-id:fake
15980     Single-int-var-in-some-register/imm32/outputs
15981     0x11/imm32/alloc-id:fake
15982     _string_81_subop_subtract/imm32/subx-name
15983     3/imm32/rm32-is-first-output
15984     0/imm32/no-r32
15985     1/imm32/imm32-is-first-inout
15986     0/imm32/no-imm8
15987     0/imm32/no-disp32
15988     0/imm32/output-is-write-only
15989     0x11/imm32/alloc-id:fake
15990     _Primitive-subtract-lit-from-mem/imm32/next
15991 _Primitive-subtract-lit-from-mem:  # (payload primitive)
15992     0x11/imm32/alloc-id:fake:payload
15993     # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32
15994     0x11/imm32/alloc-id:fake
15995     _string-subtract-from/imm32/name
15996     0x11/imm32/alloc-id:fake
15997     Int-var-and-literal/imm32/inouts
15998     0/imm32/no-outputs
15999     0/imm32/no-outputs
16000     0x11/imm32/alloc-id:fake
16001     _string_81_subop_subtract/imm32/subx-name
16002     1/imm32/rm32-is-first-inout
16003     0/imm32/no-r32
16004     2/imm32/imm32-is-second-inout
16005     0/imm32/no-imm8
16006     0/imm32/no-disp32
16007     0/imm32/output-is-write-only
16008     0x11/imm32/alloc-id:fake
16009     _Primitive-and-with-eax/imm32/next
16010 # - and
16011 _Primitive-and-with-eax:  # (payload primitive)
16012     0x11/imm32/alloc-id:fake:payload
16013     # var/eax <- and lit => 25/and-with-eax lit/imm32
16014     0x11/imm32/alloc-id:fake
16015     _string-and/imm32/name
16016     0x11/imm32/alloc-id:fake
16017     Single-lit-var/imm32/inouts
16018     0x11/imm32/alloc-id:fake
16019     Single-int-var-in-eax/imm32/outputs
16020     0x11/imm32/alloc-id:fake
16021     _string_25_and_with_eax/imm32/subx-name
16022     0/imm32/no-rm32
16023     0/imm32/no-r32
16024     1/imm32/imm32-is-first-inout
16025     0/imm32/no-imm8
16026     0/imm32/no-disp32
16027     0/imm32/output-is-write-only
16028     0x11/imm32/alloc-id:fake
16029     _Primitive-and-reg-with-reg/imm32/next
16030 _Primitive-and-reg-with-reg:  # (payload primitive)
16031     0x11/imm32/alloc-id:fake:payload
16032     # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32
16033     0x11/imm32/alloc-id:fake
16034     _string-and/imm32/name
16035     0x11/imm32/alloc-id:fake
16036     Single-int-var-in-some-register/imm32/inouts
16037     0x11/imm32/alloc-id:fake
16038     Single-int-var-in-some-register/imm32/outputs
16039     0x11/imm32/alloc-id:fake
16040     _string_21_and_with/imm32/subx-name
16041     3/imm32/rm32-is-first-output
16042     1/imm32/r32-is-first-inout
16043     0/imm32/no-imm32
16044     0/imm32/no-imm8
16045     0/imm32/no-disp32
16046     0/imm32/output-is-write-only
16047     0x11/imm32/alloc-id:fake
16048     _Primitive-and-reg-with-mem/imm32/next
16049 _Primitive-and-reg-with-mem:  # (payload primitive)
16050     0x11/imm32/alloc-id:fake:payload
16051     # and-with var1 var2/reg => 21/and-with var1 var2/r32
16052     0x11/imm32/alloc-id:fake
16053     _string-and-with/imm32/name
16054     0x11/imm32/alloc-id:fake
16055     Two-args-int-stack-int-reg/imm32/inouts
16056     0/imm32/no-outputs
16057     0/imm32/no-outputs
16058     0x11/imm32/alloc-id:fake
16059     _string_21_and_with/imm32/subx-name
16060     1/imm32/rm32-is-first-inout
16061     2/imm32/r32-is-second-inout
16062     0/imm32/no-imm32
16063     0/imm32/no-imm8
16064     0/imm32/no-disp32
16065     0/imm32/output-is-write-only
16066     0x11/imm32/alloc-id:fake
16067     _Primitive-and-mem-with-reg/imm32/next
16068 _Primitive-and-mem-with-reg:  # (payload primitive)
16069     0x11/imm32/alloc-id:fake:payload
16070     # var1/reg <- and var2 => 23/and var2/rm32 var1/r32
16071     0x11/imm32/alloc-id:fake
16072     _string-and/imm32/name
16073     0x11/imm32/alloc-id:fake
16074     Single-int-var-in-mem/imm32/inouts
16075     0x11/imm32/alloc-id:fake
16076     Single-int-var-in-some-register/imm32/outputs
16077     0x11/imm32/alloc-id:fake
16078     _string_23_and/imm32/subx-name
16079     1/imm32/rm32-is-first-inout
16080     3/imm32/r32-is-first-output
16081     0/imm32/no-imm32
16082     0/imm32/no-imm8
16083     0/imm32/no-disp32
16084     0/imm32/output-is-write-only
16085     0x11/imm32/alloc-id:fake
16086     _Primitive-and-lit-with-reg/imm32/next
16087 _Primitive-and-lit-with-reg:  # (payload primitive)
16088     0x11/imm32/alloc-id:fake:payload
16089     # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32
16090     0x11/imm32/alloc-id:fake
16091     _string-and/imm32/name
16092     0x11/imm32/alloc-id:fake
16093     Single-lit-var/imm32/inouts
16094     0x11/imm32/alloc-id:fake
16095     Single-int-var-in-some-register/imm32/outputs
16096     0x11/imm32/alloc-id:fake
16097     _string_81_subop_and/imm32/subx-name
16098     3/imm32/rm32-is-first-output
16099     0/imm32/no-r32
16100     1/imm32/imm32-is-first-inout
16101     0/imm32/no-imm8
16102     0/imm32/no-disp32
16103     0/imm32/output-is-write-only
16104     0x11/imm32/alloc-id:fake
16105     _Primitive-and-lit-with-mem/imm32/next
16106 _Primitive-and-lit-with-mem:  # (payload primitive)
16107     0x11/imm32/alloc-id:fake:payload
16108     # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32
16109     0x11/imm32/alloc-id:fake
16110     _string-and-with/imm32/name
16111     0x11/imm32/alloc-id:fake
16112     Int-var-and-literal/imm32/inouts
16113     0/imm32/no-outputs
16114     0/imm32/no-outputs
16115     0x11/imm32/alloc-id:fake
16116     _string_81_subop_and/imm32/subx-name
16117     1/imm32/rm32-is-first-inout
16118     0/imm32/no-r32
16119     2/imm32/imm32-is-second-inout
16120     0/imm32/no-imm8
16121     0/imm32/no-disp32
16122     0/imm32/output-is-write-only
16123     0x11/imm32/alloc-id:fake
16124     _Primitive-or-with-eax/imm32/next
16125 # - or
16126 _Primitive-or-with-eax:  # (payload primitive)
16127     0x11/imm32/alloc-id:fake:payload
16128     # var/eax <- or lit => 0d/or-with-eax lit/imm32
16129     0x11/imm32/alloc-id:fake
16130     _string-or/imm32/name
16131     0x11/imm32/alloc-id:fake
16132     Single-lit-var/imm32/inouts
16133     0x11/imm32/alloc-id:fake
16134     Single-int-var-in-eax/imm32/outputs
16135     0x11/imm32/alloc-id:fake
16136     _string_0d_or_with_eax/imm32/subx-name
16137     0/imm32/no-rm32
16138     0/imm32/no-r32
16139     1/imm32/imm32-is-first-inout
16140     0/imm32/no-imm8
16141     0/imm32/no-disp32
16142     0/imm32/output-is-write-only
16143     0x11/imm32/alloc-id:fake
16144     _Primitive-or-reg-with-reg/imm32/next
16145 _Primitive-or-reg-with-reg:  # (payload primitive)
16146     0x11/imm32/alloc-id:fake:payload
16147     # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32
16148     0x11/imm32/alloc-id:fake
16149     _string-or/imm32/name
16150     0x11/imm32/alloc-id:fake
16151     Single-int-var-in-some-register/imm32/inouts
16152     0x11/imm32/alloc-id:fake
16153     Single-int-var-in-some-register/imm32/outputs
16154     0x11/imm32/alloc-id:fake
16155     _string_09_or_with/imm32/subx-name
16156     3/imm32/rm32-is-first-output
16157     1/imm32/r32-is-first-inout
16158     0/imm32/no-imm32
16159     0/imm32/no-imm8
16160     0/imm32/no-disp32
16161     0/imm32/output-is-write-only
16162     0x11/imm32/alloc-id:fake
16163     _Primitive-or-reg-with-mem/imm32/next
16164 _Primitive-or-reg-with-mem:  # (payload primitive)
16165     0x11/imm32/alloc-id:fake:payload
16166     # or-with var1 var2/reg => 09/or-with var1 var2/r32
16167     0x11/imm32/alloc-id:fake
16168     _string-or-with/imm32/name
16169     0x11/imm32/alloc-id:fake
16170     Two-args-int-stack-int-reg/imm32/inouts
16171     0/imm32/no-outputs
16172     0/imm32/no-outputs
16173     0x11/imm32/alloc-id:fake
16174     _string_09_or_with/imm32/subx-name
16175     1/imm32/rm32-is-first-inout
16176     2/imm32/r32-is-second-inout
16177     0/imm32/no-imm32
16178     0/imm32/no-imm8
16179     0/imm32/no-disp32
16180     0/imm32/output-is-write-only
16181     0x11/imm32/alloc-id:fake
16182     _Primitive-or-mem-with-reg/imm32/next
16183 _Primitive-or-mem-with-reg:  # (payload primitive)
16184     0x11/imm32/alloc-id:fake:payload
16185     # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32
16186     0x11/imm32/alloc-id:fake
16187     _string-or/imm32/name
16188     0x11/imm32/alloc-id:fake
16189     Single-int-var-in-mem/imm32/inouts
16190     0x11/imm32/alloc-id:fake
16191     Single-int-var-in-some-register/imm32/outputs
16192     0x11/imm32/alloc-id:fake
16193     _string_0b_or/imm32/subx-name
16194     1/imm32/rm32-is-first-inout
16195     3/imm32/r32-is-first-output
16196     0/imm32/no-imm32
16197     0/imm32/no-imm8
16198     0/imm32/no-disp32
16199     0/imm32/output-is-write-only
16200     0x11/imm32/alloc-id:fake
16201     _Primitive-or-lit-with-reg/imm32/next
16202 _Primitive-or-lit-with-reg:  # (payload primitive)
16203     0x11/imm32/alloc-id:fake:payload
16204     # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32
16205     0x11/imm32/alloc-id:fake
16206     _string-or/imm32/name
16207     0x11/imm32/alloc-id:fake
16208     Single-lit-var/imm32/inouts
16209     0x11/imm32/alloc-id:fake
16210     Single-int-var-in-some-register/imm32/outputs
16211     0x11/imm32/alloc-id:fake
16212     _string_81_subop_or/imm32/subx-name
16213     3/imm32/rm32-is-first-output
16214     0/imm32/no-r32
16215     1/imm32/imm32-is-first-inout
16216     0/imm32/no-imm8
16217     0/imm32/no-disp32
16218     0/imm32/output-is-write-only
16219     0x11/imm32/alloc-id:fake
16220     _Primitive-or-lit-with-mem/imm32/next
16221 _Primitive-or-lit-with-mem:  # (payload primitive)
16222     0x11/imm32/alloc-id:fake:payload
16223     # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32
16224     0x11/imm32/alloc-id:fake
16225     _string-or-with/imm32/name
16226     0x11/imm32/alloc-id:fake
16227     Int-var-and-literal/imm32/inouts
16228     0/imm32/no-outputs
16229     0/imm32/no-outputs
16230     0x11/imm32/alloc-id:fake
16231     _string_81_subop_or/imm32/subx-name
16232     1/imm32/rm32-is-first-inout
16233     0/imm32/no-r32
16234     2/imm32/imm32-is-second-inout
16235     0/imm32/no-imm8
16236     0/imm32/no-disp32
16237     0/imm32/output-is-write-only
16238     0x11/imm32/alloc-id:fake
16239     _Primitive-xor-with-eax/imm32/next
16240 # - xor
16241 _Primitive-xor-with-eax:  # (payload primitive)
16242     0x11/imm32/alloc-id:fake:payload
16243     # var/eax <- xor lit => 35/xor-with-eax lit/imm32
16244     0x11/imm32/alloc-id:fake
16245     _string-xor/imm32/name
16246     0x11/imm32/alloc-id:fake
16247     Single-lit-var/imm32/inouts
16248     0x11/imm32/alloc-id:fake
16249     Single-int-var-in-eax/imm32/outputs
16250     0x11/imm32/alloc-id:fake
16251     _string_35_xor_with_eax/imm32/subx-name
16252     0/imm32/no-rm32
16253     0/imm32/no-r32
16254     1/imm32/imm32-is-first-inout
16255     0/imm32/no-imm8
16256     0/imm32/no-disp32
16257     0/imm32/output-is-write-only
16258     0x11/imm32/alloc-id:fake
16259     _Primitive-xor-reg-with-reg/imm32/next
16260 _Primitive-xor-reg-with-reg:  # (payload primitive)
16261     0x11/imm32/alloc-id:fake:payload
16262     # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32
16263     0x11/imm32/alloc-id:fake
16264     _string-xor/imm32/name
16265     0x11/imm32/alloc-id:fake
16266     Single-int-var-in-some-register/imm32/inouts
16267     0x11/imm32/alloc-id:fake
16268     Single-int-var-in-some-register/imm32/outputs
16269     0x11/imm32/alloc-id:fake
16270     _string_31_xor_with/imm32/subx-name
16271     3/imm32/rm32-is-first-output
16272     1/imm32/r32-is-first-inout
16273     0/imm32/no-imm32
16274     0/imm32/no-imm8
16275     0/imm32/no-disp32
16276     0/imm32/output-is-write-only
16277     0x11/imm32/alloc-id:fake
16278     _Primitive-xor-reg-with-mem/imm32/next
16279 _Primitive-xor-reg-with-mem:  # (payload primitive)
16280     0x11/imm32/alloc-id:fake:payload
16281     # xor-with var1 var2/reg => 31/xor-with var1 var2/r32
16282     0x11/imm32/alloc-id:fake
16283     _string-xor-with/imm32/name
16284     0x11/imm32/alloc-id:fake
16285     Two-args-int-stack-int-reg/imm32/inouts
16286     0/imm32/no-outputs
16287     0/imm32/no-outputs
16288     0x11/imm32/alloc-id:fake
16289     _string_31_xor_with/imm32/subx-name
16290     1/imm32/rm32-is-first-inout
16291     2/imm32/r32-is-second-inout
16292     0/imm32/no-imm32
16293     0/imm32/no-imm8
16294     0/imm32/no-disp32
16295     0/imm32/output-is-write-only
16296     0x11/imm32/alloc-id:fake
16297     _Primitive-xor-mem-with-reg/imm32/next
16298 _Primitive-xor-mem-with-reg:  # (payload primitive)
16299     0x11/imm32/alloc-id:fake:payload
16300     # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32
16301     0x11/imm32/alloc-id:fake
16302     _string-xor/imm32/name
16303     0x11/imm32/alloc-id:fake
16304     Single-int-var-in-mem/imm32/inouts
16305     0x11/imm32/alloc-id:fake
16306     Single-int-var-in-some-register/imm32/outputs
16307     0x11/imm32/alloc-id:fake
16308     _string_33_xor/imm32/subx-name
16309     1/imm32/rm32-is-first-inout
16310     3/imm32/r32-is-first-output
16311     0/imm32/no-imm32
16312     0/imm32/no-imm8
16313     0/imm32/no-disp32
16314     0/imm32/output-is-write-only
16315     0x11/imm32/alloc-id:fake
16316     _Primitive-xor-lit-with-reg/imm32/next
16317 _Primitive-xor-lit-with-reg:  # (payload primitive)
16318     0x11/imm32/alloc-id:fake:payload
16319     # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32
16320     0x11/imm32/alloc-id:fake
16321     _string-xor/imm32/name
16322     0x11/imm32/alloc-id:fake
16323     Single-lit-var/imm32/inouts
16324     0x11/imm32/alloc-id:fake
16325     Single-int-var-in-some-register/imm32/outputs
16326     0x11/imm32/alloc-id:fake
16327     _string_81_subop_xor/imm32/subx-name
16328     3/imm32/rm32-is-first-output
16329     0/imm32/no-r32
16330     1/imm32/imm32-is-first-inout
16331     0/imm32/no-imm8
16332     0/imm32/no-disp32
16333     0/imm32/output-is-write-only
16334     0x11/imm32/alloc-id:fake
16335     _Primitive-xor-lit-with-mem/imm32/next
16336 _Primitive-xor-lit-with-mem:  # (payload primitive)
16337     0x11/imm32/alloc-id:fake:payload
16338     # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32
16339     0x11/imm32/alloc-id:fake
16340     _string-xor-with/imm32/name
16341     0x11/imm32/alloc-id:fake
16342     Int-var-and-literal/imm32/inouts
16343     0/imm32/no-outputs
16344     0/imm32/no-outputs
16345     0x11/imm32/alloc-id:fake
16346     _string_81_subop_xor/imm32/subx-name
16347     1/imm32/rm32-is-first-inout
16348     0/imm32/no-r32
16349     2/imm32/imm32-is-second-inout
16350     0/imm32/no-imm8
16351     0/imm32/no-disp32
16352     0/imm32/output-is-write-only
16353     0x11/imm32/alloc-id:fake
16354     _Primitive-shift-reg-left-by-lit/imm32/next
16355 _Primitive-shift-reg-left-by-lit:  # (payload primitive)
16356     0x11/imm32/alloc-id:fake:payload
16357     # var1/reg <- shift-left lit => c1/shift 4/subop/left var1/rm32 lit/imm32
16358     0x11/imm32/alloc-id:fake
16359     _string-shift-left/imm32/name
16360     0x11/imm32/alloc-id:fake
16361     Single-lit-var/imm32/inouts
16362     0x11/imm32/alloc-id:fake
16363     Single-int-var-in-some-register/imm32/outputs
16364     0x11/imm32/alloc-id:fake
16365     _string_c1_subop_shift_left/imm32/subx-name
16366     3/imm32/rm32-is-first-output
16367     0/imm32/no-r32
16368     0/imm32/no-imm32
16369     1/imm32/imm8-is-first-inout
16370     0/imm32/no-disp32
16371     0/imm32/output-is-write-only
16372     0x11/imm32/alloc-id:fake
16373     _Primitive-shift-reg-right-by-lit/imm32/next
16374 _Primitive-shift-reg-right-by-lit:  # (payload primitive)
16375     0x11/imm32/alloc-id:fake:payload
16376     # var1/reg <- shift-right lit => c1/shift 5/subop/right var1/rm32 lit/imm32
16377     0x11/imm32/alloc-id:fake
16378     _string-shift-right/imm32/name
16379     0x11/imm32/alloc-id:fake
16380     Single-lit-var/imm32/inouts
16381     0x11/imm32/alloc-id:fake
16382     Single-int-var-in-some-register/imm32/outputs
16383     0x11/imm32/alloc-id:fake
16384     _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name
16385     3/imm32/rm32-is-first-output
16386     0/imm32/no-r32
16387     0/imm32/no-imm32
16388     1/imm32/imm8-is-first-inout
16389     0/imm32/no-disp32
16390     0/imm32/output-is-write-only
16391     0x11/imm32/alloc-id:fake
16392     _Primitive-shift-reg-right-signed-by-lit/imm32/next
16393 _Primitive-shift-reg-right-signed-by-lit:  # (payload primitive)
16394     0x11/imm32/alloc-id:fake:payload
16395     # var1/reg <- shift-right-signed lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32
16396     0x11/imm32/alloc-id:fake
16397     _string-shift-right-signed/imm32/name
16398     0x11/imm32/alloc-id:fake
16399     Single-lit-var/imm32/inouts
16400     0x11/imm32/alloc-id:fake
16401     Single-int-var-in-some-register/imm32/outputs
16402     0x11/imm32/alloc-id:fake
16403     _string_c1_subop_shift_right_preserving_sign/imm32/subx-name
16404     3/imm32/rm32-is-first-output
16405     0/imm32/no-r32
16406     0/imm32/no-imm32
16407     1/imm32/imm8-is-first-inout
16408     0/imm32/no-disp32
16409     0/imm32/output-is-write-only
16410     0x11/imm32/alloc-id:fake
16411     _Primitive-shift-mem-left-by-lit/imm32/next
16412 _Primitive-shift-mem-left-by-lit:  # (payload primitive)
16413     0x11/imm32/alloc-id:fake:payload
16414     # shift-left var1, lit => c1/shift 4/subop/left var1/rm32 lit/imm32
16415     0x11/imm32/alloc-id:fake
16416     _string-shift-left/imm32/name
16417     0x11/imm32/alloc-id:fake
16418     Int-var-and-literal/imm32/inouts
16419     0/imm32/no-outputs
16420     0/imm32/no-outputs
16421     0x11/imm32/alloc-id:fake
16422     _string_c1_subop_shift_left/imm32/subx-name
16423     1/imm32/rm32-is-first-inout
16424     0/imm32/no-r32
16425     0/imm32/no-imm32
16426     2/imm32/imm8-is-second-inout
16427     0/imm32/no-disp32
16428     0/imm32/output-is-write-only
16429     0x11/imm32/alloc-id:fake
16430     _Primitive-shift-mem-right-by-lit/imm32/next
16431 _Primitive-shift-mem-right-by-lit:  # (payload primitive)
16432     0x11/imm32/alloc-id:fake:payload
16433     # shift-right var1, lit => c1/shift 5/subop/right var1/rm32 lit/imm32
16434     0x11/imm32/alloc-id:fake
16435     _string-shift-right/imm32/name
16436     0x11/imm32/alloc-id:fake
16437     Int-var-and-literal/imm32/inouts
16438     0/imm32/no-outputs
16439     0/imm32/no-outputs
16440     0x11/imm32/alloc-id:fake
16441     _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name
16442     1/imm32/rm32-is-first-inout
16443     0/imm32/no-r32
16444     0/imm32/no-imm32
16445     2/imm32/imm8-is-second-inout
16446     0/imm32/no-disp32
16447     0/imm32/output-is-write-only
16448     0x11/imm32/alloc-id:fake
16449     _Primitive-shift-mem-right-signed-by-lit/imm32/next
16450 _Primitive-shift-mem-right-signed-by-lit:  # (payload primitive)
16451     0x11/imm32/alloc-id:fake:payload
16452     # shift-right-signed var1, lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32
16453     0x11/imm32/alloc-id:fake
16454     _string-shift-right-signed/imm32/name
16455     0x11/imm32/alloc-id:fake
16456     Int-var-and-literal/imm32/inouts
16457     0/imm32/no-outputs
16458     0/imm32/no-outputs
16459     0x11/imm32/alloc-id:fake
16460     _string_c1_subop_shift_right_preserving_sign/imm32/subx-name
16461     1/imm32/rm32-is-first-inout
16462     0/imm32/no-r32
16463     0/imm32/no-imm32
16464     2/imm32/imm8-is-second-inout
16465     0/imm32/no-disp32
16466     0/imm32/output-is-write-only
16467     0x11/imm32/alloc-id:fake
16468     _Primitive-copy-to-eax/imm32/next
16469 # - copy
16470 _Primitive-copy-to-eax:  # (payload primitive)
16471     0x11/imm32/alloc-id:fake:payload
16472     # var/eax <- copy lit => b8/copy-to-eax lit/imm32
16473     0x11/imm32/alloc-id:fake
16474     _string-copy/imm32/name
16475     0x11/imm32/alloc-id:fake
16476     Single-lit-var/imm32/inouts
16477     0x11/imm32/alloc-id:fake
16478     Single-int-var-in-eax/imm32/outputs
16479     0x11/imm32/alloc-id:fake
16480     _string_b8_copy_to_eax/imm32/subx-name
16481     0/imm32/no-rm32
16482     0/imm32/no-r32
16483     1/imm32/imm32-is-first-inout
16484     0/imm32/no-imm8
16485     0/imm32/no-disp32
16486     1/imm32/output-is-write-only
16487     0x11/imm32/alloc-id:fake
16488     _Primitive-copy-to-ecx/imm32/next
16489 _Primitive-copy-to-ecx:  # (payload primitive)
16490     0x11/imm32/alloc-id:fake:payload
16491     # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32
16492     0x11/imm32/alloc-id:fake
16493     _string-copy/imm32/name
16494     0x11/imm32/alloc-id:fake
16495     Single-lit-var/imm32/inouts
16496     0x11/imm32/alloc-id:fake
16497     Single-int-var-in-ecx/imm32/outputs
16498     0x11/imm32/alloc-id:fake
16499     _string_b9_copy_to_ecx/imm32/subx-name
16500     0/imm32/no-rm32
16501     0/imm32/no-r32
16502     1/imm32/imm32-is-first-inout
16503     0/imm32/no-imm8
16504     0/imm32/no-disp32
16505     1/imm32/output-is-write-only
16506     0x11/imm32/alloc-id:fake
16507     _Primitive-copy-to-edx/imm32/next
16508 _Primitive-copy-to-edx:  # (payload primitive)
16509     0x11/imm32/alloc-id:fake:payload
16510     # var/edx <- copy lit => ba/copy-to-edx lit/imm32
16511     0x11/imm32/alloc-id:fake
16512     _string-copy/imm32/name
16513     0x11/imm32/alloc-id:fake
16514     Single-lit-var/imm32/inouts
16515     0x11/imm32/alloc-id:fake
16516     Single-int-var-in-edx/imm32/outputs
16517     0x11/imm32/alloc-id:fake
16518     _string_ba_copy_to_edx/imm32/subx-name
16519     0/imm32/no-rm32
16520     0/imm32/no-r32
16521     1/imm32/imm32-is-first-inout
16522     0/imm32/no-imm8
16523     0/imm32/no-disp32
16524     1/imm32/output-is-write-only
16525     0x11/imm32/alloc-id:fake
16526     _Primitive-copy-to-ebx/imm32/next
16527 _Primitive-copy-to-ebx:  # (payload primitive)
16528     0x11/imm32/alloc-id:fake:payload
16529     # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32
16530     0x11/imm32/alloc-id:fake
16531     _string-copy/imm32/name
16532     0x11/imm32/alloc-id:fake
16533     Single-lit-var/imm32/inouts
16534     0x11/imm32/alloc-id:fake
16535     Single-int-var-in-ebx/imm32/outputs
16536     0x11/imm32/alloc-id:fake
16537     _string_bb_copy_to_ebx/imm32/subx-name
16538     0/imm32/no-rm32
16539     0/imm32/no-r32
16540     1/imm32/imm32-is-first-inout
16541     0/imm32/no-imm8
16542     0/imm32/no-disp32
16543     1/imm32/output-is-write-only
16544     0x11/imm32/alloc-id:fake
16545     _Primitive-copy-to-esi/imm32/next
16546 _Primitive-copy-to-esi:  # (payload primitive)
16547     0x11/imm32/alloc-id:fake:payload
16548     # var/esi <- copy lit => be/copy-to-esi lit/imm32
16549     0x11/imm32/alloc-id:fake
16550     _string-copy/imm32/name
16551     0x11/imm32/alloc-id:fake
16552     Single-lit-var/imm32/inouts
16553     0x11/imm32/alloc-id:fake
16554     Single-int-var-in-esi/imm32/outputs
16555     0x11/imm32/alloc-id:fake
16556     _string_be_copy_to_esi/imm32/subx-name
16557     0/imm32/no-rm32
16558     0/imm32/no-r32
16559     1/imm32/imm32-is-first-inout
16560     0/imm32/no-imm8
16561     0/imm32/no-disp32
16562     1/imm32/output-is-write-only
16563     0x11/imm32/alloc-id:fake
16564     _Primitive-copy-to-edi/imm32/next
16565 _Primitive-copy-to-edi:  # (payload primitive)
16566     0x11/imm32/alloc-id:fake:payload
16567     # var/edi <- copy lit => bf/copy-to-edi lit/imm32
16568     0x11/imm32/alloc-id:fake
16569     _string-copy/imm32/name
16570     0x11/imm32/alloc-id:fake
16571     Single-lit-var/imm32/inouts
16572     0x11/imm32/alloc-id:fake
16573     Single-int-var-in-edi/imm32/outputs
16574     0x11/imm32/alloc-id:fake
16575     _string_bf_copy_to_edi/imm32/subx-name
16576     0/imm32/no-rm32
16577     0/imm32/no-r32
16578     1/imm32/imm32-is-first-inout
16579     0/imm32/no-imm8
16580     0/imm32/no-disp32
16581     1/imm32/output-is-write-only
16582     0x11/imm32/alloc-id:fake
16583     _Primitive-copy-reg-to-reg/imm32/next
16584 _Primitive-copy-reg-to-reg:  # (payload primitive)
16585     0x11/imm32/alloc-id:fake:payload
16586     # var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32
16587     0x11/imm32/alloc-id:fake
16588     _string-copy/imm32/name
16589     0x11/imm32/alloc-id:fake
16590     Single-int-var-in-some-register/imm32/inouts
16591     0x11/imm32/alloc-id:fake
16592     Single-int-var-in-some-register/imm32/outputs
16593     0x11/imm32/alloc-id:fake
16594     _string_89_<-/imm32/subx-name
16595     3/imm32/rm32-is-first-output
16596     1/imm32/r32-is-first-inout
16597     0/imm32/no-imm32
16598     0/imm32/no-imm8
16599     0/imm32/no-disp32
16600     1/imm32/output-is-write-only
16601     0x11/imm32/alloc-id:fake
16602     _Primitive-copy-reg-to-mem/imm32/next
16603 _Primitive-copy-reg-to-mem:  # (payload primitive)
16604     0x11/imm32/alloc-id:fake:payload
16605     # copy-to var1 var2/reg => 89/<- var1 var2/r32
16606     0x11/imm32/alloc-id:fake
16607     _string-copy-to/imm32/name
16608     0x11/imm32/alloc-id:fake
16609     Two-args-int-stack-int-reg/imm32/inouts
16610     0/imm32/no-outputs
16611     0/imm32/no-outputs
16612     0x11/imm32/alloc-id:fake
16613     _string_89_<-/imm32/subx-name
16614     1/imm32/rm32-is-first-inout
16615     2/imm32/r32-is-second-inout
16616     0/imm32/no-imm32
16617     0/imm32/no-imm8
16618     0/imm32/no-disp32
16619     1/imm32/output-is-write-only
16620     0x11/imm32/alloc-id:fake
16621     _Primitive-copy-mem-to-reg/imm32/next
16622 _Primitive-copy-mem-to-reg:  # (payload primitive)
16623     0x11/imm32/alloc-id:fake:payload
16624     # var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32
16625     0x11/imm32/alloc-id:fake
16626     _string-copy/imm32/name
16627     0x11/imm32/alloc-id:fake
16628     Single-int-var-in-mem/imm32/inouts
16629     0x11/imm32/alloc-id:fake
16630     Single-int-var-in-some-register/imm32/outputs
16631     0x11/imm32/alloc-id:fake
16632     _string_8b_->/imm32/subx-name
16633     1/imm32/rm32-is-first-inout
16634     3/imm32/r32-is-first-output
16635     0/imm32/no-imm32
16636     0/imm32/no-imm8
16637     0/imm32/no-disp32
16638     1/imm32/output-is-write-only
16639     0x11/imm32/alloc-id:fake
16640     _Primitive-copy-lit-to-reg/imm32/next
16641 _Primitive-copy-lit-to-reg:  # (payload primitive)
16642     0x11/imm32/alloc-id:fake:payload
16643     # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32
16644     0x11/imm32/alloc-id:fake
16645     _string-copy/imm32/name
16646     0x11/imm32/alloc-id:fake
16647     Single-lit-var/imm32/inouts
16648     0x11/imm32/alloc-id:fake
16649     Single-int-var-in-some-register/imm32/outputs
16650     0x11/imm32/alloc-id:fake
16651     _string_c7_subop_copy/imm32/subx-name
16652     3/imm32/rm32-is-first-output
16653     0/imm32/no-r32
16654     1/imm32/imm32-is-first-inout
16655     0/imm32/no-imm8
16656     0/imm32/no-disp32
16657     1/imm32/output-is-write-only
16658     0x11/imm32/alloc-id:fake
16659     _Primitive-copy-lit-to-mem/imm32/next
16660 _Primitive-copy-lit-to-mem:  # (payload primitive)
16661     0x11/imm32/alloc-id:fake:payload
16662     # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32
16663     0x11/imm32/alloc-id:fake
16664     _string-copy-to/imm32/name
16665     0x11/imm32/alloc-id:fake
16666     Int-var-and-literal/imm32/inouts
16667     0/imm32/no-outputs
16668     0/imm32/no-outputs
16669     0x11/imm32/alloc-id:fake
16670     _string_c7_subop_copy/imm32/subx-name
16671     1/imm32/rm32-is-first-inout
16672     0/imm32/no-r32
16673     2/imm32/imm32-is-second-inout
16674     0/imm32/no-imm8
16675     0/imm32/no-disp32
16676     1/imm32/output-is-write-only
16677     0x11/imm32/alloc-id:fake
16678     _Primitive-copy-byte-from-reg/imm32/next
16679 # - copy byte
16680 _Primitive-copy-byte-from-reg:
16681     0x11/imm32/alloc-id:fake:payload
16682     # var/reg <- copy-byte var2/reg2 => 8a/byte-> %var2 var/r32
16683     0x11/imm32/alloc-id:fake
16684     _string-copy-byte/imm32/name
16685     0x11/imm32/alloc-id:fake
16686     Single-byte-var-in-some-register/imm32/inouts
16687     0x11/imm32/alloc-id:fake
16688     Single-byte-var-in-some-register/imm32/outputs
16689     0x11/imm32/alloc-id:fake
16690     _string_8a_copy_byte/imm32/subx-name
16691     1/imm32/rm32-is-first-inout
16692     3/imm32/r32-is-first-output
16693     0/imm32/no-imm32
16694     0/imm32/no-imm8
16695     0/imm32/no-disp32
16696     1/imm32/output-is-write-only
16697     0x11/imm32/alloc-id:fake
16698     _Primitive-copy-byte-from-mem/imm32/next
16699 _Primitive-copy-byte-from-mem:
16700     0x11/imm32/alloc-id:fake:payload
16701     # var/reg <- copy-byte *var2/reg2 => 8a/byte-> *var2 var/r32
16702     0x11/imm32/alloc-id:fake
16703     _string-copy-byte/imm32/name
16704     0x11/imm32/alloc-id:fake
16705     Single-byte-var-in-mem/imm32/inouts
16706     0x11/imm32/alloc-id:fake
16707     Single-byte-var-in-some-register/imm32/outputs
16708     0x11/imm32/alloc-id:fake
16709     _string_8a_copy_byte/imm32/subx-name
16710     1/imm32/rm32-is-first-inout
16711     3/imm32/r32-is-first-output
16712     0/imm32/no-imm32
16713     0/imm32/no-imm8
16714     0/imm32/no-disp32
16715     1/imm32/output-is-write-only
16716     0x11/imm32/alloc-id:fake
16717     _Primitive-copy-byte-to-mem/imm32/next
16718 _Primitive-copy-byte-to-mem:
16719     0x11/imm32/alloc-id:fake:payload
16720     # copy-byte-to *var1/reg1, var2/reg2 => 88/byte<- *reg1 reg2/r32
16721     0x11/imm32/alloc-id:fake
16722     _string-copy-byte-to/imm32/name
16723     0x11/imm32/alloc-id:fake
16724     Two-args-byte-stack-byte-reg/imm32/inouts
16725     0/imm32/no-outputs
16726     0/imm32/no-outputs
16727     0x11/imm32/alloc-id:fake
16728     _string_88_copy_byte/imm32/subx-name
16729     1/imm32/rm32-is-first-inout
16730     2/imm32/r32-is-second-inout
16731     0/imm32/no-imm32
16732     0/imm32/no-imm8
16733     0/imm32/no-disp32
16734     0/imm32/output-is-write-only
16735     0x11/imm32/alloc-id:fake
16736     _Primitive-address/imm32/next
16737 # - address
16738 _Primitive-address:  # (payload primitive)
16739     0x11/imm32/alloc-id:fake:payload
16740     # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32
16741     0x11/imm32/alloc-id:fake
16742     _string-address/imm32/name
16743     0x11/imm32/alloc-id:fake
16744     Single-int-var-in-mem/imm32/inouts
16745     0x11/imm32/alloc-id:fake
16746     Single-addr-var-in-some-register/imm32/outputs
16747     0x11/imm32/alloc-id:fake
16748     _string_8d_copy_address/imm32/subx-name
16749     1/imm32/rm32-is-first-inout
16750     3/imm32/r32-is-first-output
16751     0/imm32/no-imm32
16752     0/imm32/no-imm8
16753     0/imm32/no-disp32
16754     1/imm32/output-is-write-only
16755     0x11/imm32/alloc-id:fake
16756     _Primitive-compare-reg-with-reg/imm32/next
16757 # - compare
16758 _Primitive-compare-reg-with-reg:  # (payload primitive)
16759     0x11/imm32/alloc-id:fake:payload
16760     # compare var1/reg1 var2/reg2 => 39/compare var1/rm32 var2/r32
16761     0x11/imm32/alloc-id:fake
16762     _string-compare/imm32/name
16763     0x11/imm32/alloc-id:fake
16764     Two-int-args-in-regs/imm32/inouts
16765     0/imm32/no-outputs
16766     0/imm32/no-outputs
16767     0x11/imm32/alloc-id:fake
16768     _string_39_compare->/imm32/subx-name
16769     1/imm32/rm32-is-first-inout
16770     2/imm32/r32-is-second-inout
16771     0/imm32/no-imm32
16772     0/imm32/no-imm8
16773     0/imm32/no-disp32
16774     0/imm32/output-is-write-only
16775     0x11/imm32/alloc-id:fake
16776     _Primitive-compare-mem-with-reg/imm32/next
16777 _Primitive-compare-mem-with-reg:  # (payload primitive)
16778     0x11/imm32/alloc-id:fake:payload
16779     # compare var1 var2/reg => 39/compare var1/rm32 var2/r32
16780     0x11/imm32/alloc-id:fake
16781     _string-compare/imm32/name
16782     0x11/imm32/alloc-id:fake
16783     Two-args-int-stack-int-reg/imm32/inouts
16784     0/imm32/no-outputs
16785     0/imm32/no-outputs
16786     0x11/imm32/alloc-id:fake
16787     _string_39_compare->/imm32/subx-name
16788     1/imm32/rm32-is-first-inout
16789     2/imm32/r32-is-second-inout
16790     0/imm32/no-imm32
16791     0/imm32/no-imm8
16792     0/imm32/no-disp32
16793     0/imm32/output-is-write-only
16794     0x11/imm32/alloc-id:fake
16795     _Primitive-compare-reg-with-mem/imm32/next
16796 _Primitive-compare-reg-with-mem:  # (payload primitive)
16797     0x11/imm32/alloc-id:fake:payload
16798     # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32
16799     0x11/imm32/alloc-id:fake
16800     _string-compare/imm32/name
16801     0x11/imm32/alloc-id:fake
16802     Two-args-int-reg-int-stack/imm32/inouts
16803     0/imm32/no-outputs
16804     0/imm32/no-outputs
16805     0x11/imm32/alloc-id:fake
16806     _string_3b_compare<-/imm32/subx-name
16807     2/imm32/rm32-is-second-inout
16808     1/imm32/r32-is-first-inout
16809     0/imm32/no-imm32
16810     0/imm32/no-imm8
16811     0/imm32/no-disp32
16812     0/imm32/output-is-write-only
16813     0x11/imm32/alloc-id:fake
16814     _Primitive-compare-eax-with-literal/imm32/next
16815 _Primitive-compare-eax-with-literal:  # (payload primitive)
16816     0x11/imm32/alloc-id:fake:payload
16817     # compare var1/eax n => 3d/compare-eax-with n/imm32
16818     0x11/imm32/alloc-id:fake
16819     _string-compare/imm32/name
16820     0x11/imm32/alloc-id:fake
16821     Two-args-int-eax-int-literal/imm32/inouts
16822     0/imm32/no-outputs
16823     0/imm32/no-outputs
16824     0x11/imm32/alloc-id:fake
16825     _string_3d_compare_eax_with/imm32/subx-name
16826     0/imm32/no-rm32
16827     0/imm32/no-r32
16828     2/imm32/imm32-is-second-inout
16829     0/imm32/no-imm8
16830     0/imm32/no-disp32
16831     0/imm32/output-is-write-only
16832     0x11/imm32/alloc-id:fake
16833     _Primitive-compare-reg-with-literal/imm32/next
16834 _Primitive-compare-reg-with-literal:  # (payload primitive)
16835     0x11/imm32/alloc-id:fake:payload
16836     # compare var1/reg n => 81 7/subop/compare %reg n/imm32
16837     0x11/imm32/alloc-id:fake
16838     _string-compare/imm32/name
16839     0x11/imm32/alloc-id:fake
16840     Int-var-in-register-and-literal/imm32/inouts
16841     0/imm32/no-outputs
16842     0/imm32/no-outputs
16843     0x11/imm32/alloc-id:fake
16844     _string_81_subop_compare/imm32/subx-name
16845     1/imm32/rm32-is-first-inout
16846     0/imm32/no-r32
16847     2/imm32/imm32-is-second-inout
16848     0/imm32/no-imm8
16849     0/imm32/no-disp32
16850     0/imm32/output-is-write-only
16851     0x11/imm32/alloc-id:fake
16852     _Primitive-compare-mem-with-literal/imm32/next
16853 _Primitive-compare-mem-with-literal:  # (payload primitive)
16854     0x11/imm32/alloc-id:fake:payload
16855     # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32
16856     0x11/imm32/alloc-id:fake
16857     _string-compare/imm32/name
16858     0x11/imm32/alloc-id:fake
16859     Int-var-and-literal/imm32/inouts
16860     0/imm32/no-outputs
16861     0/imm32/no-outputs
16862     0x11/imm32/alloc-id:fake
16863     _string_81_subop_compare/imm32/subx-name
16864     1/imm32/rm32-is-first-inout
16865     0/imm32/no-r32
16866     2/imm32/imm32-is-second-inout
16867     0/imm32/no-imm8
16868     0/imm32/no-disp32
16869     0/imm32/output-is-write-only
16870     0x11/imm32/alloc-id:fake
16871     _Primitive-multiply-reg-by-reg/imm32/next
16872 # - multiply
16873 _Primitive-multiply-reg-by-reg:  # (payload primitive)
16874     0x11/imm32/alloc-id:fake:payload
16875     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
16876     0x11/imm32/alloc-id:fake
16877     _string-multiply/imm32/name
16878     0x11/imm32/alloc-id:fake
16879     Single-int-var-in-some-register/imm32/inouts
16880     0x11/imm32/alloc-id:fake
16881     Single-int-var-in-some-register/imm32/outputs
16882     0x11/imm32/alloc-id:fake
16883     _string_0f_af_multiply/imm32/subx-name
16884     1/imm32/rm32-is-first-inout
16885     3/imm32/r32-is-first-output
16886     0/imm32/no-imm32
16887     0/imm32/no-imm8
16888     0/imm32/no-disp32
16889     0/imm32/output-is-write-only
16890     0x11/imm32/alloc-id:fake
16891     _Primitive-multiply-reg-by-mem/imm32/next
16892 _Primitive-multiply-reg-by-mem:  # (payload primitive)
16893     0x11/imm32/alloc-id:fake:payload
16894     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
16895     0x11/imm32/alloc-id:fake
16896     _string-multiply/imm32/name
16897     0x11/imm32/alloc-id:fake
16898     Single-int-var-in-mem/imm32/inouts
16899     0x11/imm32/alloc-id:fake
16900     Single-int-var-in-some-register/imm32/outputs
16901     0x11/imm32/alloc-id:fake
16902     _string_0f_af_multiply/imm32/subx-name
16903     1/imm32/rm32-is-first-inout
16904     3/imm32/r32-is-first-output
16905     0/imm32/no-imm32
16906     0/imm32/no-imm8
16907     0/imm32/no-disp32
16908     0/imm32/output-is-write-only
16909     0x11/imm32/alloc-id:fake
16910     _Primitive-break-if-addr</imm32/next
16911 # - branches
16912 _Primitive-break-if-addr<:  # (payload primitive)
16913     0x11/imm32/alloc-id:fake:payload
16914     0x11/imm32/alloc-id:fake
16915     _string-break-if-addr</imm32/name
16916     0/imm32/no-inouts
16917     0/imm32/no-inouts
16918     0/imm32/no-outputs
16919     0/imm32/no-outputs
16920     0x11/imm32/alloc-id:fake
16921     _string_0f_82_jump_break/imm32/subx-name
16922     0/imm32/no-rm32
16923     0/imm32/no-r32
16924     0/imm32/no-imm32
16925     0/imm32/no-imm8
16926     0/imm32/no-disp32
16927     0/imm32/no-output
16928     0x11/imm32/alloc-id:fake
16929     _Primitive-break-if-addr>=/imm32/next
16930 _Primitive-break-if-addr>=:  # (payload primitive)
16931     0x11/imm32/alloc-id:fake:payload
16932     0x11/imm32/alloc-id:fake
16933     _string-break-if-addr>=/imm32/name
16934     0/imm32/no-inouts
16935     0/imm32/no-inouts
16936     0/imm32/no-outputs
16937     0/imm32/no-outputs
16938     0x11/imm32/alloc-id:fake
16939     _string_0f_83_jump_break/imm32/subx-name
16940     0/imm32/no-rm32
16941     0/imm32/no-r32
16942     0/imm32/no-imm32
16943     0/imm32/no-imm8
16944     0/imm32/no-disp32
16945     0/imm32/no-output
16946     0x11/imm32/alloc-id:fake
16947     _Primitive-break-if-=/imm32/next
16948 _Primitive-break-if-=:  # (payload primitive)
16949     0x11/imm32/alloc-id:fake:payload
16950     0x11/imm32/alloc-id:fake
16951     _string-break-if-=/imm32/name
16952     0/imm32/no-inouts
16953     0/imm32/no-inouts
16954     0/imm32/no-outputs
16955     0/imm32/no-outputs
16956     0x11/imm32/alloc-id:fake
16957     _string_0f_84_jump_break/imm32/subx-name
16958     0/imm32/no-rm32
16959     0/imm32/no-r32
16960     0/imm32/no-imm32
16961     0/imm32/no-imm8
16962     0/imm32/no-disp32
16963     0/imm32/no-output
16964     0x11/imm32/alloc-id:fake
16965     _Primitive-break-if-!=/imm32/next
16966 _Primitive-break-if-!=:  # (payload primitive)
16967     0x11/imm32/alloc-id:fake:payload
16968     0x11/imm32/alloc-id:fake
16969     _string-break-if-!=/imm32/name
16970     0/imm32/no-inouts
16971     0/imm32/no-inouts
16972     0/imm32/no-outputs
16973     0/imm32/no-outputs
16974     0x11/imm32/alloc-id:fake
16975     _string_0f_85_jump_break/imm32/subx-name
16976     0/imm32/no-rm32
16977     0/imm32/no-r32
16978     0/imm32/no-imm32
16979     0/imm32/no-imm8
16980     0/imm32/no-disp32
16981     0/imm32/no-output
16982     0x11/imm32/alloc-id:fake
16983     _Primitive-break-if-addr<=/imm32/next
16984 _Primitive-break-if-addr<=:  # (payload primitive)
16985     0x11/imm32/alloc-id:fake:payload
16986     0x11/imm32/alloc-id:fake
16987     _string-break-if-addr<=/imm32/name
16988     0/imm32/no-inouts
16989     0/imm32/no-inouts
16990     0/imm32/no-outputs
16991     0/imm32/no-outputs
16992     0x11/imm32/alloc-id:fake
16993     _string_0f_86_jump_break/imm32/subx-name
16994     0/imm32/no-rm32
16995     0/imm32/no-r32
16996     0/imm32/no-imm32
16997     0/imm32/no-imm8
16998     0/imm32/no-disp32
16999     0/imm32/no-output
17000     0x11/imm32/alloc-id:fake
17001     _Primitive-break-if-addr>/imm32/next
17002 _Primitive-break-if-addr>:  # (payload primitive)
17003     0x11/imm32/alloc-id:fake:payload
17004     0x11/imm32/alloc-id:fake
17005     _string-break-if-addr>/imm32/name
17006     0/imm32/no-inouts
17007     0/imm32/no-inouts
17008     0/imm32/no-outputs
17009     0/imm32/no-outputs
17010     0x11/imm32/alloc-id:fake
17011     _string_0f_87_jump_break/imm32/subx-name
17012     0/imm32/no-rm32
17013     0/imm32/no-r32
17014     0/imm32/no-imm32
17015     0/imm32/no-imm8
17016     0/imm32/no-disp32
17017     0/imm32/no-output
17018     0x11/imm32/alloc-id:fake
17019     _Primitive-break-if-</imm32/next
17020 _Primitive-break-if-<:  # (payload primitive)
17021     0x11/imm32/alloc-id:fake:payload
17022     0x11/imm32/alloc-id:fake
17023     _string-break-if-</imm32/name
17024     0/imm32/no-inouts
17025     0/imm32/no-inouts
17026     0/imm32/no-outputs
17027     0/imm32/no-outputs
17028     0x11/imm32/alloc-id:fake
17029     _string_0f_8c_jump_break/imm32/subx-name
17030     0/imm32/no-rm32
17031     0/imm32/no-r32
17032     0/imm32/no-imm32
17033     0/imm32/no-imm8
17034     0/imm32/no-disp32
17035     0/imm32/no-output
17036     0x11/imm32/alloc-id:fake
17037     _Primitive-break-if->=/imm32/next
17038 _Primitive-break-if->=:  # (payload primitive)
17039     0x11/imm32/alloc-id:fake:payload
17040     0x11/imm32/alloc-id:fake
17041     _string-break-if->=/imm32/name
17042     0/imm32/no-inouts
17043     0/imm32/no-inouts
17044     0/imm32/no-outputs
17045     0/imm32/no-outputs
17046     0x11/imm32/alloc-id:fake
17047     _string_0f_8d_jump_break/imm32/subx-name
17048     0/imm32/no-rm32
17049     0/imm32/no-r32
17050     0/imm32/no-imm32
17051     0/imm32/no-imm8
17052     0/imm32/no-disp32
17053     0/imm32/no-output
17054     0x11/imm32/alloc-id:fake
17055     _Primitive-break-if-<=/imm32/next
17056 _Primitive-break-if-<=:  # (payload primitive)
17057     0x11/imm32/alloc-id:fake:payload
17058     0x11/imm32/alloc-id:fake
17059     _string-break-if-<=/imm32/name
17060     0/imm32/no-inouts
17061     0/imm32/no-inouts
17062     0/imm32/no-outputs
17063     0/imm32/no-outputs
17064     0x11/imm32/alloc-id:fake
17065     _string_0f_8e_jump_break/imm32/subx-name
17066     0/imm32/no-rm32
17067     0/imm32/no-r32
17068     0/imm32/no-imm32
17069     0/imm32/no-imm8
17070     0/imm32/no-disp32
17071     0/imm32/no-output
17072     0x11/imm32/alloc-id:fake
17073     _Primitive-break-if->/imm32/next
17074 _Primitive-break-if->:  # (payload primitive)
17075     0x11/imm32/alloc-id:fake:payload
17076     0x11/imm32/alloc-id:fake
17077     _string-break-if->/imm32/name
17078     0/imm32/no-inouts
17079     0/imm32/no-inouts
17080     0/imm32/no-outputs
17081     0/imm32/no-outputs
17082     0x11/imm32/alloc-id:fake
17083     _string_0f_8f_jump_break/imm32/subx-name
17084     0/imm32/no-rm32
17085     0/imm32/no-r32
17086     0/imm32/no-imm32
17087     0/imm32/no-imm8
17088     0/imm32/no-disp32
17089     0/imm32/no-output
17090     0x11/imm32/alloc-id:fake
17091     _Primitive-break/imm32/next
17092 _Primitive-break:  # (payload primitive)
17093     0x11/imm32/alloc-id:fake:payload
17094     0x11/imm32/alloc-id:fake
17095     _string-break/imm32/name
17096     0/imm32/no-inouts
17097     0/imm32/no-inouts
17098     0/imm32/no-outputs
17099     0/imm32/no-outputs
17100     0x11/imm32/alloc-id:fake
17101     _string_e9_jump_break/imm32/subx-name
17102     0/imm32/no-rm32
17103     0/imm32/no-r32
17104     0/imm32/no-imm32
17105     0/imm32/no-imm8
17106     0/imm32/no-disp32
17107     0/imm32/no-output
17108     0x11/imm32/alloc-id:fake
17109     _Primitive-loop-if-addr</imm32/next
17110 _Primitive-loop-if-addr<:  # (payload primitive)
17111     0x11/imm32/alloc-id:fake:payload
17112     0x11/imm32/alloc-id:fake
17113     _string-loop-if-addr</imm32/name
17114     0/imm32/no-inouts
17115     0/imm32/no-inouts
17116     0/imm32/no-outputs
17117     0/imm32/no-outputs
17118     0x11/imm32/alloc-id:fake
17119     _string_0f_82_jump_loop/imm32/subx-name
17120     0/imm32/no-rm32
17121     0/imm32/no-r32
17122     0/imm32/no-imm32
17123     0/imm32/no-imm8
17124     0/imm32/no-disp32
17125     0/imm32/no-output
17126     0x11/imm32/alloc-id:fake
17127     _Primitive-loop-if-addr>=/imm32/next
17128 _Primitive-loop-if-addr>=:  # (payload primitive)
17129     0x11/imm32/alloc-id:fake:payload
17130     0x11/imm32/alloc-id:fake
17131     _string-loop-if-addr>=/imm32/name
17132     0/imm32/no-inouts
17133     0/imm32/no-inouts
17134     0/imm32/no-outputs
17135     0/imm32/no-outputs
17136     0x11/imm32/alloc-id:fake
17137     _string_0f_83_jump_loop/imm32/subx-name
17138     0/imm32/no-rm32
17139     0/imm32/no-r32
17140     0/imm32/no-imm32
17141     0/imm32/no-imm8
17142     0/imm32/no-disp32
17143     0/imm32/no-output
17144     0x11/imm32/alloc-id:fake
17145     _Primitive-loop-if-=/imm32/next
17146 _Primitive-loop-if-=:  # (payload primitive)
17147     0x11/imm32/alloc-id:fake:payload
17148     0x11/imm32/alloc-id:fake
17149     _string-loop-if-=/imm32/name
17150     0/imm32/no-inouts
17151     0/imm32/no-inouts
17152     0/imm32/no-outputs
17153     0/imm32/no-outputs
17154     0x11/imm32/alloc-id:fake
17155     _string_0f_84_jump_loop/imm32/subx-name
17156     0/imm32/no-rm32
17157     0/imm32/no-r32
17158     0/imm32/no-imm32
17159     0/imm32/no-imm8
17160     0/imm32/no-disp32
17161     0/imm32/no-output
17162     0x11/imm32/alloc-id:fake
17163     _Primitive-loop-if-!=/imm32/next
17164 _Primitive-loop-if-!=:  # (payload primitive)
17165     0x11/imm32/alloc-id:fake:payload
17166     0x11/imm32/alloc-id:fake
17167     _string-loop-if-!=/imm32/name
17168     0/imm32/no-inouts
17169     0/imm32/no-inouts
17170     0/imm32/no-outputs
17171     0/imm32/no-outputs
17172     0x11/imm32/alloc-id:fake
17173     _string_0f_85_jump_loop/imm32/subx-name
17174     0/imm32/no-rm32
17175     0/imm32/no-r32
17176     0/imm32/no-imm32
17177     0/imm32/no-imm8
17178     0/imm32/no-disp32
17179     0/imm32/no-output
17180     0x11/imm32/alloc-id:fake
17181     _Primitive-loop-if-addr<=/imm32/next
17182 _Primitive-loop-if-addr<=:  # (payload primitive)
17183     0x11/imm32/alloc-id:fake:payload
17184     0x11/imm32/alloc-id:fake
17185     _string-loop-if-addr<=/imm32/name
17186     0/imm32/no-inouts
17187     0/imm32/no-inouts
17188     0/imm32/no-outputs
17189     0/imm32/no-outputs
17190     0x11/imm32/alloc-id:fake
17191     _string_0f_86_jump_loop/imm32/subx-name
17192     0/imm32/no-rm32
17193     0/imm32/no-r32
17194     0/imm32/no-imm32
17195     0/imm32/no-imm8
17196     0/imm32/no-disp32
17197     0/imm32/no-output
17198     0x11/imm32/alloc-id:fake
17199     _Primitive-loop-if-addr>/imm32/next
17200 _Primitive-loop-if-addr>:  # (payload primitive)
17201     0x11/imm32/alloc-id:fake:payload
17202     0x11/imm32/alloc-id:fake
17203     _string-loop-if-addr>/imm32/name
17204     0/imm32/no-inouts
17205     0/imm32/no-inouts
17206     0/imm32/no-outputs
17207     0/imm32/no-outputs
17208     0x11/imm32/alloc-id:fake
17209     _string_0f_87_jump_loop/imm32/subx-name
17210     0/imm32/no-rm32
17211     0/imm32/no-r32
17212     0/imm32/no-imm32
17213     0/imm32/no-imm8
17214     0/imm32/no-disp32
17215     0/imm32/no-output
17216     0x11/imm32/alloc-id:fake
17217     _Primitive-loop-if-</imm32/next
17218 _Primitive-loop-if-<:  # (payload primitive)
17219     0x11/imm32/alloc-id:fake:payload
17220     0x11/imm32/alloc-id:fake
17221     _string-loop-if-</imm32/name
17222     0/imm32/no-inouts
17223     0/imm32/no-inouts
17224     0/imm32/no-outputs
17225     0/imm32/no-outputs
17226     0x11/imm32/alloc-id:fake
17227     _string_0f_8c_jump_loop/imm32/subx-name
17228     0/imm32/no-rm32
17229     0/imm32/no-r32
17230     0/imm32/no-imm32
17231     0/imm32/no-imm8
17232     0/imm32/no-disp32
17233     0/imm32/no-output
17234     0x11/imm32/alloc-id:fake
17235     _Primitive-loop-if->=/imm32/next
17236 _Primitive-loop-if->=:  # (payload primitive)
17237     0x11/imm32/alloc-id:fake:payload
17238     0x11/imm32/alloc-id:fake
17239     _string-loop-if->=/imm32/name
17240     0/imm32/no-inouts
17241     0/imm32/no-inouts
17242     0/imm32/no-outputs
17243     0/imm32/no-outputs
17244     0x11/imm32/alloc-id:fake
17245     _string_0f_8d_jump_loop/imm32/subx-name
17246     0/imm32/no-rm32
17247     0/imm32/no-r32
17248     0/imm32/no-imm32
17249     0/imm32/no-imm8
17250     0/imm32/no-disp32
17251     0/imm32/no-output
17252     0x11/imm32/alloc-id:fake
17253     _Primitive-loop-if-<=/imm32/next
17254 _Primitive-loop-if-<=:  # (payload primitive)
17255     0x11/imm32/alloc-id:fake:payload
17256     0x11/imm32/alloc-id:fake
17257     _string-loop-if-<=/imm32/name
17258     0/imm32/no-inouts
17259     0/imm32/no-inouts
17260     0/imm32/no-outputs
17261     0/imm32/no-outputs
17262     0x11/imm32/alloc-id:fake
17263     _string_0f_8e_jump_loop/imm32/subx-name
17264     0/imm32/no-rm32
17265     0/imm32/no-r32
17266     0/imm32/no-imm32
17267     0/imm32/no-imm8
17268     0/imm32/no-disp32
17269     0/imm32/no-output
17270     0x11/imm32/alloc-id:fake
17271     _Primitive-loop-if->/imm32/next
17272 _Primitive-loop-if->:  # (payload primitive)
17273     0x11/imm32/alloc-id:fake:payload
17274     0x11/imm32/alloc-id:fake
17275     _string-loop-if->/imm32/name
17276     0/imm32/no-inouts
17277     0/imm32/no-inouts
17278     0/imm32/no-outputs
17279     0/imm32/no-outputs
17280     0x11/imm32/alloc-id:fake
17281     _string_0f_8f_jump_loop/imm32/subx-name
17282     0/imm32/no-rm32
17283     0/imm32/no-r32
17284     0/imm32/no-imm32
17285     0/imm32/no-imm8
17286     0/imm32/no-disp32
17287     0/imm32/no-output
17288     0x11/imm32/alloc-id:fake
17289     _Primitive-loop/imm32/next  # we probably don't need an unconditional break
17290 _Primitive-loop:  # (payload primitive)
17291     0x11/imm32/alloc-id:fake:payload
17292     0x11/imm32/alloc-id:fake
17293     _string-loop/imm32/name
17294     0/imm32/no-inouts
17295     0/imm32/no-inouts
17296     0/imm32/no-outputs
17297     0/imm32/no-outputs
17298     0x11/imm32/alloc-id:fake
17299     _string_e9_jump_loop/imm32/subx-name
17300     0/imm32/no-rm32
17301     0/imm32/no-r32
17302     0/imm32/no-imm32
17303     0/imm32/no-imm8
17304     0/imm32/no-disp32
17305     0/imm32/no-output
17306     0x11/imm32/alloc-id:fake
17307     _Primitive-break-if-addr<-named/imm32/next
17308 # - branches to named blocks
17309 _Primitive-break-if-addr<-named:  # (payload primitive)
17310     0x11/imm32/alloc-id:fake:payload
17311     0x11/imm32/alloc-id:fake
17312     _string-break-if-addr</imm32/name
17313     0x11/imm32/alloc-id:fake
17314     Single-lit-var/imm32/inouts
17315     0/imm32/no-outputs
17316     0/imm32/no-outputs
17317     0x11/imm32/alloc-id:fake
17318     _string_0f_82_jump_label/imm32/subx-name
17319     0/imm32/no-rm32
17320     0/imm32/no-r32
17321     0/imm32/no-imm32
17322     0/imm32/no-imm8
17323     1/imm32/disp32-is-first-inout
17324     0/imm32/no-output
17325     0x11/imm32/alloc-id:fake
17326     _Primitive-break-if-addr>=-named/imm32/next
17327 _Primitive-break-if-addr>=-named:  # (payload primitive)
17328     0x11/imm32/alloc-id:fake:payload
17329     0x11/imm32/alloc-id:fake
17330     _string-break-if-addr>=/imm32/name
17331     0x11/imm32/alloc-id:fake
17332     Single-lit-var/imm32/inouts
17333     0/imm32/no-outputs
17334     0/imm32/no-outputs
17335     0x11/imm32/alloc-id:fake
17336     _string_0f_83_jump_label/imm32/subx-name
17337     0/imm32/no-rm32
17338     0/imm32/no-r32
17339     0/imm32/no-imm32
17340     0/imm32/no-imm8
17341     1/imm32/disp32-is-first-inout
17342     0/imm32/no-output
17343     0x11/imm32/alloc-id:fake
17344     _Primitive-break-if-=-named/imm32/next
17345 _Primitive-break-if-=-named:  # (payload primitive)
17346     0x11/imm32/alloc-id:fake:payload
17347     0x11/imm32/alloc-id:fake
17348     _string-break-if-=/imm32/name
17349     0x11/imm32/alloc-id:fake
17350     Single-lit-var/imm32/inouts
17351     0/imm32/no-outputs
17352     0/imm32/no-outputs
17353     0x11/imm32/alloc-id:fake
17354     _string_0f_84_jump_label/imm32/subx-name
17355     0/imm32/no-rm32
17356     0/imm32/no-r32
17357     0/imm32/no-imm32
17358     0/imm32/no-imm8
17359     1/imm32/disp32-is-first-inout
17360     0/imm32/no-output
17361     0x11/imm32/alloc-id:fake
17362     _Primitive-break-if-!=-named/imm32/next
17363 _Primitive-break-if-!=-named:  # (payload primitive)
17364     0x11/imm32/alloc-id:fake:payload
17365     0x11/imm32/alloc-id:fake
17366     _string-break-if-!=/imm32/name
17367     0x11/imm32/alloc-id:fake
17368     Single-lit-var/imm32/inouts
17369     0/imm32/no-outputs
17370     0/imm32/no-outputs
17371     0x11/imm32/alloc-id:fake
17372     _string_0f_85_jump_label/imm32/subx-name
17373     0/imm32/no-rm32
17374     0/imm32/no-r32
17375     0/imm32/no-imm32
17376     0/imm32/no-imm8
17377     1/imm32/disp32-is-first-inout
17378     0/imm32/no-output
17379     0x11/imm32/alloc-id:fake
17380     _Primitive-break-if-addr<=-named/imm32/next
17381 _Primitive-break-if-addr<=-named:  # (payload primitive)
17382     0x11/imm32/alloc-id:fake:payload
17383     0x11/imm32/alloc-id:fake
17384     _string-break-if-addr<=/imm32/name
17385     0x11/imm32/alloc-id:fake
17386     Single-lit-var/imm32/inouts
17387     0/imm32/no-outputs
17388     0/imm32/no-outputs
17389     0x11/imm32/alloc-id:fake
17390     _string_0f_86_jump_label/imm32/subx-name
17391     0/imm32/no-rm32
17392     0/imm32/no-r32
17393     0/imm32/no-imm32
17394     0/imm32/no-imm8
17395     1/imm32/disp32-is-first-inout
17396     0/imm32/no-output
17397     0x11/imm32/alloc-id:fake
17398     _Primitive-break-if-addr>-named/imm32/next
17399 _Primitive-break-if-addr>-named:  # (payload primitive)
17400     0x11/imm32/alloc-id:fake:payload
17401     0x11/imm32/alloc-id:fake
17402     _string-break-if-addr>/imm32/name
17403     0x11/imm32/alloc-id:fake
17404     Single-lit-var/imm32/inouts
17405     0/imm32/no-outputs
17406     0/imm32/no-outputs
17407     0x11/imm32/alloc-id:fake
17408     _string_0f_87_jump_label/imm32/subx-name
17409     0/imm32/no-rm32
17410     0/imm32/no-r32
17411     0/imm32/no-imm32
17412     0/imm32/no-imm8
17413     1/imm32/disp32-is-first-inout
17414     0/imm32/no-output
17415     0x11/imm32/alloc-id:fake
17416     _Primitive-break-if-<-named/imm32/next
17417 _Primitive-break-if-<-named:  # (payload primitive)
17418     0x11/imm32/alloc-id:fake:payload
17419     0x11/imm32/alloc-id:fake
17420     _string-break-if-</imm32/name
17421     0x11/imm32/alloc-id:fake
17422     Single-lit-var/imm32/inouts
17423     0/imm32/no-outputs
17424     0/imm32/no-outputs
17425     0x11/imm32/alloc-id:fake
17426     _string_0f_8c_jump_label/imm32/subx-name
17427     0/imm32/no-rm32
17428     0/imm32/no-r32
17429     0/imm32/no-imm32
17430     0/imm32/no-imm8
17431     1/imm32/disp32-is-first-inout
17432     0/imm32/no-output
17433     0x11/imm32/alloc-id:fake
17434     _Primitive-break-if->=-named/imm32/next
17435 _Primitive-break-if->=-named:  # (payload primitive)
17436     0x11/imm32/alloc-id:fake:payload
17437     0x11/imm32/alloc-id:fake
17438     _string-break-if->=/imm32/name
17439     0x11/imm32/alloc-id:fake
17440     Single-lit-var/imm32/inouts
17441     0/imm32/no-outputs
17442     0/imm32/no-outputs
17443     0x11/imm32/alloc-id:fake
17444     _string_0f_8d_jump_label/imm32/subx-name
17445     0/imm32/no-rm32
17446     0/imm32/no-r32
17447     0/imm32/no-imm32
17448     0/imm32/no-imm8
17449     1/imm32/disp32-is-first-inout
17450     0/imm32/no-output
17451     0x11/imm32/alloc-id:fake
17452     _Primitive-break-if-<=-named/imm32/next
17453 _Primitive-break-if-<=-named:  # (payload primitive)
17454     0x11/imm32/alloc-id:fake:payload
17455     0x11/imm32/alloc-id:fake
17456     _string-break-if-<=/imm32/name
17457     0x11/imm32/alloc-id:fake
17458     Single-lit-var/imm32/inouts
17459     0/imm32/no-outputs
17460     0/imm32/no-outputs
17461     0x11/imm32/alloc-id:fake
17462     _string_0f_8e_jump_label/imm32/subx-name
17463     0/imm32/no-rm32
17464     0/imm32/no-r32
17465     0/imm32/no-imm32
17466     0/imm32/no-imm8
17467     1/imm32/disp32-is-first-inout
17468     0/imm32/no-output
17469     0x11/imm32/alloc-id:fake
17470     _Primitive-break-if->-named/imm32/next
17471 _Primitive-break-if->-named:  # (payload primitive)
17472     0x11/imm32/alloc-id:fake:payload
17473     0x11/imm32/alloc-id:fake
17474     _string-break-if->/imm32/name
17475     0x11/imm32/alloc-id:fake
17476     Single-lit-var/imm32/inouts
17477     0/imm32/no-outputs
17478     0/imm32/no-outputs
17479     0x11/imm32/alloc-id:fake
17480     _string_0f_8f_jump_label/imm32/subx-name
17481     0/imm32/no-rm32
17482     0/imm32/no-r32
17483     0/imm32/no-imm32
17484     0/imm32/no-imm8
17485     1/imm32/disp32-is-first-inout
17486     0/imm32/no-output
17487     0x11/imm32/alloc-id:fake
17488     _Primitive-break-named/imm32/next
17489 _Primitive-break-named:  # (payload primitive)
17490     0x11/imm32/alloc-id:fake:payload
17491     0x11/imm32/alloc-id:fake
17492     _string-break/imm32/name
17493     0x11/imm32/alloc-id:fake
17494     Single-lit-var/imm32/inouts
17495     0/imm32/no-outputs
17496     0/imm32/no-outputs
17497     0x11/imm32/alloc-id:fake
17498     _string_e9_jump_label/imm32/subx-name
17499     0/imm32/no-rm32
17500     0/imm32/no-r32
17501     0/imm32/no-imm32
17502     0/imm32/no-imm8
17503     1/imm32/disp32-is-first-inout
17504     0/imm32/no-output
17505     0x11/imm32/alloc-id:fake
17506     _Primitive-loop-if-addr<-named/imm32/next
17507 _Primitive-loop-if-addr<-named:  # (payload primitive)
17508     0x11/imm32/alloc-id:fake:payload
17509     0x11/imm32/alloc-id:fake
17510     _string-loop-if-addr</imm32/name
17511     0x11/imm32/alloc-id:fake
17512     Single-lit-var/imm32/inouts
17513     0/imm32/no-outputs
17514     0/imm32/no-outputs
17515     0x11/imm32/alloc-id:fake
17516     _string_0f_82_jump_label/imm32/subx-name
17517     0/imm32/no-rm32
17518     0/imm32/no-r32
17519     0/imm32/no-imm32
17520     0/imm32/no-imm8
17521     1/imm32/disp32-is-first-inout
17522     0/imm32/no-output
17523     0x11/imm32/alloc-id:fake
17524     _Primitive-loop-if-addr>=-named/imm32/next
17525 _Primitive-loop-if-addr>=-named:  # (payload primitive)
17526     0x11/imm32/alloc-id:fake:payload
17527     0x11/imm32/alloc-id:fake
17528     _string-loop-if-addr>=/imm32/name
17529     0x11/imm32/alloc-id:fake
17530     Single-lit-var/imm32/inouts
17531     0/imm32/no-outputs
17532     0/imm32/no-outputs
17533     0x11/imm32/alloc-id:fake
17534     _string_0f_83_jump_label/imm32/subx-name
17535     0/imm32/no-rm32
17536     0/imm32/no-r32
17537     0/imm32/no-imm32
17538     0/imm32/no-imm8
17539     1/imm32/disp32-is-first-inout
17540     0/imm32/no-output
17541     0x11/imm32/alloc-id:fake
17542     _Primitive-loop-if-=-named/imm32/next
17543 _Primitive-loop-if-=-named:  # (payload primitive)
17544     0x11/imm32/alloc-id:fake:payload
17545     0x11/imm32/alloc-id:fake
17546     _string-loop-if-=/imm32/name
17547     0x11/imm32/alloc-id:fake
17548     Single-lit-var/imm32/inouts
17549     0/imm32/no-outputs
17550     0/imm32/no-outputs
17551     0x11/imm32/alloc-id:fake
17552     _string_0f_84_jump_label/imm32/subx-name
17553     0/imm32/no-rm32
17554     0/imm32/no-r32
17555     0/imm32/no-imm32
17556     0/imm32/no-imm8
17557     1/imm32/disp32-is-first-inout
17558     0/imm32/no-output
17559     0x11/imm32/alloc-id:fake
17560     _Primitive-loop-if-!=-named/imm32/next
17561 _Primitive-loop-if-!=-named:  # (payload primitive)
17562     0x11/imm32/alloc-id:fake:payload
17563     0x11/imm32/alloc-id:fake
17564     _string-loop-if-!=/imm32/name
17565     0x11/imm32/alloc-id:fake
17566     Single-lit-var/imm32/inouts
17567     0/imm32/no-outputs
17568     0/imm32/no-outputs
17569     0x11/imm32/alloc-id:fake
17570     _string_0f_85_jump_label/imm32/subx-name
17571     0/imm32/no-rm32
17572     0/imm32/no-r32
17573     0/imm32/no-imm32
17574     0/imm32/no-imm8
17575     1/imm32/disp32-is-first-inout
17576     0/imm32/no-output
17577     0x11/imm32/alloc-id:fake
17578     _Primitive-loop-if-addr<=-named/imm32/next
17579 _Primitive-loop-if-addr<=-named:  # (payload primitive)
17580     0x11/imm32/alloc-id:fake:payload
17581     0x11/imm32/alloc-id:fake
17582     _string-loop-if-addr<=/imm32/name
17583     0x11/imm32/alloc-id:fake
17584     Single-lit-var/imm32/inouts
17585     0/imm32/no-outputs
17586     0/imm32/no-outputs
17587     0x11/imm32/alloc-id:fake
17588     _string_0f_86_jump_label/imm32/subx-name
17589     0/imm32/no-rm32
17590     0/imm32/no-r32
17591     0/imm32/no-imm32
17592     0/imm32/no-imm8
17593     1/imm32/disp32-is-first-inout
17594     0/imm32/no-output
17595     0x11/imm32/alloc-id:fake
17596     _Primitive-loop-if-addr>-named/imm32/next
17597 _Primitive-loop-if-addr>-named:  # (payload primitive)
17598     0x11/imm32/alloc-id:fake:payload
17599     0x11/imm32/alloc-id:fake
17600     _string-loop-if-addr>/imm32/name
17601     0x11/imm32/alloc-id:fake
17602     Single-lit-var/imm32/inouts
17603     0/imm32/no-outputs
17604     0/imm32/no-outputs
17605     0x11/imm32/alloc-id:fake
17606     _string_0f_87_jump_label/imm32/subx-name
17607     0/imm32/no-rm32
17608     0/imm32/no-r32
17609     0/imm32/no-imm32
17610     0/imm32/no-imm8
17611     1/imm32/disp32-is-first-inout
17612     0/imm32/no-output
17613     0x11/imm32/alloc-id:fake
17614     _Primitive-loop-if-<-named/imm32/next
17615 _Primitive-loop-if-<-named:  # (payload primitive)
17616     0x11/imm32/alloc-id:fake:payload
17617     0x11/imm32/alloc-id:fake
17618     _string-loop-if-</imm32/name
17619     0x11/imm32/alloc-id:fake
17620     Single-lit-var/imm32/inouts
17621     0/imm32/no-outputs
17622     0/imm32/no-outputs
17623     0x11/imm32/alloc-id:fake
17624     _string_0f_8c_jump_label/imm32/subx-name
17625     0/imm32/no-rm32
17626     0/imm32/no-r32
17627     0/imm32/no-imm32
17628     0/imm32/no-imm8
17629     1/imm32/disp32-is-first-inout
17630     0/imm32/no-output
17631     0x11/imm32/alloc-id:fake
17632     _Primitive-loop-if->=-named/imm32/next
17633 _Primitive-loop-if->=-named:  # (payload primitive)
17634     0x11/imm32/alloc-id:fake:payload
17635     0x11/imm32/alloc-id:fake
17636     _string-loop-if->=/imm32/name
17637     0x11/imm32/alloc-id:fake
17638     Single-lit-var/imm32/inouts
17639     0/imm32/no-outputs
17640     0/imm32/no-outputs
17641     0x11/imm32/alloc-id:fake
17642     _string_0f_8d_jump_label/imm32/subx-name
17643     0/imm32/no-rm32
17644     0/imm32/no-r32
17645     0/imm32/no-imm32
17646     0/imm32/no-imm8
17647     1/imm32/disp32-is-first-inout
17648     0/imm32/no-output
17649     0x11/imm32/alloc-id:fake
17650     _Primitive-loop-if-<=-named/imm32/next
17651 _Primitive-loop-if-<=-named:  # (payload primitive)
17652     0x11/imm32/alloc-id:fake:payload
17653     0x11/imm32/alloc-id:fake
17654     _string-loop-if-<=/imm32/name
17655     0x11/imm32/alloc-id:fake
17656     Single-lit-var/imm32/inouts
17657     0/imm32/no-outputs
17658     0/imm32/no-outputs
17659     0x11/imm32/alloc-id:fake
17660     _string_0f_8e_jump_label/imm32/subx-name
17661     0/imm32/no-rm32
17662     0/imm32/no-r32
17663     0/imm32/no-imm32
17664     0/imm32/no-imm8
17665     1/imm32/disp32-is-first-inout
17666     0/imm32/no-output
17667     0x11/imm32/alloc-id:fake
17668     _Primitive-loop-if->-named/imm32/next
17669 _Primitive-loop-if->-named:  # (payload primitive)
17670     0x11/imm32/alloc-id:fake:payload
17671     0x11/imm32/alloc-id:fake
17672     _string-loop-if->/imm32/name
17673     0x11/imm32/alloc-id:fake
17674     Single-lit-var/imm32/inouts
17675     0/imm32/no-outputs
17676     0/imm32/no-outputs
17677     0x11/imm32/alloc-id:fake
17678     _string_0f_8f_jump_label/imm32/subx-name
17679     0/imm32/no-rm32
17680     0/imm32/no-r32
17681     0/imm32/no-imm32
17682     0/imm32/no-imm8
17683     1/imm32/disp32-is-first-inout
17684     0/imm32/no-output
17685     0x11/imm32/alloc-id:fake
17686     _Primitive-loop-named/imm32/next  # we probably don't need an unconditional break
17687 _Primitive-loop-named:  # (payload primitive)
17688     0x11/imm32/alloc-id:fake:payload
17689     0x11/imm32/alloc-id:fake
17690     _string-loop/imm32/name
17691     0x11/imm32/alloc-id:fake
17692     Single-lit-var/imm32/inouts
17693     0/imm32/no-outputs
17694     0/imm32/no-outputs
17695     0x11/imm32/alloc-id:fake
17696     _string_e9_jump_label/imm32/subx-name
17697     0/imm32/no-rm32
17698     0/imm32/no-r32
17699     0/imm32/no-imm32
17700     0/imm32/no-imm8
17701     1/imm32/disp32-is-first-inout
17702     0/imm32/no-output
17703     0/imm32/next
17704     0/imm32/next
17705 
17706 # string literals for Mu instructions
17707 _string-add:  # (payload array byte)
17708     0x11/imm32/alloc-id:fake:payload
17709     # "add"
17710     0x3/imm32/size
17711     0x61/a 0x64/d 0x64/d
17712 _string-address:  # (payload array byte)
17713     0x11/imm32/alloc-id:fake:payload
17714     # "address"
17715     0x7/imm32/size
17716     0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
17717 _string-add-to:  # (payload array byte)
17718     0x11/imm32/alloc-id:fake:payload
17719     # "add-to"
17720     0x6/imm32/size
17721     0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
17722 _string-and:  # (payload array byte)
17723     0x11/imm32/alloc-id:fake:payload
17724     # "and"
17725     0x3/imm32/size
17726     0x61/a 0x6e/n 0x64/d
17727 _string-and-with:  # (payload array byte)
17728     0x11/imm32/alloc-id:fake:payload
17729     # "and-with"
17730     0x8/imm32/size
17731     0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
17732 _string-break:  # (payload array byte)
17733     0x11/imm32/alloc-id:fake:payload
17734     # "break"
17735     0x5/imm32/size
17736     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k
17737 _string-break-if-<:  # (payload array byte)
17738     0x11/imm32/alloc-id:fake:payload
17739     # "break-if-<"
17740     0xa/imm32/size
17741     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
17742 _string-break-if-<=:  # (payload array byte)
17743     0x11/imm32/alloc-id:fake:payload
17744     # "break-if-<="
17745     0xb/imm32/size
17746     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
17747 _string-break-if-=:  # (payload array byte)
17748     0x11/imm32/alloc-id:fake:payload
17749     # "break-if-="
17750     0xa/imm32/size
17751     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
17752 _string-break-if->:  # (payload array byte)
17753     0x11/imm32/alloc-id:fake:payload
17754     # "break-if->"
17755     0xa/imm32/size
17756     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
17757 _string-break-if->=:  # (payload array byte)
17758     0x11/imm32/alloc-id:fake:payload
17759     # "break-if->="
17760     0xb/imm32/size
17761     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
17762 _string-break-if-!=:  # (payload array byte)
17763     0x11/imm32/alloc-id:fake:payload
17764     # "break-if-!="
17765     0xb/imm32/size
17766     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
17767 _string-break-if-addr<:  # (payload array byte)
17768     0x11/imm32/alloc-id:fake:payload
17769     # "break-if-addr<"
17770     0xe/imm32/size
17771     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/<
17772 _string-break-if-addr<=:  # (payload array byte)
17773     0x11/imm32/alloc-id:fake:payload
17774     # "break-if-addr<="
17775     0xf/imm32/size
17776     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/=
17777 _string-break-if-addr>:  # (payload array byte)
17778     0x11/imm32/alloc-id:fake:payload
17779     # "break-if-addr>"
17780     0xe/imm32/size
17781     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/>
17782 _string-break-if-addr>=:  # (payload array byte)
17783     0x11/imm32/alloc-id:fake:payload
17784     # "break-if-addr>="
17785     0xf/imm32/size
17786     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/=
17787 _string-compare:  # (payload array byte)
17788     0x11/imm32/alloc-id:fake:payload
17789     # "compare"
17790     0x7/imm32/size
17791     0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
17792 _string-copy:  # (payload array byte)
17793     0x11/imm32/alloc-id:fake:payload
17794     # "copy"
17795     0x4/imm32/size
17796     0x63/c 0x6f/o 0x70/p 0x79/y
17797 _string-copy-to:  # (payload array byte)
17798     0x11/imm32/alloc-id:fake:payload
17799     # "copy-to"
17800     0x7/imm32/size
17801     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o
17802 _string-copy-byte:
17803     0x11/imm32/alloc-id:fake:payload
17804     # "copy-byte"
17805     0x9/imm32/size
17806     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e
17807 _string-copy-byte-to:
17808     0x11/imm32/alloc-id:fake:payload
17809     # "copy-byte-to"
17810     0xc/imm32/size
17811     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x74/t 0x6f/o
17812 _string-decrement:  # (payload array byte)
17813     0x11/imm32/alloc-id:fake:payload
17814     # "decrement"
17815     0x9/imm32/size
17816     0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
17817 _string-increment:  # (payload array byte)
17818     0x11/imm32/alloc-id:fake:payload
17819     # "increment"
17820     0x9/imm32/size
17821     0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
17822 _string-loop:  # (payload array byte)
17823     0x11/imm32/alloc-id:fake:payload
17824     # "loop"
17825     0x4/imm32/size
17826     0x6c/l 0x6f/o 0x6f/o 0x70/p
17827 _string-loop-if-<:  # (payload array byte)
17828     0x11/imm32/alloc-id:fake:payload
17829     # "loop-if-<"
17830     0x9/imm32/size
17831     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
17832 _string-loop-if-<=:  # (payload array byte)
17833     0x11/imm32/alloc-id:fake:payload
17834     # "loop-if-<="
17835     0xa/imm32/size
17836     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
17837 _string-loop-if-=:  # (payload array byte)
17838     0x11/imm32/alloc-id:fake:payload
17839     # "loop-if-="
17840     0x9/imm32/size
17841     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
17842 _string-loop-if->:  # (payload array byte)
17843     0x11/imm32/alloc-id:fake:payload
17844     # "loop-if->"
17845     0x9/imm32/size
17846     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
17847 _string-loop-if->=:  # (payload array byte)
17848     0x11/imm32/alloc-id:fake:payload
17849     # "loop-if->="
17850     0xa/imm32/size
17851     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
17852 _string-loop-if-!=:  # (payload array byte)
17853     0x11/imm32/alloc-id:fake:payload
17854     # "loop-if-!="
17855     0xa/imm32/size
17856     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
17857 _string-loop-if-addr<:  # (payload array byte)
17858     0x11/imm32/alloc-id:fake:payload
17859     # "loop-if-addr<"
17860     0xd/imm32/size
17861     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/<
17862 _string-loop-if-addr<=:  # (payload array byte)
17863     0x11/imm32/alloc-id:fake:payload
17864     # "loop-if-addr<="
17865     0xe/imm32/size
17866     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/=
17867 _string-loop-if-addr>:  # (payload array byte)
17868     0x11/imm32/alloc-id:fake:payload
17869     # "loop-if-addr>"
17870     0xd/imm32/size
17871     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/>
17872 _string-loop-if-addr>=:  # (payload array byte)
17873     0x11/imm32/alloc-id:fake:payload
17874     # "loop-if-addr>="
17875     0xe/imm32/size
17876     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/=
17877 _string-multiply:  # (payload array byte)
17878     0x11/imm32/alloc-id:fake:payload
17879     # "multiply"
17880     0x8/imm32/size
17881     0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
17882 _string-or:  # (payload array byte)
17883     0x11/imm32/alloc-id:fake:payload
17884     # "or"
17885     0x2/imm32/size
17886     0x6f/o 0x72/r
17887 _string-or-with:  # (payload array byte)
17888     0x11/imm32/alloc-id:fake:payload
17889     # "or-with"
17890     0x7/imm32/size
17891     0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
17892 _string-subtract:  # (payload array byte)
17893     0x11/imm32/alloc-id:fake:payload
17894     # "subtract"
17895     0x8/imm32/size
17896     0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
17897 _string-subtract-from:  # (payload array byte)
17898     0x11/imm32/alloc-id:fake:payload
17899     # "subtract-from"
17900     0xd/imm32/size
17901     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
17902 _string-xor:  # (payload array byte)
17903     0x11/imm32/alloc-id:fake:payload
17904     # "xor"
17905     0x3/imm32/size
17906     0x78/x 0x6f/o 0x72/r
17907 _string-xor-with:  # (payload array byte)
17908     0x11/imm32/alloc-id:fake:payload
17909     # "xor-with"
17910     0x8/imm32/size
17911     0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
17912 _string-shift-left:  # (payload array byte)
17913     0x11/imm32/alloc-id:fake:payload
17914     # "shift-left"
17915     0xa/imm32/size
17916     0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x6c/l 0x65/e 0x66/f 0x74/t
17917 _string-shift-right:  # (payload array byte)
17918     0x11/imm32/alloc-id:fake:payload
17919     # "shift-right"
17920     0xb/imm32/size
17921     0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x72/r 0x69/i 0x67/g 0x68/h 0x74/t
17922 _string-shift-right-signed:  # (payload array byte)
17923     0x11/imm32/alloc-id:fake:payload
17924     # "shift-right-signed"
17925     0x12/imm32/size
17926     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
17927 
17928 # string literals for SubX instructions
17929 _string_01_add_to:  # (payload array byte)
17930     0x11/imm32/alloc-id:fake:payload
17931     # "01/add-to"
17932     0x9/imm32/size
17933     0x30/0 0x31/1 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
17934 _string_03_add:  # (payload array byte)
17935     0x11/imm32/alloc-id:fake:payload
17936     # "03/add"
17937     0x6/imm32/size
17938     0x30/0 0x33/3 0x2f/slash 0x61/a 0x64/d 0x64/d
17939 _string_05_add_to_eax:  # (payload array byte)
17940     0x11/imm32/alloc-id:fake:payload
17941     # "05/add-to-eax"
17942     0xd/imm32/size
17943     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
17944 _string_09_or_with:  # (payload array byte)
17945     0x11/imm32/alloc-id:fake:payload
17946     # "09/or-with"
17947     0xa/imm32/size
17948     0x30/0 0x39/9 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
17949 _string_0b_or:  # (payload array byte)
17950     0x11/imm32/alloc-id:fake:payload
17951     # "0b/or"
17952     0x5/imm32/size
17953     0x30/0 0x62/b 0x2f/slash 0x6f/o 0x72/r
17954 _string_0d_or_with_eax:  # (payload array byte)
17955     0x11/imm32/alloc-id:fake:payload
17956     # "0d/or-with-eax"
17957     0xe/imm32/size
17958     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
17959 _string_0f_82_jump_label:  # (payload array byte)
17960     0x11/imm32/alloc-id:fake:payload
17961     # "0f 82/jump-if-addr<"
17962     0x13/imm32/size
17963     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/<
17964 _string_0f_82_jump_break:  # (payload array byte)
17965     0x11/imm32/alloc-id:fake:payload
17966     # "0f 82/jump-if-addr< break/disp32"
17967     0x20/imm32/size
17968     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
17969 _string_0f_82_jump_loop:  # (payload array byte)
17970     0x11/imm32/alloc-id:fake:payload
17971     # "0f 82/jump-if-addr< loop/disp32"
17972     0x1f/imm32/size
17973     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
17974 _string_0f_83_jump_label:  # (payload array byte)
17975     0x11/imm32/alloc-id:fake:payload
17976     # "0f 83/jump-if-addr>="
17977     0x14/imm32/size
17978     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/=
17979 _string_0f_83_jump_break:  # (payload array byte)
17980     0x11/imm32/alloc-id:fake:payload
17981     # "0f 83/jump-if-addr>= break/disp32"
17982     0x21/imm32/size
17983     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
17984 _string_0f_83_jump_loop:  # (payload array byte)
17985     0x11/imm32/alloc-id:fake:payload
17986     # "0f 83/jump-if-addr>= loop/disp32"
17987     0x20/imm32/size
17988     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
17989 _string_0f_84_jump_label:  # (payload array byte)
17990     0x11/imm32/alloc-id:fake:payload
17991     # "0f 84/jump-if-="
17992     0xf/imm32/size
17993     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/=
17994 _string_0f_84_jump_break:  # (payload array byte)
17995     0x11/imm32/alloc-id:fake:payload
17996     # "0f 84/jump-if-= break/disp32"
17997     0x1c/imm32/size
17998     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
17999 _string_0f_84_jump_loop:  # (payload array byte)
18000     0x11/imm32/alloc-id:fake:payload
18001     # "0f 84/jump-if-= loop/disp32"
18002     0x1b/imm32/size
18003     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
18004 _string_0f_85_jump_label:  # (payload array byte)
18005     0x11/imm32/alloc-id:fake:payload
18006     # "0f 85/jump-if-!="
18007     0x10/imm32/size
18008     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/=
18009 _string_0f_85_jump_break:  # (payload array byte)
18010     0x11/imm32/alloc-id:fake:payload
18011     # "0f 85/jump-if-!= break/disp32"
18012     0x1d/imm32/size
18013     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
18014 _string_0f_85_jump_loop:  # (payload array byte)
18015     0x11/imm32/alloc-id:fake:payload
18016     # "0f 85/jump-if-!= loop/disp32"
18017     0x1c/imm32/size
18018     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
18019 _string_0f_86_jump_label:  # (payload array byte)
18020     0x11/imm32/alloc-id:fake:payload
18021     # "0f 86/jump-if-addr<="
18022     0x14/imm32/size
18023     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/=
18024 _string_0f_86_jump_break:  # (payload array byte)
18025     0x11/imm32/alloc-id:fake:payload
18026     # "0f 86/jump-if-addr<= break/disp32"
18027     0x21/imm32/size
18028     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
18029 _string_0f_86_jump_loop:  # (payload array byte)
18030     0x11/imm32/alloc-id:fake:payload
18031     # "0f 86/jump-if-addr<= loop/disp32"
18032     0x20/imm32/size
18033     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
18034 _string_0f_87_jump_label:  # (payload array byte)
18035     0x11/imm32/alloc-id:fake:payload
18036     # "0f 87/jump-if-addr>"
18037     0x13/imm32/size
18038     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/>
18039 _string_0f_87_jump_break:  # (payload array byte)
18040     0x11/imm32/alloc-id:fake:payload
18041     # "0f 87/jump-if-addr> break/disp32"
18042     0x20/imm32/size
18043     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
18044 _string_0f_87_jump_loop:  # (payload array byte)
18045     0x11/imm32/alloc-id:fake:payload
18046     # "0f 87/jump-if-addr> loop/disp32"
18047     0x1f/imm32/size
18048     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
18049 _string_0f_8c_jump_label:  # (payload array byte)
18050     0x11/imm32/alloc-id:fake:payload
18051     # "0f 8c/jump-if-<"
18052     0xf/imm32/size
18053     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/<
18054 _string_0f_8c_jump_break:  # (payload array byte)
18055     0x11/imm32/alloc-id:fake:payload
18056     # "0f 8c/jump-if-< break/disp32"
18057     0x1c/imm32/size
18058     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
18059 _string_0f_8c_jump_loop:  # (payload array byte)
18060     0x11/imm32/alloc-id:fake:payload
18061     # "0f 8c/jump-if-< loop/disp32"
18062     0x1b/imm32/size
18063     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
18064 _string_0f_8d_jump_label:  # (payload array byte)
18065     0x11/imm32/alloc-id:fake:payload
18066     # "0f 8d/jump-if->="
18067     0x10/imm32/size
18068     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/=
18069 _string_0f_8d_jump_break:  # (payload array byte)
18070     0x11/imm32/alloc-id:fake:payload
18071     # "0f 8d/jump-if->= break/disp32"
18072     0x1d/imm32/size
18073     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
18074 _string_0f_8d_jump_loop:  # (payload array byte)
18075     0x11/imm32/alloc-id:fake:payload
18076     # "0f 8d/jump-if->= loop/disp32"
18077     0x1c/imm32/size
18078     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
18079 _string_0f_8e_jump_label:  # (payload array byte)
18080     0x11/imm32/alloc-id:fake:payload
18081     # "0f 8e/jump-if-<="
18082     0x10/imm32/size
18083     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/=
18084 _string_0f_8e_jump_break:  # (payload array byte)
18085     0x11/imm32/alloc-id:fake:payload
18086     # "0f 8e/jump-if-<= break/disp32"
18087     0x1d/imm32/size
18088     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
18089 _string_0f_8e_jump_loop:  # (payload array byte)
18090     0x11/imm32/alloc-id:fake:payload
18091     # "0f 8e/jump-if-<= loop/disp32"
18092     0x1c/imm32/size
18093     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
18094 _string_0f_8f_jump_label:  # (payload array byte)
18095     0x11/imm32/alloc-id:fake:payload
18096     # "0f 8f/jump-if->"
18097     0xf/imm32/size
18098     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/>
18099 _string_0f_8f_jump_break:  # (payload array byte)
18100     0x11/imm32/alloc-id:fake:payload
18101     # "0f 8f/jump-if-> break/disp32"
18102     0x1c/imm32/size
18103     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
18104 _string_0f_8f_jump_loop:  # (payload array byte)
18105     0x11/imm32/alloc-id:fake:payload
18106     # "0f 8f/jump-if-> loop/disp32"
18107     0x1b/imm32/size
18108     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
18109 _string_0f_af_multiply:  # (payload array byte)
18110     0x11/imm32/alloc-id:fake:payload
18111     # "0f af/multiply"
18112     0xe/imm32/size
18113     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
18114 _string_21_and_with:  # (payload array byte)
18115     0x11/imm32/alloc-id:fake:payload
18116     # "21/and-with"
18117     0xb/imm32/size
18118     0x32/2 0x31/1 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
18119 _string_23_and:  # (payload array byte)
18120     0x11/imm32/alloc-id:fake:payload
18121     # "23/and"
18122     0x6/imm32/size
18123     0x32/2 0x33/3 0x2f/slash 0x61/a 0x6e/n 0x64/d
18124 _string_25_and_with_eax:  # (payload array byte)
18125     0x11/imm32/alloc-id:fake:payload
18126     # "25/and-with-eax"
18127     0xf/imm32/size
18128     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
18129 _string_29_subtract_from:  # (payload array byte)
18130     0x11/imm32/alloc-id:fake:payload
18131     # "29/subtract-from"
18132     0x10/imm32/size
18133     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
18134 _string_2b_subtract:  # (payload array byte)
18135     0x11/imm32/alloc-id:fake:payload
18136     # "2b/subtract"
18137     0xb/imm32/size
18138     0x32/2 0x62/b 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
18139 _string_2d_subtract_from_eax:  # (payload array byte)
18140     0x11/imm32/alloc-id:fake:payload
18141     # "2d/subtract-from-eax"
18142     0x14/imm32/size
18143     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
18144 _string_31_xor_with:  # (payload array byte)
18145     0x11/imm32/alloc-id:fake:payload
18146     # "31/xor-with"
18147     0xb/imm32/size
18148     0x33/3 0x31/1 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
18149 _string_33_xor:  # (payload array byte)
18150     0x11/imm32/alloc-id:fake:payload
18151     # "33/xor"
18152     0x6/imm32/size
18153     0x33/3 0x33/3 0x2f/slash 0x78/x 0x6f/o 0x72/r
18154 _string_35_xor_with_eax:  # (payload array byte)
18155     0x11/imm32/alloc-id:fake:payload
18156     # "35/xor-with-eax"
18157     0xf/imm32/size
18158     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
18159 _string_39_compare->:  # (payload array byte)
18160     0x11/imm32/alloc-id:fake:payload
18161     # "39/compare->"
18162     0xc/imm32/size
18163     0x33/3 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x3e/>
18164 _string_3b_compare<-:  # (payload array byte)
18165     0x11/imm32/alloc-id:fake:payload
18166     # "3b/compare<-"
18167     0xc/imm32/size
18168     0x33/3 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x3c/< 0x2d/dash
18169 _string_3d_compare_eax_with:  # (payload array byte)
18170     0x11/imm32/alloc-id:fake:payload
18171     # "3d/compare-eax-with"
18172     0x13/imm32/size
18173     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
18174 _string_40_increment_eax:  # (payload array byte)
18175     0x11/imm32/alloc-id:fake:payload
18176     # "40/increment-eax"
18177     0x10/imm32/size
18178     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
18179 _string_41_increment_ecx:  # (payload array byte)
18180     0x11/imm32/alloc-id:fake:payload
18181     # "41/increment-ecx"
18182     0x10/imm32/size
18183     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
18184 _string_42_increment_edx:  # (payload array byte)
18185     0x11/imm32/alloc-id:fake:payload
18186     # "42/increment-edx"
18187     0x10/imm32/size
18188     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
18189 _string_43_increment_ebx:  # (payload array byte)
18190     0x11/imm32/alloc-id:fake:payload
18191     # "43/increment-ebx"
18192     0x10/imm32/size
18193     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
18194 _string_46_increment_esi:  # (payload array byte)
18195     0x11/imm32/alloc-id:fake:payload
18196     # "46/increment-esi"
18197     0x10/imm32/size
18198     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
18199 _string_47_increment_edi:  # (payload array byte)
18200     0x11/imm32/alloc-id:fake:payload
18201     # "47/increment-edi"
18202     0x10/imm32/size
18203     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
18204 _string_48_decrement_eax:  # (payload array byte)
18205     0x11/imm32/alloc-id:fake:payload
18206     # "48/decrement-eax"
18207     0x10/imm32/size
18208     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
18209 _string_49_decrement_ecx:  # (payload array byte)
18210     0x11/imm32/alloc-id:fake:payload
18211     # "49/decrement-ecx"
18212     0x10/imm32/size
18213     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
18214 _string_4a_decrement_edx:  # (payload array byte)
18215     0x11/imm32/alloc-id:fake:payload
18216     # "4a/decrement-edx"
18217     0x10/imm32/size
18218     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
18219 _string_4b_decrement_ebx:  # (payload array byte)
18220     0x11/imm32/alloc-id:fake:payload
18221     # "4b/decrement-ebx"
18222     0x10/imm32/size
18223     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
18224 _string_4e_decrement_esi:  # (payload array byte)
18225     0x11/imm32/alloc-id:fake:payload
18226     # "4e/decrement-esi"
18227     0x10/imm32/size
18228     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
18229 _string_4f_decrement_edi:  # (payload array byte)
18230     0x11/imm32/alloc-id:fake:payload
18231     # "4f/decrement-edi"
18232     0x10/imm32/size
18233     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
18234 _string_81_subop_add:  # (payload array byte)
18235     0x11/imm32/alloc-id:fake:payload
18236     # "81 0/subop/add"
18237     0xe/imm32/size
18238     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
18239 _string_81_subop_or:  # (payload array byte)
18240     0x11/imm32/alloc-id:fake:payload
18241     # "81 1/subop/or"
18242     0xd/imm32/size
18243     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
18244 _string_81_subop_and:  # (payload array byte)
18245     0x11/imm32/alloc-id:fake:payload
18246     # "81 4/subop/and"
18247     0xe/imm32/size
18248     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
18249 _string_81_subop_subtract:  # (payload array byte)
18250     0x11/imm32/alloc-id:fake:payload
18251     # "81 5/subop/subtract"
18252     0x13/imm32/size
18253     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
18254 _string_81_subop_xor:  # (payload array byte)
18255     0x11/imm32/alloc-id:fake:payload
18256     # "81 6/subop/xor"
18257     0xe/imm32/size
18258     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
18259 _string_81_subop_compare:  # (payload array byte)
18260     0x11/imm32/alloc-id:fake:payload
18261     # "81 7/subop/compare"
18262     0x12/imm32/size
18263     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
18264 _string_89_<-:  # (payload array byte)
18265     0x11/imm32/alloc-id:fake:payload
18266     # "89/<-"
18267     0x5/imm32/size
18268     0x38/8 0x39/9 0x2f/slash 0x3c/< 0x2d/dash
18269 _string_8b_->:  # (payload array byte)
18270     0x11/imm32/alloc-id:fake:payload
18271     # "8b/->"
18272     0x5/imm32/size
18273     0x38/8 0x62/b 0x2f/slash 0x2d/dash 0x3e/>
18274 _string_8a_copy_byte:
18275     0x11/imm32/alloc-id:fake:payload
18276     # "8a/byte->"
18277     0x9/imm32/size
18278     0x38/8 0x61/a 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x3e/>
18279 _string_88_copy_byte:
18280     0x11/imm32/alloc-id:fake:payload
18281     # "88/byte<-"
18282     0x9/imm32/size
18283     0x38/8 0x38/8 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x3c/< 0x2d/-
18284 _string_8d_copy_address:  # (payload array byte)
18285     0x11/imm32/alloc-id:fake:payload
18286     # "8d/copy-address"
18287     0xf/imm32/size
18288     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
18289 _string_b8_copy_to_eax:  # (payload array byte)
18290     0x11/imm32/alloc-id:fake:payload
18291     # "b8/copy-to-eax"
18292     0xe/imm32/size
18293     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
18294 _string_b9_copy_to_ecx:  # (payload array byte)
18295     0x11/imm32/alloc-id:fake:payload
18296     # "b9/copy-to-ecx"
18297     0xe/imm32/size
18298     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
18299 _string_ba_copy_to_edx:  # (payload array byte)
18300     0x11/imm32/alloc-id:fake:payload
18301     # "ba/copy-to-edx"
18302     0xe/imm32/size
18303     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
18304 _string_bb_copy_to_ebx:  # (payload array byte)
18305     0x11/imm32/alloc-id:fake:payload
18306     # "bb/copy-to-ebx"
18307     0xe/imm32/size
18308     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
18309 _string_be_copy_to_esi:  # (payload array byte)
18310     0x11/imm32/alloc-id:fake:payload
18311     # "be/copy-to-esi"
18312     0xe/imm32/size
18313     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
18314 _string_bf_copy_to_edi:  # (payload array byte)
18315     0x11/imm32/alloc-id:fake:payload
18316     # "bf/copy-to-edi"
18317     0xe/imm32/size
18318     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
18319 _string_c7_subop_copy:  # (payload array byte)
18320     0x11/imm32/alloc-id:fake:payload
18321     # "c7 0/subop/copy"
18322     0xf/imm32/size
18323     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
18324 _string_e9_jump_label:  # (payload array byte)
18325     0x11/imm32/alloc-id:fake:payload
18326     # "e9/jump"
18327     0x7/imm32/size
18328     0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p
18329 _string_e9_jump_break:  # (payload array byte)
18330     0x11/imm32/alloc-id:fake:payload
18331     # "e9/jump break/disp32"
18332     0x14/imm32/size
18333     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
18334 _string_e9_jump_loop:  # (payload array byte)
18335     0x11/imm32/alloc-id:fake:payload
18336     # "e9/jump loop/disp32"
18337     0x13/imm32/size
18338     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
18339 _string_ff_subop_increment:  # (payload array byte)
18340     0x11/imm32/alloc-id:fake:payload
18341     # "ff 0/subop/increment"
18342     0x14/imm32/size
18343     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
18344 _string_ff_subop_decrement:  # (payload array byte)
18345     0x11/imm32/alloc-id:fake:payload
18346     # "ff 1/subop/decrement"
18347     0x14/imm32/size
18348     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
18349 _string_c1_subop_shift_left:  # (payload array byte)
18350     0x11/imm32/alloc-id:fake:payload
18351     # "c1/shift 4/subop/left"
18352     0x15/imm32/size
18353     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
18354 _string_c1_subop_shift_right_padding_zeroes:  # (payload array byte)
18355     0x11/imm32/alloc-id:fake:payload
18356     # "c1/shift 5/subop/right-padding-zeroes"
18357     0x25/imm32/size
18358     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
18359 _string_c1_subop_shift_right_preserving_sign:  # (payload array byte)
18360     0x11/imm32/alloc-id:fake:payload
18361     # "c1/shift 7/subop/right-preserving-sign"
18362     0x26/imm32/size
18363     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
18364 
18365 Single-int-var-in-mem:  # (payload list var)
18366     0x11/imm32/alloc-id:fake:payload
18367     0x11/imm32/alloc-id:fake
18368     Int-var-in-mem/imm32
18369     0/imm32/next
18370     0/imm32/next
18371 
18372 Int-var-in-mem:  # (payload var)
18373     0x11/imm32/alloc-id:fake:payload
18374     0/imm32/name
18375     0/imm32/name
18376     0x11/imm32/alloc-id:fake
18377     Type-int/imm32
18378     1/imm32/some-block-depth
18379     1/imm32/some-stack-offset
18380     0/imm32/no-register
18381     0/imm32/no-register
18382 
18383 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
18384 Single-byte-var-in-mem:  # (payload list var)
18385     0x11/imm32/alloc-id:fake:payload
18386     0x11/imm32/alloc-id:fake
18387     Byte-var-in-mem/imm32
18388     0/imm32/next
18389     0/imm32/next
18390 
18391 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
18392 Byte-var-in-mem:  # (payload var)
18393     0x11/imm32/alloc-id:fake:payload
18394     0/imm32/name
18395     0/imm32/name
18396     0x11/imm32/alloc-id:fake
18397     Type-byte/imm32
18398     1/imm32/some-block-depth
18399     1/imm32/some-stack-offset
18400     0/imm32/no-register
18401     0/imm32/no-register
18402 
18403 Two-args-int-stack-int-reg:  # (payload list var)
18404     0x11/imm32/alloc-id:fake:payload
18405     0x11/imm32/alloc-id:fake
18406     Int-var-in-mem/imm32
18407     0x11/imm32/alloc-id:fake
18408     Single-int-var-in-some-register/imm32/next
18409 
18410 Two-int-args-in-regs:  # (payload list var)
18411     0x11/imm32/alloc-id:fake:payload
18412     0x11/imm32/alloc-id:fake
18413     Int-var-in-some-register/imm32
18414     0x11/imm32/alloc-id:fake
18415     Single-int-var-in-some-register/imm32/next
18416 
18417 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
18418 Two-args-byte-stack-byte-reg:  # (payload list var)
18419     0x11/imm32/alloc-id:fake:payload
18420     0x11/imm32/alloc-id:fake
18421     Byte-var-in-mem/imm32
18422     0x11/imm32/alloc-id:fake
18423     Single-byte-var-in-some-register/imm32/next
18424 
18425 Two-args-int-reg-int-stack:  # (payload list var)
18426     0x11/imm32/alloc-id:fake:payload
18427     0x11/imm32/alloc-id:fake
18428     Int-var-in-some-register/imm32
18429     0x11/imm32/alloc-id:fake
18430     Single-int-var-in-mem/imm32/next
18431 
18432 Two-args-int-eax-int-literal:  # (payload list var)
18433     0x11/imm32/alloc-id:fake:payload
18434     0x11/imm32/alloc-id:fake
18435     Int-var-in-eax/imm32
18436     0x11/imm32/alloc-id:fake
18437     Single-lit-var/imm32/next
18438 
18439 Int-var-and-literal:  # (payload list var)
18440     0x11/imm32/alloc-id:fake:payload
18441     0x11/imm32/alloc-id:fake
18442     Int-var-in-mem/imm32
18443     0x11/imm32/alloc-id:fake
18444     Single-lit-var/imm32/next
18445 
18446 Int-var-in-register-and-literal:  # (payload list var)
18447     0x11/imm32/alloc-id:fake:payload
18448     0x11/imm32/alloc-id:fake
18449     Int-var-in-some-register/imm32
18450     0x11/imm32/alloc-id:fake
18451     Single-lit-var/imm32/next
18452 
18453 Single-int-var-in-some-register:  # (payload list var)
18454     0x11/imm32/alloc-id:fake:payload
18455     0x11/imm32/alloc-id:fake
18456     Int-var-in-some-register/imm32
18457     0/imm32/next
18458     0/imm32/next
18459 
18460 Single-addr-var-in-some-register:  # (payload list var)
18461     0x11/imm32/alloc-id:fake:payload
18462     0x11/imm32/alloc-id:fake
18463     Addr-var-in-some-register/imm32
18464     0/imm32/next
18465     0/imm32/next
18466 
18467 Single-byte-var-in-some-register:  # (payload list var)
18468     0x11/imm32/alloc-id:fake:payload
18469     0x11/imm32/alloc-id:fake
18470     Byte-var-in-some-register/imm32
18471     0/imm32/next
18472     0/imm32/next
18473 
18474 Int-var-in-some-register:  # (payload var)
18475     0x11/imm32/alloc-id:fake:payload
18476     0/imm32/name
18477     0/imm32/name
18478     0x11/imm32/alloc-id:fake
18479     Type-int/imm32
18480     1/imm32/some-block-depth
18481     0/imm32/no-stack-offset
18482     0x11/imm32/alloc-id:fake
18483     Any-register/imm32
18484 
18485 Any-register:  # (payload array byte)
18486     0x11/imm32/alloc-id:fake:payload
18487     1/imm32/size
18488     # data
18489     2a/asterisk
18490 
18491 Addr-var-in-some-register:  # (payload var)
18492     0x11/imm32/alloc-id:fake:payload
18493     0/imm32/name
18494     0/imm32/name
18495     0x11/imm32/alloc-id:fake
18496     Type-addr/imm32
18497     1/imm32/some-block-depth
18498     0/imm32/no-stack-offset
18499     0x11/imm32/alloc-id:fake
18500     Any-register/imm32
18501 
18502 Byte-var-in-some-register:  # (payload var)
18503     0x11/imm32/alloc-id:fake:payload
18504     0/imm32/name
18505     0/imm32/name
18506     0x11/imm32/alloc-id:fake
18507     Type-byte/imm32
18508     1/imm32/some-block-depth
18509     0/imm32/no-stack-offset
18510     0x11/imm32/alloc-id:fake
18511     Any-register/imm32
18512 
18513 Single-int-var-in-eax:  # (payload list var)
18514     0x11/imm32/alloc-id:fake:payload
18515     0x11/imm32/alloc-id:fake
18516     Int-var-in-eax/imm32
18517     0/imm32/next
18518     0/imm32/next
18519 
18520 Int-var-in-eax:
18521     0x11/imm32/alloc-id:fake:payload
18522     0/imm32/name
18523     0/imm32/name
18524     0x11/imm32/alloc-id:fake
18525     Type-int/imm32
18526     1/imm32/some-block-depth
18527     0/imm32/no-stack-offset
18528     0x11/imm32/alloc-id:fake
18529     $Register-eax/imm32
18530 
18531 Single-int-var-in-ecx:  # (payload list var)
18532     0x11/imm32/alloc-id:fake:payload
18533     0x11/imm32/alloc-id:fake
18534     Int-var-in-ecx/imm32
18535     0/imm32/next
18536     0/imm32/next
18537 
18538 Int-var-in-ecx:
18539     0x11/imm32/alloc-id:fake:payload
18540     0/imm32/name
18541     0/imm32/name
18542     0x11/imm32/alloc-id:fake
18543     Type-int/imm32
18544     1/imm32/some-block-depth
18545     0/imm32/no-stack-offset
18546     0x11/imm32/alloc-id:fake
18547     $Register-ecx/imm32/register
18548 
18549 Single-int-var-in-edx:  # (payload list var)
18550     0x11/imm32/alloc-id:fake:payload
18551     0x11/imm32/alloc-id:fake
18552     Int-var-in-edx/imm32
18553     0/imm32/next
18554     0/imm32/next
18555 
18556 Int-var-in-edx:  # (payload list var)
18557     0x11/imm32/alloc-id:fake:payload
18558     0/imm32/name
18559     0/imm32/name
18560     0x11/imm32/alloc-id:fake
18561     Type-int/imm32
18562     1/imm32/some-block-depth
18563     0/imm32/no-stack-offset
18564     0x11/imm32/alloc-id:fake
18565     $Register-edx/imm32/register
18566 
18567 Single-int-var-in-ebx:  # (payload list var)
18568     0x11/imm32/alloc-id:fake:payload
18569     0x11/imm32/alloc-id:fake
18570     Int-var-in-ebx/imm32
18571     0/imm32/next
18572     0/imm32/next
18573 
18574 Int-var-in-ebx:  # (payload list var)
18575     0x11/imm32/alloc-id:fake:payload
18576     0/imm32/name
18577     0/imm32/name
18578     0x11/imm32/alloc-id:fake
18579     Type-int/imm32
18580     1/imm32/some-block-depth
18581     0/imm32/no-stack-offset
18582     0x11/imm32/alloc-id:fake
18583     $Register-ebx/imm32/register
18584 
18585 Single-int-var-in-esi:  # (payload list var)
18586     0x11/imm32/alloc-id:fake:payload
18587     0x11/imm32/alloc-id:fake
18588     Int-var-in-esi/imm32
18589     0/imm32/next
18590     0/imm32/next
18591 
18592 Int-var-in-esi:  # (payload list var)
18593     0x11/imm32/alloc-id:fake:payload
18594     0/imm32/name
18595     0/imm32/name
18596     0x11/imm32/alloc-id:fake
18597     Type-int/imm32
18598     1/imm32/some-block-depth
18599     0/imm32/no-stack-offset
18600     0x11/imm32/alloc-id:fake
18601     $Register-esi/imm32/register
18602 
18603 Single-int-var-in-edi:  # (payload list var)
18604     0x11/imm32/alloc-id:fake:payload
18605     0x11/imm32/alloc-id:fake
18606     Int-var-in-edi/imm32
18607     0/imm32/next
18608     0/imm32/next
18609 
18610 Int-var-in-edi:  # (payload list var)
18611     0x11/imm32/alloc-id:fake:payload
18612     0/imm32/name
18613     0/imm32/name
18614     0x11/imm32/alloc-id:fake
18615     Type-int/imm32
18616     1/imm32/some-block-depth
18617     0/imm32/no-stack-offset
18618     0x11/imm32/alloc-id:fake
18619     $Register-edi/imm32/register
18620 
18621 Single-lit-var:  # (payload list var)
18622     0x11/imm32/alloc-id:fake:payload
18623     0x11/imm32/alloc-id:fake
18624     Lit-var/imm32
18625     0/imm32/next
18626     0/imm32/next
18627 
18628 Lit-var:  # (payload var)
18629     0x11/imm32/alloc-id:fake:payload
18630     0/imm32/name
18631     0/imm32/name
18632     0x11/imm32/alloc-id:fake
18633     Type-literal/imm32
18634     1/imm32/some-block-depth
18635     0/imm32/no-stack-offset
18636     0/imm32/no-register
18637     0/imm32/no-register
18638 
18639 Type-int:  # (payload type-tree)
18640     0x11/imm32/alloc-id:fake:payload
18641     1/imm32/is-atom
18642     1/imm32/value:int
18643     0/imm32/left:unused
18644     0/imm32/right:null
18645     0/imm32/right:null
18646 
18647 Type-literal:  # (payload type-tree)
18648     0x11/imm32/alloc-id:fake:payload
18649     1/imm32/is-atom
18650     0/imm32/value:literal
18651     0/imm32/left:unused
18652     0/imm32/right:null
18653     0/imm32/right:null
18654 
18655 Type-addr:  # (payload type-tree)
18656     0x11/imm32/alloc-id:fake:payload
18657     1/imm32/is-atom
18658     2/imm32/value:addr
18659     0/imm32/left:unused
18660     0/imm32/right:null
18661     0/imm32/right:null
18662 
18663 Type-byte:  # (payload type-tree)
18664     0x11/imm32/alloc-id:fake:payload
18665     1/imm32/is-atom
18666     8/imm32/value:byte
18667     0/imm32/left:unused
18668     0/imm32/right:null
18669     0/imm32/right:null
18670 
18671 == code
18672 emit-subx-primitive:  # out: (addr buffered-file), stmt: (addr stmt), primitive: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
18673     # . prologue
18674     55/push-ebp
18675     89/<- %ebp 4/r32/esp
18676     # . save registers
18677     50/push-eax
18678     51/push-ecx
18679     # ecx = primitive
18680     8b/-> *(ebp+0x10) 1/r32/ecx
18681     # emit primitive name
18682     (emit-indent *(ebp+8) *Curr-block-depth)
18683     (lookup *(ecx+0x18) *(ecx+0x1c))  # Primitive-subx-name Primitive-subx-name => eax
18684     (write-buffered *(ebp+8) %eax)
18685     # emit rm32 if necessary
18686     (emit-subx-rm32 *(ebp+8) *(ecx+0x20) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-rm32
18687     # emit r32 if necessary
18688     (emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc))  # Primitive-subx-r32
18689     # emit imm32 if necessary
18690     (emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc))  # Primitive-subx-imm32
18691     # emit imm8 if necessary
18692     (emit-subx-imm8 *(ebp+8) *(ecx+0x2c) *(ebp+0xc))  # Primitive-subx-imm8
18693     # emit disp32 if necessary
18694     (emit-subx-disp32 *(ebp+8) *(ecx+0x30) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-disp32
18695     (write-buffered *(ebp+8) Newline)
18696 $emit-subx-primitive:end:
18697     # . restore registers
18698     59/pop-to-ecx
18699     58/pop-to-eax
18700     # . epilogue
18701     89/<- %esp 5/r32/ebp
18702     5d/pop-to-ebp
18703     c3/return
18704 
18705 emit-subx-rm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
18706     # . prologue
18707     55/push-ebp
18708     89/<- %ebp 4/r32/esp
18709     # . save registers
18710     50/push-eax
18711     # if (l == 0) return
18712     81 7/subop/compare *(ebp+0xc) 0/imm32
18713     74/jump-if-= $emit-subx-rm32:end/disp8
18714     # var v/eax: (addr stmt-var)
18715     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
18716     (emit-subx-var-as-rm32 *(ebp+8) %eax)
18717 $emit-subx-rm32:end:
18718     # . restore registers
18719     58/pop-to-eax
18720     # . epilogue
18721     89/<- %esp 5/r32/ebp
18722     5d/pop-to-ebp
18723     c3/return
18724 
18725 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)
18726     # . prologue
18727     55/push-ebp
18728     89/<- %ebp 4/r32/esp
18729     # . save registers
18730     51/push-ecx
18731     # eax = l
18732     8b/-> *(ebp+0xc) 0/r32/eax
18733     # ecx = stmt
18734     8b/-> *(ebp+8) 1/r32/ecx
18735     # if (l == 1) return stmt->inouts
18736     {
18737       3d/compare-eax-and 1/imm32
18738       75/jump-if-!= break/disp8
18739 $get-stmt-operand-from-arg-location:1:
18740       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
18741       eb/jump $get-stmt-operand-from-arg-location:end/disp8
18742     }
18743     # if (l == 2) return stmt->inouts->next
18744     {
18745       3d/compare-eax-and 2/imm32
18746       75/jump-if-!= break/disp8
18747 $get-stmt-operand-from-arg-location:2:
18748       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
18749       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
18750       eb/jump $get-stmt-operand-from-arg-location:end/disp8
18751     }
18752     # if (l == 3) return stmt->outputs
18753     {
18754       3d/compare-eax-and 3/imm32
18755       75/jump-if-!= break/disp8
18756 $get-stmt-operand-from-arg-location:3:
18757       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
18758       eb/jump $get-stmt-operand-from-arg-location:end/disp8
18759     }
18760     # abort
18761     e9/jump $get-stmt-operand-from-arg-location:abort/disp32
18762 $get-stmt-operand-from-arg-location:end:
18763     # . restore registers
18764     59/pop-to-ecx
18765     # . epilogue
18766     89/<- %esp 5/r32/ebp
18767     5d/pop-to-ebp
18768     c3/return
18769 
18770 $get-stmt-operand-from-arg-location:abort:
18771     # error("invalid arg-location " eax)
18772     (write-buffered *(ebp+0x10) "invalid arg-location ")
18773     (write-int32-hex-buffered *(ebp+0x10) %eax)
18774     (write-buffered *(ebp+0x10) Newline)
18775     (flush *(ebp+0x10))
18776     (stop *(ebp+0x14) 1)
18777     # never gets here
18778 
18779 emit-subx-r32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
18780     # . prologue
18781     55/push-ebp
18782     89/<- %ebp 4/r32/esp
18783     # . save registers
18784     50/push-eax
18785     51/push-ecx
18786     # if (l == 0) return
18787     81 7/subop/compare *(ebp+0xc) 0/imm32
18788     0f 84/jump-if-= $emit-subx-r32:end/disp32
18789     # var v/eax: (addr stmt-var)
18790     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
18791     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
18792     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
18793     (maybe-get Mu-registers %eax 0xc)  # => eax: (addr register-index)
18794     (write-buffered *(ebp+8) Space)
18795     (write-int32-hex-buffered *(ebp+8) *eax)
18796     (write-buffered *(ebp+8) "/r32")
18797 $emit-subx-r32:end:
18798     # . restore registers
18799     59/pop-to-ecx
18800     58/pop-to-eax
18801     # . epilogue
18802     89/<- %esp 5/r32/ebp
18803     5d/pop-to-ebp
18804     c3/return
18805 
18806 emit-subx-imm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
18807     # . prologue
18808     55/push-ebp
18809     89/<- %ebp 4/r32/esp
18810     # . save registers
18811     50/push-eax
18812     51/push-ecx
18813     # if (l == 0) return
18814     81 7/subop/compare *(ebp+0xc) 0/imm32
18815     0f 84/jump-if-= $emit-subx-imm32:end/disp32
18816     # var v/eax: (handle var)
18817     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
18818     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
18819     (lookup *eax *(eax+4))  # Var-name Var-name => eax
18820     (write-buffered *(ebp+8) Space)
18821     (write-buffered *(ebp+8) %eax)
18822     (write-buffered *(ebp+8) "/imm32")
18823 $emit-subx-imm32:end:
18824     # . restore registers
18825     59/pop-to-ecx
18826     58/pop-to-eax
18827     # . epilogue
18828     89/<- %esp 5/r32/ebp
18829     5d/pop-to-ebp
18830     c3/return
18831 
18832 emit-subx-imm8:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
18833     # . prologue
18834     55/push-ebp
18835     89/<- %ebp 4/r32/esp
18836     # . save registers
18837     50/push-eax
18838     51/push-ecx
18839     # if (l == 0) return
18840     81 7/subop/compare *(ebp+0xc) 0/imm32
18841     0f 84/jump-if-= $emit-subx-imm32:end/disp32
18842     # var v/eax: (handle var)
18843     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
18844     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
18845     (lookup *eax *(eax+4))  # Var-name Var-name => eax
18846     (write-buffered *(ebp+8) Space)
18847     (write-buffered *(ebp+8) %eax)
18848     (write-buffered *(ebp+8) "/imm8")
18849 $emit-subx-imm8:end:
18850     # . restore registers
18851     59/pop-to-ecx
18852     58/pop-to-eax
18853     # . epilogue
18854     89/<- %esp 5/r32/ebp
18855     5d/pop-to-ebp
18856     c3/return
18857 
18858 emit-subx-disp32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
18859     # . prologue
18860     55/push-ebp
18861     89/<- %ebp 4/r32/esp
18862     # . save registers
18863     50/push-eax
18864     51/push-ecx
18865     # if (location == 0) return
18866     81 7/subop/compare *(ebp+0xc) 0/imm32
18867     0f 84/jump-if-= $emit-subx-disp32:end/disp32
18868     # var v/eax: (addr stmt-var)
18869     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
18870     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
18871     (lookup *eax *(eax+4))  # Var-name Var-name => eax
18872     (write-buffered *(ebp+8) Space)
18873     (write-buffered *(ebp+8) %eax)
18874     # hack: if instruction operation starts with "break", emit ":break"
18875     # var name/ecx: (addr array byte) = lookup(stmt->operation)
18876     8b/-> *(ebp+0x10) 0/r32/eax
18877     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
18878     89/<- %ecx 0/r32/eax
18879     {
18880       (string-starts-with? %ecx "break")  # => eax
18881       3d/compare-eax-and 0/imm32/false
18882       74/jump-if-= break/disp8
18883       (write-buffered *(ebp+8) ":break")
18884     }
18885     # hack: if instruction operation starts with "loop", emit ":loop"
18886     {
18887       (string-starts-with? %ecx "loop")  # => eax
18888       3d/compare-eax-and 0/imm32/false
18889       74/jump-if-= break/disp8
18890       (write-buffered *(ebp+8) ":loop")
18891     }
18892     (write-buffered *(ebp+8) "/disp32")
18893 $emit-subx-disp32:end:
18894     # . restore registers
18895     59/pop-to-ecx
18896     58/pop-to-eax
18897     # . epilogue
18898     89/<- %esp 5/r32/ebp
18899     5d/pop-to-ebp
18900     c3/return
18901 
18902 emit-call:  # out: (addr buffered-file), stmt: (addr stmt)
18903     # . prologue
18904     55/push-ebp
18905     89/<- %ebp 4/r32/esp
18906     # . save registers
18907     50/push-eax
18908     51/push-ecx
18909     #
18910     (emit-indent *(ebp+8) *Curr-block-depth)
18911     (write-buffered *(ebp+8) "(")
18912     # ecx = stmt
18913     8b/-> *(ebp+0xc) 1/r32/ecx
18914     # - emit function name
18915     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
18916     (write-buffered *(ebp+8) %eax)
18917     # - emit arguments
18918     # var curr/eax: (addr stmt-var) = lookup(stmt->inouts)
18919     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
18920     {
18921       # if (curr == null) break
18922       3d/compare-eax-and 0/imm32
18923       74/jump-if-= break/disp8
18924       #
18925       (emit-subx-call-operand *(ebp+8) %eax)
18926       # curr = lookup(curr->next)
18927       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
18928       eb/jump loop/disp8
18929     }
18930     #
18931     (write-buffered *(ebp+8) ")\n")
18932 $emit-call:end:
18933     # . restore registers
18934     59/pop-to-ecx
18935     58/pop-to-eax
18936     # . epilogue
18937     89/<- %esp 5/r32/ebp
18938     5d/pop-to-ebp
18939     c3/return
18940 
18941 emit-subx-call-operand:  # out: (addr buffered-file), s: (addr stmt-var)
18942     # shares code with emit-subx-var-as-rm32
18943     # . prologue
18944     55/push-ebp
18945     89/<- %ebp 4/r32/esp
18946     # . save registers
18947     50/push-eax
18948     51/push-ecx
18949     56/push-esi
18950     # ecx = s
18951     8b/-> *(ebp+0xc) 1/r32/ecx
18952     # var operand/esi: (addr var) = lookup(s->value)
18953     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
18954     89/<- %esi 0/r32/eax
18955     # if (operand->register && !s->is-deref?) emit "%__"
18956     {
18957 $emit-subx-call-operand:check-for-register-direct:
18958       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
18959       74/jump-if-= break/disp8
18960       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
18961       75/jump-if-!= break/disp8
18962 $emit-subx-call-operand:register-direct:
18963       (write-buffered *(ebp+8) " %")
18964       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
18965       (write-buffered *(ebp+8) %eax)
18966       e9/jump $emit-subx-call-operand:end/disp32
18967     }
18968     # else if (operand->register && s->is-deref?) emit "*__"
18969     {
18970 $emit-subx-call-operand:check-for-register-indirect:
18971       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
18972       74/jump-if-= break/disp8
18973       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
18974       74/jump-if-= break/disp8
18975 $emit-subx-call-operand:register-indirect:
18976       (emit-subx-call-operand-register-indirect *(ebp+8) %esi)
18977       e9/jump $emit-subx-call-operand:end/disp32
18978     }
18979     # else if (operand->stack-offset) emit "*(ebp+__)"
18980     {
18981       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
18982       74/jump-if-= break/disp8
18983 $emit-subx-call-operand:stack:
18984       (emit-subx-call-operand-stack *(ebp+8) %esi)
18985       e9/jump $emit-subx-call-operand:end/disp32
18986     }
18987     # else if (operand->type == literal) emit "__"
18988     {
18989       (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
18990       81 7/subop/compare *(eax+4) 0/imm32  # Type-tree-left
18991       75/jump-if-!= break/disp8
18992 $emit-subx-call-operand:literal:
18993       (write-buffered *(ebp+8) Space)
18994       (lookup *esi *(esi+4))  # Var-name Var-name => eax
18995       (write-buffered *(ebp+8) %eax)
18996     }
18997 $emit-subx-call-operand:end:
18998     # . restore registers
18999     5e/pop-to-esi
19000     59/pop-to-ecx
19001     58/pop-to-eax
19002     # . epilogue
19003     89/<- %esp 5/r32/ebp
19004     5d/pop-to-ebp
19005     c3/return
19006 
19007 emit-subx-call-operand-register-indirect:  # out: (addr buffered-file), v: (addr var)
19008     # . prologue
19009     55/push-ebp
19010     89/<- %ebp 4/r32/esp
19011     # . save registers
19012     50/push-eax
19013     51/push-ecx
19014     56/push-esi
19015     # esi = v
19016     8b/-> *(ebp+0xc) 6/r32/esi
19017     # var size/ecx: int = size-of-deref(v)
19018     (size-of-deref %esi)  # => eax
19019     89/<- %ecx 0/r32/eax
19020     # var reg-name/esi: (addr array byte) = lookup(v->register)
19021     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
19022     89/<- %esi 0/r32/eax
19023     # TODO: assert size is a multiple of 4
19024     # var i/eax: int = 0
19025     b8/copy-to-eax 0/imm32
19026     {
19027 $emit-subx-call-operand-register-indirect:loop:
19028       # if (i >= size) break
19029       39/compare %eax 1/r32/ecx
19030       7d/jump-if->= break/disp8
19031       # emit " *(" v->register "+" i ")"
19032       (write-buffered *(ebp+8) " *(")
19033       (write-buffered *(ebp+8) %esi)
19034       (write-buffered *(ebp+8) "+")
19035       (write-int32-hex-buffered *(ebp+8) %eax)
19036       (write-buffered *(ebp+8) ")")
19037       # i += 4
19038       05/add-to-eax 4/imm32
19039       #
19040       eb/jump loop/disp8
19041     }
19042 $emit-subx-call-operand-register-indirect:end:
19043     # . restore registers
19044     5e/pop-to-esi
19045     59/pop-to-ecx
19046     58/pop-to-eax
19047     # . epilogue
19048     89/<- %esp 5/r32/ebp
19049     5d/pop-to-ebp
19050     c3/return
19051 
19052 emit-subx-call-operand-stack:  # out: (addr buffered-file), v: (addr var)
19053     # . prologue
19054     55/push-ebp
19055     89/<- %ebp 4/r32/esp
19056     # . save registers
19057     50/push-eax
19058     51/push-ecx
19059     56/push-esi
19060     # esi = v
19061     8b/-> *(ebp+0xc) 6/r32/esi
19062     # var curr/ecx: int = v->offset
19063     8b/-> *(esi+0x14) 1/r32/ecx  # Var-offset
19064     # var max/eax: int = v->offset + size-of(v)
19065     (size-of %esi)  # => eax
19066     # TODO: assert size is a multiple of 4
19067     01/add-to %eax 1/r32/ecx
19068     {
19069 $emit-subx-call-operand-stack:loop:
19070       # if (curr >= max) break
19071       39/compare %ecx 0/r32/eax
19072       7d/jump-if->= break/disp8
19073       # emit " *(ebp+" curr ")"
19074       (write-buffered *(ebp+8) " *(ebp+")
19075       (write-int32-hex-buffered *(ebp+8) %ecx)
19076       (write-buffered *(ebp+8) ")")
19077       # i += 4
19078       81 0/subop/add %ecx 4/imm32
19079       #
19080       eb/jump loop/disp8
19081     }
19082 $emit-subx-call-operand-stack:end:
19083     # . restore registers
19084     5e/pop-to-esi
19085     59/pop-to-ecx
19086     58/pop-to-eax
19087     # . epilogue
19088     89/<- %esp 5/r32/ebp
19089     5d/pop-to-ebp
19090     c3/return
19091 
19092 emit-subx-var-as-rm32:  # out: (addr buffered-file), s: (addr stmt-var)
19093     # . prologue
19094     55/push-ebp
19095     89/<- %ebp 4/r32/esp
19096     # . save registers
19097     50/push-eax
19098     51/push-ecx
19099     56/push-esi
19100     # ecx = s
19101     8b/-> *(ebp+0xc) 1/r32/ecx
19102     # var operand/esi: (addr var) = lookup(s->value)
19103     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
19104     89/<- %esi 0/r32/eax
19105     # if (operand->register && s->is-deref?) emit "*__"
19106     {
19107 $emit-subx-var-as-rm32:check-for-register-indirect:
19108       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19109       74/jump-if-= break/disp8
19110       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19111       74/jump-if-= break/disp8
19112 $emit-subx-var-as-rm32:register-indirect:
19113       (write-buffered *(ebp+8) " *")
19114       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
19115       (write-buffered *(ebp+8) %eax)
19116       e9/jump $emit-subx-var-as-rm32:end/disp32
19117     }
19118     # if (operand->register && !s->is-deref?) emit "%__"
19119     {
19120 $emit-subx-var-as-rm32:check-for-register-direct:
19121       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19122       74/jump-if-= break/disp8
19123       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19124       75/jump-if-!= break/disp8
19125 $emit-subx-var-as-rm32:register-direct:
19126       (write-buffered *(ebp+8) " %")
19127       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
19128       (write-buffered *(ebp+8) %eax)
19129       e9/jump $emit-subx-var-as-rm32:end/disp32
19130     }
19131     # else if (operand->stack-offset) emit "*(ebp+__)"
19132     {
19133       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
19134       74/jump-if-= break/disp8
19135 $emit-subx-var-as-rm32:stack:
19136       (write-buffered *(ebp+8) Space)
19137       (write-buffered *(ebp+8) "*(ebp+")
19138       (write-int32-hex-buffered *(ebp+8) *(esi+0x14))  # Var-offset
19139       (write-buffered *(ebp+8) ")")
19140     }
19141 $emit-subx-var-as-rm32:end:
19142     # . restore registers
19143     5e/pop-to-esi
19144     59/pop-to-ecx
19145     58/pop-to-eax
19146     # . epilogue
19147     89/<- %esp 5/r32/ebp
19148     5d/pop-to-ebp
19149     c3/return
19150 
19151 find-matching-primitive:  # primitives: (addr primitive), stmt: (addr stmt) -> result/eax: (addr primitive)
19152     # . prologue
19153     55/push-ebp
19154     89/<- %ebp 4/r32/esp
19155     # . save registers
19156     51/push-ecx
19157     # var curr/ecx: (addr primitive) = primitives
19158     8b/-> *(ebp+8) 1/r32/ecx
19159     {
19160 $find-matching-primitive:loop:
19161       # if (curr == null) break
19162       81 7/subop/compare %ecx 0/imm32
19163       74/jump-if-= break/disp8
19164       # if match(curr, stmt) return curr
19165       {
19166         (mu-stmt-matches-primitive? *(ebp+0xc) %ecx)  # => eax
19167         3d/compare-eax-and 0/imm32/false
19168         74/jump-if-= break/disp8
19169         89/<- %eax 1/r32/ecx
19170         eb/jump $find-matching-primitive:end/disp8
19171       }
19172 $find-matching-primitive:next-primitive:
19173       # curr = curr->next
19174       (lookup *(ecx+0x38) *(ecx+0x3c))  # Primitive-next Primitive-next => eax
19175       89/<- %ecx 0/r32/eax
19176       #
19177       e9/jump loop/disp32
19178     }
19179     # return null
19180     b8/copy-to-eax 0/imm32
19181 $find-matching-primitive:end:
19182     # . restore registers
19183     59/pop-to-ecx
19184     # . epilogue
19185     89/<- %esp 5/r32/ebp
19186     5d/pop-to-ebp
19187     c3/return
19188 
19189 mu-stmt-matches-primitive?:  # stmt: (addr stmt), primitive: (addr primitive) -> result/eax: boolean
19190     # A mu stmt matches a primitive if the name matches, all the inout vars
19191     # match, and all the output vars match.
19192     # Vars match if types match and registers match.
19193     # In addition, a stmt output matches a primitive's output if types match
19194     # and the primitive has a wildcard register.
19195     # . prologue
19196     55/push-ebp
19197     89/<- %ebp 4/r32/esp
19198     # . save registers
19199     51/push-ecx
19200     52/push-edx
19201     53/push-ebx
19202     56/push-esi
19203     57/push-edi
19204     # ecx = stmt
19205     8b/-> *(ebp+8) 1/r32/ecx
19206     # edx = primitive
19207     8b/-> *(ebp+0xc) 2/r32/edx
19208     {
19209 $mu-stmt-matches-primitive?:check-name:
19210       # if (primitive->name != stmt->operation) return false
19211       # . var esi: (addr array byte) = lookup(stmt->operation)
19212       (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
19213       89/<- %esi 0/r32/eax
19214       # . var edi: (addr array byte) = lookup(primitive->name)
19215       (lookup *edx *(edx+4))  # Primitive-name Primitive-name => eax
19216       89/<- %edi 0/r32/eax
19217       (string-equal? %esi %edi)  # => eax
19218       3d/compare-eax-and 0/imm32/false
19219       75/jump-if-!= break/disp8
19220       b8/copy-to-eax 0/imm32
19221       e9/jump $mu-stmt-matches-primitive?:end/disp32
19222     }
19223     # var curr/esi: (addr stmt-var) = lookup(stmt->inouts)
19224     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
19225     89/<- %esi 0/r32/eax
19226     # var curr2/edi: (addr list var) = lookup(primitive->inouts)
19227     (lookup *(edx+8) *(edx+0xc))  # Primitive-inouts Primitive-inouts => eax
19228     89/<- %edi 0/r32/eax
19229     {
19230 $mu-stmt-matches-primitive?:inouts-loop:
19231       # if (curr == 0 && curr2 == 0) move on to check outputs
19232       {
19233 $mu-stmt-matches-primitive?:check-both-inouts-null:
19234         81 7/subop/compare %esi 0/imm32
19235         75/jump-if-!= break/disp8
19236 $mu-stmt-matches-primitive?:stmt-inout-null:
19237         81 7/subop/compare %edi 0/imm32
19238         0f 84/jump-if-= $mu-stmt-matches-primitive?:check-outputs/disp32
19239 $mu-stmt-matches-primitive?:stmt-inout-null-and-prim-inout-not-null:
19240         # return false
19241         b8/copy-to-eax 0/imm32/false
19242         e9/jump $mu-stmt-matches-primitive?:end/disp32
19243       }
19244       # if (curr2 == 0) return false
19245       {
19246 $mu-stmt-matches-primitive?:check-prim-inout-null:
19247         81 7/subop/compare %edi 0/imm32
19248         75/jump-if-!= break/disp8
19249 $mu-stmt-matches-primitive?:prim-inout-null:
19250         b8/copy-to-eax 0/imm32/false
19251         e9/jump $mu-stmt-matches-primitive?:end/disp32
19252       }
19253       # if (curr != curr2) return false
19254       {
19255 $mu-stmt-matches-primitive?:check-inouts-match:
19256         (lookup *edi *(edi+4))  # List-value List-value => eax
19257         (operand-matches-primitive? %esi %eax)  # => eax
19258         3d/compare-eax-and 0/imm32/false
19259         75/jump-if-!= break/disp8
19260 $mu-stmt-matches-primitive?:inouts-match:
19261         b8/copy-to-eax 0/imm32/false
19262         e9/jump $mu-stmt-matches-primitive?:end/disp32
19263       }
19264 $mu-stmt-matches-primitive?:next-inout:
19265       # curr = lookup(curr->next)
19266       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
19267       89/<- %esi 0/r32/eax
19268       # curr2 = lookup(curr2->next)
19269       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
19270       89/<- %edi 0/r32/eax
19271       #
19272       e9/jump loop/disp32
19273     }
19274 $mu-stmt-matches-primitive?:check-outputs:
19275     # var curr/esi: (addr stmt-var) = lookup(stmt->outputs)
19276     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
19277     89/<- %esi 0/r32/eax
19278     # var curr2/edi: (addr list var) = lookup(primitive->outputs)
19279     (lookup *(edx+0x10) *(edx+0x14))  # Primitive-outputs Primitive-outputs => eax
19280     89/<- %edi 0/r32/eax
19281     {
19282 $mu-stmt-matches-primitive?:outputs-loop:
19283       # if (curr == 0) return (curr2 == 0)
19284       {
19285 $mu-stmt-matches-primitive?:check-both-outputs-null:
19286         81 7/subop/compare %esi 0/imm32
19287         75/jump-if-!= break/disp8
19288         {
19289 $mu-stmt-matches-primitive?:stmt-output-null:
19290           81 7/subop/compare %edi 0/imm32
19291           75/jump-if-!= break/disp8
19292 $mu-stmt-matches-primitive?:both-outputs-null:
19293           # return true
19294           b8/copy-to-eax 1/imm32
19295           e9/jump $mu-stmt-matches-primitive?:end/disp32
19296         }
19297 $mu-stmt-matches-primitive?:stmt-output-null-and-prim-output-not-null:
19298         # return false
19299         b8/copy-to-eax 0/imm32
19300         e9/jump $mu-stmt-matches-primitive?:end/disp32
19301       }
19302       # if (curr2 == 0) return false
19303       {
19304 $mu-stmt-matches-primitive?:check-prim-output-null:
19305         81 7/subop/compare %edi 0/imm32
19306         75/jump-if-!= break/disp8
19307 $mu-stmt-matches-primitive?:prim-output-is-null:
19308         b8/copy-to-eax 0/imm32
19309         e9/jump $mu-stmt-matches-primitive?:end/disp32
19310       }
19311       # if (curr != curr2) return false
19312       {
19313 $mu-stmt-matches-primitive?:check-outputs-match:
19314         (lookup *edi *(edi+4))  # List-value List-value => eax
19315         (operand-matches-primitive? %esi %eax)  # => eax
19316         3d/compare-eax-and 0/imm32/false
19317         75/jump-if-!= break/disp8
19318 $mu-stmt-matches-primitive?:outputs-match:
19319         b8/copy-to-eax 0/imm32
19320         e9/jump $mu-stmt-matches-primitive?:end/disp32
19321       }
19322 $mu-stmt-matches-primitive?:next-output:
19323       # curr = lookup(curr->next)
19324       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
19325       89/<- %esi 0/r32/eax
19326       # curr2 = lookup(curr2->next)
19327       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
19328       89/<- %edi 0/r32/eax
19329       #
19330       e9/jump loop/disp32
19331     }
19332 $mu-stmt-matches-primitive?:return-true:
19333     b8/copy-to-eax 1/imm32
19334 $mu-stmt-matches-primitive?:end:
19335     # . restore registers
19336     5f/pop-to-edi
19337     5e/pop-to-esi
19338     5b/pop-to-ebx
19339     5a/pop-to-edx
19340     59/pop-to-ecx
19341     # . epilogue
19342     89/<- %esp 5/r32/ebp
19343     5d/pop-to-ebp
19344     c3/return
19345 
19346 operand-matches-primitive?:  # s: (addr stmt-var), prim-var: (addr var) -> result/eax: boolean
19347     # . prologue
19348     55/push-ebp
19349     89/<- %ebp 4/r32/esp
19350     # . save registers
19351     51/push-ecx
19352     52/push-edx
19353     53/push-ebx
19354     56/push-esi
19355     57/push-edi
19356     # ecx = s
19357     8b/-> *(ebp+8) 1/r32/ecx
19358     # var var/esi: (addr var) = lookup(s->value)
19359     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
19360     89/<- %esi 0/r32/eax
19361     # edi = prim-var
19362     8b/-> *(ebp+0xc) 7/r32/edi
19363 $operand-matches-primitive?:check-type:
19364     # if !category-match?(var->type, prim-var->type) return false
19365     # . var vtype/ebx: (addr type-tree) = lookup(var->type)
19366     (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
19367     89/<- %ebx 0/r32/eax
19368     # . var ptype/eax: (addr type-tree) = lookup(prim-var->type)
19369     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
19370     (subx-type-category-match? %ebx %eax)  # => eax
19371     3d/compare-eax-and 0/imm32/false
19372     0f 84/jump-if-= $operand-matches-primitive?:return-false/disp32
19373     {
19374 $operand-matches-primitive?:check-register:
19375       # if prim-var is in memory and var is in register but dereference, match
19376       {
19377         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
19378         0f 85/jump-if-!= break/disp32
19379         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19380         74/jump-if-= break/disp8
19381         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19382         74/jump-if-= break/disp8
19383 $operand-matches-primitive?:var-deref-match:
19384         e9/jump $operand-matches-primitive?:return-true/disp32
19385       }
19386       # if prim-var is in register and var is in register but dereference, no match
19387       {
19388         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
19389         0f 84/jump-if-= break/disp32
19390         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19391         0f 84/jump-if-= break/disp32
19392         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19393         74/jump-if-= break/disp8
19394 $operand-matches-primitive?:var-deref-no-match:
19395         e9/jump $operand-matches-primitive?:return-false/disp32
19396       }
19397       # return false if var->register doesn't match prim-var->register
19398       {
19399         # if register addresses are equal, it's a match
19400         # var vreg/ebx: (addr array byte) = lookup(var->register)
19401         (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
19402         89/<- %ebx 0/r32/eax
19403         # var preg/ecx: (addr array byte) = lookup(prim-var->register)
19404         (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
19405         89/<- %ecx 0/r32/eax
19406         # if (vreg == preg) break
19407         39/compare %ecx 3/r32/ebx
19408         74/jump-if-= break/disp8
19409 $operand-matches-primitive?:var-register-no-match:
19410         # if either address is 0, return false
19411         81 7/subop/compare %ebx 0/imm32
19412         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
19413         81 7/subop/compare %ecx 0/imm32
19414         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
19415         # if prim-var->register is wildcard, it's a match
19416         (string-equal? %ecx "*")  # Any-register => eax
19417         3d/compare-eax-and 0/imm32/false
19418         75/jump-if-!= break/disp8
19419 $operand-matches-primitive?:wildcard-no-match:
19420         # if string contents aren't equal, return false
19421         (string-equal? %ecx %ebx)  # => eax
19422         3d/compare-eax-and 0/imm32/false
19423         74/jump-if-= $operand-matches-primitive?:return-false/disp8
19424       }
19425     }
19426 $operand-matches-primitive?:return-true:
19427     b8/copy-to-eax 1/imm32/true
19428     eb/jump $operand-matches-primitive?:end/disp8
19429 $operand-matches-primitive?:return-false:
19430     b8/copy-to-eax 0/imm32/false
19431 $operand-matches-primitive?:end:
19432     # . restore registers
19433     5f/pop-to-edi
19434     5e/pop-to-esi
19435     5b/pop-to-ebx
19436     5a/pop-to-edx
19437     59/pop-to-ecx
19438     # . epilogue
19439     89/<- %esp 5/r32/ebp
19440     5d/pop-to-ebp
19441     c3/return
19442 
19443 find-matching-function:  # functions: (addr function), stmt: (addr stmt) -> result/eax: (addr function)
19444     # . prologue
19445     55/push-ebp
19446     89/<- %ebp 4/r32/esp
19447     # . save registers
19448     51/push-ecx
19449     # var curr/ecx: (handle function) = functions
19450     8b/-> *(ebp+8) 1/r32/ecx
19451     {
19452       # if (curr == null) break
19453       81 7/subop/compare %ecx 0/imm32
19454       74/jump-if-= break/disp8
19455 #?       (write-buffered Stderr "iter\n")
19456 #?       (flush Stderr)
19457       # if match(stmt, curr) return curr
19458       {
19459         (mu-stmt-matches-function? *(ebp+0xc) %ecx)  # => eax
19460         3d/compare-eax-and 0/imm32/false
19461         74/jump-if-= break/disp8
19462         89/<- %eax 1/r32/ecx
19463         eb/jump $find-matching-function:end/disp8
19464       }
19465       # curr = curr->next
19466       (lookup *(ecx+0x20) *(ecx+0x24))  # Function-next Function-next => eax
19467       89/<- %ecx 0/r32/eax
19468       #
19469       eb/jump loop/disp8
19470     }
19471     # return null
19472     b8/copy-to-eax 0/imm32
19473 $find-matching-function:end:
19474     # . restore registers
19475     59/pop-to-ecx
19476     # . epilogue
19477     89/<- %esp 5/r32/ebp
19478     5d/pop-to-ebp
19479     c3/return
19480 
19481 # Just compare names; user-defined functions don't support overloading yet.
19482 mu-stmt-matches-function?:  # stmt: (addr stmt1), function: (addr function) -> result/eax: boolean
19483     # . prologue
19484     55/push-ebp
19485     89/<- %ebp 4/r32/esp
19486     # . save registers
19487     51/push-ecx
19488     # return function->name == stmt->operation
19489     # ecx = lookup(stmt->operation)
19490     8b/-> *(ebp+8) 0/r32/eax
19491     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
19492     89/<- %ecx 0/r32/eax
19493     # eax = lookup(function->name)
19494     8b/-> *(ebp+0xc) 0/r32/eax
19495     (lookup *eax *(eax+4))  # Function-name Function-name => eax
19496     (string-equal? %eax %ecx)  # => eax
19497 $mu-stmt-matches-function?:end:
19498     # . restore registers
19499     59/pop-to-ecx
19500     # . epilogue
19501     89/<- %esp 5/r32/ebp
19502     5d/pop-to-ebp
19503     c3/return
19504 
19505 # Type-checking happens elsewhere. This method is for selecting between
19506 # primitives.
19507 subx-type-category-match?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
19508     # . prologue
19509     55/push-ebp
19510     89/<- %ebp 4/r32/esp
19511     # . save registers
19512     51/push-ecx
19513     # var alit/ecx: boolean = is-literal-type?(a)
19514     (is-simple-mu-type? *(ebp+8) 0)  # => eax
19515     89/<- %ecx 0/r32/eax
19516     # var blit/eax: boolean = is-literal-type?(b)
19517     (is-simple-mu-type? *(ebp+0xc) 0)  # => eax
19518     # return alit == blit
19519     39/compare %eax 1/r32/ecx
19520     0f 94/set-byte-if-= %al
19521     81 4/subop/and %eax 0xff/imm32
19522 $subx-type-category-match?:end:
19523     # . restore registers
19524     59/pop-to-ecx
19525     # . epilogue
19526     89/<- %esp 5/r32/ebp
19527     5d/pop-to-ebp
19528     c3/return
19529 
19530 is-simple-mu-type?:  # a: (addr type-tree), n: type-id -> result/eax: boolean
19531     # . prologue
19532     55/push-ebp
19533     89/<- %ebp 4/r32/esp
19534     # . save registers
19535     51/push-ecx
19536     # ecx = n
19537     8b/-> *(ebp+0xc) 1/r32/ecx
19538     # return (a->value == n)
19539     8b/-> *(ebp+8) 0/r32/eax
19540     39/compare *(eax+4) 1/r32/ecx  # Type-tree-value
19541     0f 94/set-byte-if-= %al
19542     81 4/subop/and %eax 0xff/imm32
19543 $is-simple-mu-type?:end:
19544     # . restore registers
19545     59/pop-to-ecx
19546     # . epilogue
19547     89/<- %esp 5/r32/ebp
19548     5d/pop-to-ebp
19549     c3/return
19550 
19551 is-mu-addr-type?:  # a: (addr type-tree) -> result/eax: boolean
19552     # . prologue
19553     55/push-ebp
19554     89/<- %ebp 4/r32/esp
19555     # eax = a
19556     8b/-> *(ebp+8) 0/r32/eax
19557     # if (!a->is-atom?) a = a->left
19558     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
19559     {
19560       75/jump-if-!= break/disp8
19561       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
19562     }
19563     # return (a->value == addr)
19564     81 7/subop/compare *(eax+4) 2/imm32/addr  # Type-tree-value
19565     0f 94/set-byte-if-= %al
19566     81 4/subop/and %eax 0xff/imm32
19567 $is-mu-addr-type?:end:
19568     # . epilogue
19569     89/<- %esp 5/r32/ebp
19570     5d/pop-to-ebp
19571     c3/return
19572 
19573 is-mu-array-type?:  # a: (addr type-tree) -> result/eax: boolean
19574     # . prologue
19575     55/push-ebp
19576     89/<- %ebp 4/r32/esp
19577     # eax = a
19578     8b/-> *(ebp+8) 0/r32/eax
19579     # if (!a->is-atom?) a = a->left
19580     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
19581     {
19582       75/jump-if-!= break/disp8
19583       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
19584     }
19585     # return (a->value == array)
19586     81 7/subop/compare *(eax+4) 3/imm32/array  # Type-tree-value
19587     0f 94/set-byte-if-= %al
19588     81 4/subop/and %eax 0xff/imm32
19589 $is-mu-array-type?:end:
19590     # . epilogue
19591     89/<- %esp 5/r32/ebp
19592     5d/pop-to-ebp
19593     c3/return
19594 
19595 test-emit-subx-stmt-primitive:
19596     # Primitive operation on a variable on the stack.
19597     #   increment foo
19598     # =>
19599     #   ff 0/subop/increment *(ebp-8)
19600     #
19601     # There's a variable on the var stack as follows:
19602     #   name: 'foo'
19603     #   type: int
19604     #   stack-offset: -8
19605     #
19606     # There's a primitive with this info:
19607     #   name: 'increment'
19608     #   inouts: int/mem
19609     #   value: 'ff 0/subop/increment'
19610     #
19611     # . prologue
19612     55/push-ebp
19613     89/<- %ebp 4/r32/esp
19614     # setup
19615     (clear-stream _test-output-stream)
19616     (clear-stream $_test-output-buffered-file->buffer)
19617     # simulate allocated payloads starting with an initial fake alloc-id (0x11)
19618 $test-emit-subx-stmt-primitive:initialize-type:
19619     # var type/ecx: (payload type-tree) = int
19620     68/push 0/imm32/right:null
19621     68/push 0/imm32/right:null
19622     68/push 0/imm32/left:unused
19623     68/push 1/imm32/value:int
19624     68/push 1/imm32/is-atom?:true
19625     68/push 0x11/imm32/alloc-id:fake:payload
19626     89/<- %ecx 4/r32/esp
19627 $test-emit-subx-stmt-primitive:initialize-var:
19628     # var var-foo/ecx: (payload var) = var(type)
19629     68/push 0/imm32/no-register
19630     68/push 0/imm32/no-register
19631     68/push -8/imm32/stack-offset
19632     68/push 1/imm32/block-depth
19633     51/push-ecx/type
19634     68/push 0x11/imm32/alloc-id:fake
19635     68/push 0/imm32/name
19636     68/push 0/imm32/name
19637     68/push 0x11/imm32/alloc-id:fake:payload
19638     89/<- %ecx 4/r32/esp
19639 $test-emit-subx-stmt-primitive:initialize-var-name:
19640     # var-foo->name = "foo"
19641     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19642     (copy-array Heap "foo" %eax)
19643 $test-emit-subx-stmt-primitive:initialize-stmt-var:
19644     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
19645     68/push 0/imm32/is-deref:false
19646     68/push 0/imm32/next
19647     68/push 0/imm32/next
19648     51/push-ecx/var-foo
19649     68/push 0x11/imm32/alloc-id:fake
19650     68/push 0x11/imm32/alloc-id:fake:payload
19651     89/<- %ebx 4/r32/esp
19652 $test-emit-subx-stmt-primitive:initialize-stmt:
19653     # var stmt/esi: (addr statement)
19654     68/push 0/imm32/no-outputs
19655     68/push 0/imm32/no-outputs
19656     53/push-ebx/inouts
19657     68/push 0x11/imm32/alloc-id:fake
19658     68/push 0/imm32/operation
19659     68/push 0/imm32/operation
19660     68/push 1/imm32/tag
19661     89/<- %esi 4/r32/esp
19662 $test-emit-subx-stmt-primitive:initialize-stmt-operation:
19663     # stmt->operation = "increment"
19664     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19665     (copy-array Heap "increment" %eax)
19666 $test-emit-subx-stmt-primitive:initialize-primitive:
19667     # var primitives/ebx: (addr primitive)
19668     68/push 0/imm32/next
19669     68/push 0/imm32/next
19670     68/push 0/imm32/output-is-write-only
19671     68/push 0/imm32/no-disp32
19672     68/push 0/imm32/no-imm8
19673     68/push 0/imm32/no-imm32
19674     68/push 0/imm32/no-r32
19675     68/push 1/imm32/rm32-is-first-inout
19676     68/push 0/imm32/subx-name
19677     68/push 0/imm32/subx-name
19678     68/push 0/imm32/no-outputs
19679     68/push 0/imm32/no-outputs
19680     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
19681     68/push 0x11/imm32/alloc-id:fake
19682     68/push 0/imm32/name
19683     68/push 0/imm32/name
19684     89/<- %ebx 4/r32/esp
19685 $test-emit-subx-stmt-primitive:initialize-primitive-name:
19686     # primitives->name = "increment"
19687     (copy-array Heap "increment" %ebx)  # Primitive-name
19688 $test-emit-subx-stmt-primitive:initialize-primitive-subx-name:
19689     # primitives->subx-name = "ff 0/subop/increment"
19690     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
19691     (copy-array Heap "ff 0/subop/increment" %eax)
19692     # convert
19693     c7 0/subop/copy *Curr-block-depth 0/imm32
19694     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
19695     (flush _test-output-buffered-file)
19696 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
19702     # check output
19703     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-stmt-primitive")
19704     # . epilogue
19705     89/<- %esp 5/r32/ebp
19706     5d/pop-to-ebp
19707     c3/return
19708 
19709 test-emit-subx-stmt-primitive-register:
19710     # Primitive operation on a variable in a register.
19711     #   foo <- increment
19712     # =>
19713     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
19714     #
19715     # There's a variable on the var stack as follows:
19716     #   name: 'foo'
19717     #   type: int
19718     #   register: 'eax'
19719     #
19720     # There's a primitive with this info:
19721     #   name: 'increment'
19722     #   out: int/reg
19723     #   value: 'ff 0/subop/increment'
19724     #
19725     # . prologue
19726     55/push-ebp
19727     89/<- %ebp 4/r32/esp
19728     # setup
19729     (clear-stream _test-output-stream)
19730     (clear-stream $_test-output-buffered-file->buffer)
19731 $test-emit-subx-stmt-primitive-register:initialize-type:
19732     # var type/ecx: (payload type-tree) = int
19733     68/push 0/imm32/right:null
19734     68/push 0/imm32/right:null
19735     68/push 0/imm32/left:unused
19736     68/push 1/imm32/value:int
19737     68/push 1/imm32/is-atom?:true
19738     68/push 0x11/imm32/alloc-id:fake:payload
19739     89/<- %ecx 4/r32/esp
19740 $test-emit-subx-stmt-primitive-register:initialize-var:
19741     # var var-foo/ecx: (payload var)
19742     68/push 0/imm32/register
19743     68/push 0/imm32/register
19744     68/push 0/imm32/no-stack-offset
19745     68/push 1/imm32/block-depth
19746     51/push-ecx
19747     68/push 0x11/imm32/alloc-id:fake
19748     68/push 0/imm32/name
19749     68/push 0/imm32/name
19750     68/push 0x11/imm32/alloc-id:fake:payload
19751     89/<- %ecx 4/r32/esp
19752 $test-emit-subx-stmt-primitive-register:initialize-var-name:
19753     # var-foo->name = "foo"
19754     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19755     (copy-array Heap "foo" %eax)
19756 $test-emit-subx-stmt-primitive-register:initialize-var-register:
19757     # var-foo->register = "eax"
19758     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
19759     (copy-array Heap "eax" %eax)
19760 $test-emit-subx-stmt-primitive-register:initialize-stmt-var:
19761     # var operand/ebx: (payload stmt-var)
19762     68/push 0/imm32/is-deref:false
19763     68/push 0/imm32/next
19764     68/push 0/imm32/next
19765     51/push-ecx/var-foo
19766     68/push 0x11/imm32/alloc-id:fake
19767     68/push 0x11/imm32/alloc-id:fake:payload
19768     89/<- %ebx 4/r32/esp
19769 $test-emit-subx-stmt-primitive-register:initialize-stmt:
19770     # var stmt/esi: (addr statement)
19771     53/push-ebx/outputs
19772     68/push 0x11/imm32/alloc-id:fake
19773     68/push 0/imm32/no-inouts
19774     68/push 0/imm32/no-inouts
19775     68/push 0/imm32/operation
19776     68/push 0/imm32/operation
19777     68/push 1/imm32
19778     89/<- %esi 4/r32/esp
19779 $test-emit-subx-stmt-primitive-register:initialize-stmt-operation:
19780     # stmt->operation = "increment"
19781     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19782     (copy-array Heap "increment" %eax)
19783 $test-emit-subx-stmt-primitive-register:initialize-formal-var:
19784     # var formal-var/ebx: (payload var)
19785     68/push 0/imm32/register
19786     68/push 0/imm32/register
19787     68/push 0/imm32/no-stack-offset
19788     68/push 1/imm32/block-depth
19789     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
19790     68/push 0x11/imm32/alloc-id:fake
19791     68/push 0/imm32/name
19792     68/push 0/imm32/name
19793     68/push 0x11/imm32/alloc-id:fake:payload
19794     89/<- %ebx 4/r32/esp
19795 $test-emit-subx-stmt-primitive-register:initialize-formal-var-name:
19796     # formal-var->name = "dummy"
19797     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
19798     (copy-array Heap "dummy" %eax)
19799 $test-emit-subx-stmt-primitive-register:initialize-formal-register:
19800     # formal-var->register = "*"
19801     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
19802     (copy-array Heap "*" %eax)  # Any-register
19803 $test-emit-subx-stmt-primitive-register:initialize-var-list:
19804     # var formal-outputs/ebx: (payload list var)
19805     68/push 0/imm32/next
19806     68/push 0/imm32/next
19807     53/push-ebx/formal-var
19808     68/push 0x11/imm32/alloc-id:fake
19809     68/push 0x11/imm32/alloc-id:fake:payload
19810     89/<- %ebx 4/r32/esp
19811 $test-emit-subx-stmt-primitive-register:initialize-primitive:
19812     # var primitives/ebx: (addr primitive)
19813     68/push 0/imm32/next
19814     68/push 0/imm32/next
19815     68/push 0/imm32/output-is-write-only
19816     68/push 0/imm32/no-disp32
19817     68/push 0/imm32/no-imm8
19818     68/push 0/imm32/no-imm32
19819     68/push 0/imm32/no-r32
19820     68/push 3/imm32/rm32-is-first-output
19821     68/push 0/imm32/subx-name
19822     68/push 0/imm32/subx-name
19823     53/push-ebx/outputs
19824     68/push 0x11/imm32/alloc-id:fake
19825     68/push 0/imm32/no-inouts
19826     68/push 0/imm32/no-inouts
19827     68/push 0/imm32/name
19828     68/push 0/imm32/name
19829     89/<- %ebx 4/r32/esp
19830 $test-emit-subx-stmt-primitive-register:initialize-primitive-name:
19831     # primitives->name = "increment"
19832     (copy-array Heap "increment" %ebx)  # Primitive-name
19833 $test-emit-subx-stmt-primitive-register:initialize-primitive-subx-name:
19834     # primitives->subx-name = "ff 0/subop/increment"
19835     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
19836     (copy-array Heap "ff 0/subop/increment" %eax)
19837     # convert
19838     c7 0/subop/copy *Curr-block-depth 0/imm32
19839     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
19840     (flush _test-output-buffered-file)
19841 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
19847     # check output
19848     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-primitive-register")
19849     # . epilogue
19850     89/<- %esp 5/r32/ebp
19851     5d/pop-to-ebp
19852     c3/return
19853 
19854 test-emit-subx-stmt-select-primitive:
19855     # Select the right primitive between overloads.
19856     #   foo <- increment
19857     # =>
19858     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
19859     #
19860     # There's a variable on the var stack as follows:
19861     #   name: 'foo'
19862     #   type: int
19863     #   register: 'eax'
19864     #
19865     # There's two primitives, as follows:
19866     #   - name: 'increment'
19867     #     out: int/reg
19868     #     value: 'ff 0/subop/increment'
19869     #   - name: 'increment'
19870     #     inout: int/mem
19871     #     value: 'ff 0/subop/increment'
19872     #
19873     # . prologue
19874     55/push-ebp
19875     89/<- %ebp 4/r32/esp
19876     # setup
19877     (clear-stream _test-output-stream)
19878     (clear-stream $_test-output-buffered-file->buffer)
19879 $test-emit-subx-stmt-select-primitive:initialize-type:
19880     # var type/ecx: (payload type-tree) = int
19881     68/push 0/imm32/right:null
19882     68/push 0/imm32/right:null
19883     68/push 0/imm32/left:unused
19884     68/push 1/imm32/value:int
19885     68/push 1/imm32/is-atom?:true
19886     68/push 0x11/imm32/alloc-id:fake:payload
19887     89/<- %ecx 4/r32/esp
19888 $test-emit-subx-stmt-select-primitive:initialize-var:
19889     # var var-foo/ecx: (payload var)
19890     68/push 0/imm32/register
19891     68/push 0/imm32/register
19892     68/push 0/imm32/no-stack-offset
19893     68/push 1/imm32/block-depth
19894     51/push-ecx
19895     68/push 0x11/imm32/alloc-id:fake
19896     68/push 0/imm32/name
19897     68/push 0/imm32/name
19898     68/push 0x11/imm32/alloc-id:fake:payload
19899     89/<- %ecx 4/r32/esp
19900 $test-emit-subx-stmt-select-primitive:initialize-var-name:
19901     # var-foo->name = "foo"
19902     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19903     (copy-array Heap "foo" %eax)
19904 $test-emit-subx-stmt-select-primitive:initialize-var-register:
19905     # var-foo->register = "eax"
19906     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
19907     (copy-array Heap "eax" %eax)
19908 $test-emit-subx-stmt-select-primitive:initialize-stmt-var:
19909     # var operand/ebx: (payload stmt-var)
19910     68/push 0/imm32/is-deref:false
19911     68/push 0/imm32/next
19912     68/push 0/imm32/next
19913     51/push-ecx/var-foo
19914     68/push 0x11/imm32/alloc-id:fake
19915     68/push 0x11/imm32/alloc-id:fake:payload
19916     89/<- %ebx 4/r32/esp
19917 $test-emit-subx-stmt-select-primitive:initialize-stmt:
19918     # var stmt/esi: (addr statement)
19919     53/push-ebx/outputs
19920     68/push 0x11/imm32/alloc-id:fake
19921     68/push 0/imm32/no-inouts
19922     68/push 0/imm32/no-inouts
19923     68/push 0/imm32/operation
19924     68/push 0/imm32/operation
19925     68/push 1/imm32
19926     89/<- %esi 4/r32/esp
19927 $test-emit-subx-stmt-select-primitive:initialize-stmt-operation:
19928     # stmt->operation = "increment"
19929     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19930     (copy-array Heap "increment" %eax)
19931 $test-emit-subx-stmt-select-primitive:initialize-formal-var:
19932     # var formal-var/ebx: (payload var)
19933     68/push 0/imm32/register
19934     68/push 0/imm32/register
19935     68/push 0/imm32/no-stack-offset
19936     68/push 1/imm32/block-depth
19937     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
19938     68/push 0x11/imm32/alloc-id:fake
19939     68/push 0/imm32/name
19940     68/push 0/imm32/name
19941     68/push 0x11/imm32/alloc-id:fake:payload
19942     89/<- %ebx 4/r32/esp
19943 $test-emit-subx-stmt-select-primitive:initialize-formal-var-name:
19944     # formal-var->name = "dummy"
19945     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
19946     (copy-array Heap "dummy" %eax)
19947 $test-emit-subx-stmt-select-primitive:initialize-formal-register:
19948     # formal-var->register = "*"
19949     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
19950     (copy-array Heap "*" %eax)  # Any-register
19951 $test-emit-subx-stmt-select-primitive:initialize-var-list:
19952     # var formal-outputs/ebx: (payload list var)
19953     68/push 0/imm32/next
19954     68/push 0/imm32/next
19955     53/push-ebx/formal-var
19956     68/push 0x11/imm32/alloc-id:fake
19957     68/push 0x11/imm32/alloc-id:fake:payload
19958     89/<- %ebx 4/r32/esp
19959 $test-emit-subx-stmt-select-primitive:initialize-primitive2:
19960     # var primitive2/edi: (payload primitive)
19961     68/push 0/imm32/next
19962     68/push 0/imm32/next
19963     68/push 0/imm32/output-is-write-only
19964     68/push 0/imm32/no-disp32
19965     68/push 0/imm32/no-imm8
19966     68/push 0/imm32/no-imm32
19967     68/push 0/imm32/no-r32
19968     68/push 3/imm32/rm32-is-first-output
19969     68/push 0/imm32/subx-name
19970     68/push 0/imm32/subx-name
19971     53/push-ebx/outputs
19972     68/push 0x11/imm32/alloc-id:fake
19973     68/push 0/imm32/no-inouts
19974     68/push 0/imm32/no-inouts
19975     68/push 0/imm32/name
19976     68/push 0/imm32/name
19977     68/push 0x11/imm32/alloc-id:fake:payload
19978     89/<- %edi 4/r32/esp
19979 $test-emit-subx-stmt-select-primitive:initialize-primitive2-name:
19980     # primitives->name = "increment"
19981     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
19982     (copy-array Heap "increment" %eax)
19983 $test-emit-subx-stmt-select-primitive:initialize-primitive2-subx-name:
19984     # primitives->subx-name = "ff 0/subop/increment"
19985     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
19986     (copy-array Heap "ff 0/subop/increment" %eax)
19987 $test-emit-subx-stmt-select-primitive:initialize-primitive:
19988     # var primitives/ebx: (addr primitive)
19989     57/push-edi
19990     68/push 0x11/imm32/alloc-id:fake
19991     68/push 0/imm32/output-is-write-only
19992     68/push 0/imm32/no-disp32
19993     68/push 0/imm32/no-imm8
19994     68/push 0/imm32/no-imm32
19995     68/push 0/imm32/no-r32
19996     68/push 1/imm32/rm32-is-first-inout
19997     68/push 0/imm32/subx-name
19998     68/push 0/imm32/subx-name
19999     68/push 0/imm32/no-outputs
20000     68/push 0/imm32/no-outputs
20001     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
20002     68/push 0x11/imm32/alloc-id:fake
20003     68/push 0/imm32/name
20004     68/push 0/imm32/name
20005     89/<- %ebx 4/r32/esp
20006 $test-emit-subx-stmt-select-primitive:initialize-primitive-name:
20007     # primitives->name = "increment"
20008     (copy-array Heap "increment" %ebx)  # Primitive-name
20009 $test-emit-subx-stmt-select-primitive:initialize-primitive-subx-name:
20010     # primitives->subx-name = "ff 0/subop/increment"
20011     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
20012     (copy-array Heap "ff 0/subop/increment" %eax)
20013     # convert
20014     c7 0/subop/copy *Curr-block-depth 0/imm32
20015     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
20016     (flush _test-output-buffered-file)
20017 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20023     # check output
20024     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive")
20025     # . epilogue
20026     89/<- %esp 5/r32/ebp
20027     5d/pop-to-ebp
20028     c3/return
20029 
20030 test-emit-subx-stmt-select-primitive-2:
20031     # Select the right primitive between overloads.
20032     #   increment foo
20033     # =>
20034     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
20035     #
20036     # There's a variable on the var stack as follows:
20037     #   name: 'foo'
20038     #   type: int
20039     #   register: 'eax'
20040     #
20041     # There's two primitives, as follows:
20042     #   - name: 'increment'
20043     #     out: int/reg
20044     #     value: 'ff 0/subop/increment'
20045     #   - name: 'increment'
20046     #     inout: int/mem
20047     #     value: 'ff 0/subop/increment'
20048     #
20049     # . prologue
20050     55/push-ebp
20051     89/<- %ebp 4/r32/esp
20052     # setup
20053     (clear-stream _test-output-stream)
20054     (clear-stream $_test-output-buffered-file->buffer)
20055 $test-emit-subx-stmt-select-primitive-2:initialize-type:
20056     # var type/ecx: (payload type-tree) = int
20057     68/push 0/imm32/right:null
20058     68/push 0/imm32/right:null
20059     68/push 0/imm32/left:unused
20060     68/push 1/imm32/value:int
20061     68/push 1/imm32/is-atom?:true
20062     68/push 0x11/imm32/alloc-id:fake:payload
20063     89/<- %ecx 4/r32/esp
20064 $test-emit-subx-stmt-select-primitive-2:initialize-var:
20065     # var var-foo/ecx: (payload var)
20066     68/push 0/imm32/register
20067     68/push 0/imm32/register
20068     68/push 0/imm32/no-stack-offset
20069     68/push 1/imm32/block-depth
20070     51/push-ecx
20071     68/push 0x11/imm32/alloc-id:fake
20072     68/push 0/imm32/name
20073     68/push 0/imm32/name
20074     68/push 0x11/imm32/alloc-id:fake:payload
20075     89/<- %ecx 4/r32/esp
20076 $test-emit-subx-stmt-select-primitive-2:initialize-var-name:
20077     # var-foo->name = "foo"
20078     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20079     (copy-array Heap "foo" %eax)
20080 $test-emit-subx-stmt-select-primitive-2:initialize-var-register:
20081     # var-foo->register = "eax"
20082     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20083     (copy-array Heap "eax" %eax)
20084 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-var:
20085     # var operand/ebx: (payload stmt-var)
20086     68/push 0/imm32/is-deref:false
20087     68/push 0/imm32/next
20088     68/push 0/imm32/next
20089     51/push-ecx/var-foo
20090     68/push 0x11/imm32/alloc-id:fake
20091     68/push 0x11/imm32/alloc-id:fake:payload
20092     89/<- %ebx 4/r32/esp
20093 $test-emit-subx-stmt-select-primitive-2:initialize-stmt:
20094     # var stmt/esi: (addr statement)
20095     68/push 0/imm32/no-outputs
20096     68/push 0/imm32/no-outputs
20097     53/push-ebx/inouts
20098     68/push 0x11/imm32/alloc-id:fake
20099     68/push 0/imm32/operation
20100     68/push 0/imm32/operation
20101     68/push 1/imm32
20102     89/<- %esi 4/r32/esp
20103 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-operation:
20104     # stmt->operation = "increment"
20105     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20106     (copy-array Heap "increment" %eax)
20107 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var:
20108     # var formal-var/ebx: (payload var)
20109     68/push 0/imm32/register
20110     68/push 0/imm32/register
20111     68/push 0/imm32/no-stack-offset
20112     68/push 1/imm32/block-depth
20113     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
20114     68/push 0x11/imm32/alloc-id:fake
20115     68/push 0/imm32/name
20116     68/push 0/imm32/name
20117     68/push 0x11/imm32/alloc-id:fake:payload
20118     89/<- %ebx 4/r32/esp
20119 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var-name:
20120     # formal-var->name = "dummy"
20121     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
20122     (copy-array Heap "dummy" %eax)
20123 $test-emit-subx-stmt-select-primitive-2:initialize-formal-register:
20124     # formal-var->register = "*"
20125     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
20126     (copy-array Heap "*" %eax)  # Any-register
20127 $test-emit-subx-stmt-select-primitive-2:initialize-var-list:
20128     # var formal-outputs/ebx: (payload list stmt-var)
20129     68/push 0/imm32/next
20130     68/push 0/imm32/next
20131     53/push-ebx/formal-var
20132     68/push 0x11/imm32/alloc-id:fake
20133     68/push 0x11/imm32/alloc-id:fake:payload
20134     89/<- %ebx 4/r32/esp
20135 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2:
20136     # var primitive2/edi: (payload primitive)
20137     68/push 0/imm32/next
20138     68/push 0/imm32/next
20139     68/push 0/imm32/output-is-write-only
20140     68/push 0/imm32/no-disp32
20141     68/push 0/imm32/no-imm8
20142     68/push 0/imm32/no-imm32
20143     68/push 0/imm32/no-r32
20144     68/push 3/imm32/rm32-is-first-output
20145     68/push 0/imm32/subx-name
20146     68/push 0/imm32/subx-name
20147     53/push-ebx/outputs
20148     68/push 0x11/imm32/alloc-id:fake
20149     68/push 0/imm32/no-inouts
20150     68/push 0/imm32/no-inouts
20151     68/push 0/imm32/name
20152     68/push 0/imm32/name
20153     68/push 0x11/imm32/alloc-id:fake:payload
20154     89/<- %edi 4/r32/esp
20155 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-name:
20156     # primitives->name = "increment"
20157     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
20158     (copy-array Heap "increment" %eax)
20159 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-subx-name:
20160     # primitives->subx-name = "ff 0/subop/increment"
20161     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
20162     (copy-array Heap "ff 0/subop/increment" %eax)
20163 $test-emit-subx-stmt-select-primitive-2:initialize-primitive:
20164     # var primitives/ebx: (addr primitive)
20165     57/push-edi
20166     68/push 0x11/imm32/alloc-id:fake
20167     68/push 0/imm32/output-is-write-only
20168     68/push 0/imm32/no-disp32
20169     68/push 0/imm32/no-imm8
20170     68/push 0/imm32/no-imm32
20171     68/push 0/imm32/no-r32
20172     68/push 1/imm32/rm32-is-first-inout
20173     68/push 0/imm32/subx-name
20174     68/push 0/imm32/subx-name
20175     68/push 0/imm32/no-outputs
20176     68/push 0/imm32/no-outputs
20177     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
20178     68/push 0x11/imm32/alloc-id:fake
20179     68/push 0/imm32/name
20180     68/push 0/imm32/name
20181     89/<- %ebx 4/r32/esp
20182 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-name:
20183     # primitives->name = "increment"
20184     (copy-array Heap "increment" %ebx)  # Primitive-name
20185 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-subx-name:
20186     # primitives->subx-name = "ff 0/subop/increment"
20187     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
20188     (copy-array Heap "ff 0/subop/increment" %eax)
20189     # convert
20190     c7 0/subop/copy *Curr-block-depth 0/imm32
20191     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
20192     (flush _test-output-buffered-file)
20193 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20199     # check output
20200     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive-2")
20201     # . epilogue
20202     89/<- %esp 5/r32/ebp
20203     5d/pop-to-ebp
20204     c3/return
20205 
20206 test-increment-register:
20207     # Select the right register between overloads.
20208     #   foo <- increment
20209     # =>
20210     #   50/increment-eax
20211     #
20212     # There's a variable on the var stack as follows:
20213     #   name: 'foo'
20214     #   type: int
20215     #   register: 'eax'
20216     #
20217     # Primitives are the global definitions.
20218     #
20219     # . prologue
20220     55/push-ebp
20221     89/<- %ebp 4/r32/esp
20222     # setup
20223     (clear-stream _test-output-stream)
20224     (clear-stream $_test-output-buffered-file->buffer)
20225 $test-increment-register:initialize-type:
20226     # var type/ecx: (payload type-tree) = int
20227     68/push 0/imm32/right:null
20228     68/push 0/imm32/right:null
20229     68/push 0/imm32/left:unused
20230     68/push 1/imm32/value:int
20231     68/push 1/imm32/is-atom?:true
20232     68/push 0x11/imm32/alloc-id:fake:payload
20233     89/<- %ecx 4/r32/esp
20234 $test-increment-register:initialize-var:
20235     # var var-foo/ecx: (payload var)
20236     68/push 0/imm32/register
20237     68/push 0/imm32/register
20238     68/push 0/imm32/no-stack-offset
20239     68/push 1/imm32/block-depth
20240     51/push-ecx
20241     68/push 0x11/imm32/alloc-id:fake
20242     68/push 0/imm32/name
20243     68/push 0/imm32/name
20244     68/push 0x11/imm32/alloc-id:fake:payload
20245     89/<- %ecx 4/r32/esp
20246 $test-increment-register:initialize-var-name:
20247     # var-foo->name = "foo"
20248     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20249     (copy-array Heap "foo" %eax)
20250 $test-increment-register:initialize-var-register:
20251     # var-foo->register = "eax"
20252     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20253     (copy-array Heap "eax" %eax)
20254 $test-increment-register:initialize-stmt-var:
20255     # var operand/ebx: (payload stmt-var)
20256     68/push 0/imm32/is-deref:false
20257     68/push 0/imm32/next
20258     68/push 0/imm32/next
20259     51/push-ecx/var-foo
20260     68/push 0x11/imm32/alloc-id:fake
20261     68/push 0x11/imm32/alloc-id:fake:payload
20262     89/<- %ebx 4/r32/esp
20263 $test-increment-register:initialize-stmt:
20264     # var stmt/esi: (addr statement)
20265     53/push-ebx/outputs
20266     68/push 0x11/imm32/alloc-id:fake
20267     68/push 0/imm32/no-inouts
20268     68/push 0/imm32/no-inouts
20269     68/push 0/imm32/operation
20270     68/push 0/imm32/operation
20271     68/push 1/imm32
20272     89/<- %esi 4/r32/esp
20273 $test-increment-register:initialize-stmt-operation:
20274     # stmt->operation = "increment"
20275     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20276     (copy-array Heap "increment" %eax)
20277     # convert
20278     c7 0/subop/copy *Curr-block-depth 0/imm32
20279     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
20280     (flush _test-output-buffered-file)
20281 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20287     # check output
20288     (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register")
20289     # . epilogue
20290     89/<- %esp 5/r32/ebp
20291     5d/pop-to-ebp
20292     c3/return
20293 
20294 test-add-reg-to-reg:
20295     #   var1/reg <- add var2/reg
20296     # =>
20297     #   01/add-to %var1 var2
20298     #
20299     # . prologue
20300     55/push-ebp
20301     89/<- %ebp 4/r32/esp
20302     # setup
20303     (clear-stream _test-output-stream)
20304     (clear-stream $_test-output-buffered-file->buffer)
20305 $test-add-reg-to-reg:initialize-type:
20306     # var type/ecx: (payload type-tree) = int
20307     68/push 0/imm32/right:null
20308     68/push 0/imm32/right:null
20309     68/push 0/imm32/left:unused
20310     68/push 1/imm32/value:int
20311     68/push 1/imm32/is-atom?:true
20312     68/push 0x11/imm32/alloc-id:fake:payload
20313     89/<- %ecx 4/r32/esp
20314 $test-add-reg-to-reg:initialize-var1:
20315     # var var1/ecx: (payload var)
20316     68/push 0/imm32/register
20317     68/push 0/imm32/register
20318     68/push 0/imm32/no-stack-offset
20319     68/push 1/imm32/block-depth
20320     51/push-ecx
20321     68/push 0x11/imm32/alloc-id:fake
20322     68/push 0/imm32/name
20323     68/push 0/imm32/name
20324     68/push 0x11/imm32/alloc-id:fake:payload
20325     89/<- %ecx 4/r32/esp
20326 $test-add-reg-to-reg:initialize-var1-name:
20327     # var1->name = "var1"
20328     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20329     (copy-array Heap "var1" %eax)
20330 $test-add-reg-to-reg:initialize-var1-register:
20331     # var1->register = "eax"
20332     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20333     (copy-array Heap "eax" %eax)
20334 $test-add-reg-to-reg:initialize-var2:
20335     # var var2/edx: (payload var)
20336     68/push 0/imm32/register
20337     68/push 0/imm32/register
20338     68/push 0/imm32/no-stack-offset
20339     68/push 1/imm32/block-depth
20340     ff 6/subop/push *(ecx+0x10)
20341     68/push 0x11/imm32/alloc-id:fake
20342     68/push 0/imm32/name
20343     68/push 0/imm32/name
20344     68/push 0x11/imm32/alloc-id:fake:payload
20345     89/<- %edx 4/r32/esp
20346 $test-add-reg-to-reg:initialize-var2-name:
20347     # var2->name = "var2"
20348     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
20349     (copy-array Heap "var2" %eax)
20350 $test-add-reg-to-reg:initialize-var2-register:
20351     # var2->register = "ecx"
20352     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
20353     (copy-array Heap "ecx" %eax)
20354 $test-add-reg-to-reg:initialize-inouts:
20355     # var inouts/esi: (payload stmt-var) = [var2]
20356     68/push 0/imm32/is-deref:false
20357     68/push 0/imm32/next
20358     68/push 0/imm32/next
20359     52/push-edx/var2
20360     68/push 0x11/imm32/alloc-id:fake
20361     68/push 0x11/imm32/alloc-id:fake:payload
20362     89/<- %esi 4/r32/esp
20363 $test-add-reg-to-reg:initialize-outputs:
20364     # var outputs/edi: (payload stmt-var) = [var1]
20365     68/push 0/imm32/is-deref:false
20366     68/push 0/imm32/next
20367     68/push 0/imm32/next
20368     51/push-ecx/var1
20369     68/push 0x11/imm32/alloc-id:fake
20370     68/push 0x11/imm32/alloc-id:fake:payload
20371     89/<- %edi 4/r32/esp
20372 $test-add-reg-to-reg:initialize-stmt:
20373     # var stmt/esi: (addr statement)
20374     68/push 0/imm32/next
20375     68/push 0/imm32/next
20376     57/push-edi/outputs
20377     68/push 0x11/imm32/alloc-id:fake
20378     56/push-esi/inouts
20379     68/push 0x11/imm32/alloc-id:fake
20380     68/push 0/imm32/operation
20381     68/push 0/imm32/operation
20382     68/push 1/imm32/tag:stmt1
20383     89/<- %esi 4/r32/esp
20384 $test-add-reg-to-reg:initialize-stmt-operation:
20385     # stmt->operation = "add"
20386     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20387     (copy-array Heap "add" %eax)
20388     # convert
20389     c7 0/subop/copy *Curr-block-depth 0/imm32
20390     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
20391     (flush _test-output-buffered-file)
20392 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20398     # check output
20399     (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg")
20400     # . epilogue
20401     89/<- %esp 5/r32/ebp
20402     5d/pop-to-ebp
20403     c3/return
20404 
20405 test-add-reg-to-mem:
20406     #   add-to var1 var2/reg
20407     # =>
20408     #   01/add-to *(ebp+__) var2
20409     #
20410     # . prologue
20411     55/push-ebp
20412     89/<- %ebp 4/r32/esp
20413     # setup
20414     (clear-stream _test-output-stream)
20415     (clear-stream $_test-output-buffered-file->buffer)
20416 $test-add-reg-to-mem:initialize-type:
20417     # var type/ecx: (payload type-tree) = int
20418     68/push 0/imm32/right:null
20419     68/push 0/imm32/right:null
20420     68/push 0/imm32/left:unused
20421     68/push 1/imm32/value:int
20422     68/push 1/imm32/is-atom?:true
20423     68/push 0x11/imm32/alloc-id:fake:payload
20424     89/<- %ecx 4/r32/esp
20425 $test-add-reg-to-mem:initialize-var1:
20426     # var var1/ecx: (payload var)
20427     68/push 0/imm32/register
20428     68/push 0/imm32/register
20429     68/push 8/imm32/stack-offset
20430     68/push 1/imm32/block-depth
20431     51/push-ecx
20432     68/push 0x11/imm32/alloc-id:fake
20433     68/push 0/imm32/name
20434     68/push 0/imm32/name
20435     68/push 0x11/imm32/alloc-id:fake:payload
20436     89/<- %ecx 4/r32/esp
20437 $test-add-reg-to-mem:initialize-var1-name:
20438     # var1->name = "var1"
20439     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20440     (copy-array Heap "var1" %eax)
20441 $test-add-reg-to-mem:initialize-var2:
20442     # var var2/edx: (payload var)
20443     68/push 0/imm32/register
20444     68/push 0/imm32/register
20445     68/push 0/imm32/no-stack-offset
20446     68/push 1/imm32/block-depth
20447     ff 6/subop/push *(ecx+0x10)
20448     68/push 0x11/imm32/alloc-id:fake
20449     68/push 0/imm32/name
20450     68/push 0/imm32/name
20451     68/push 0x11/imm32/alloc-id:fake:payload
20452     89/<- %edx 4/r32/esp
20453 $test-add-reg-to-mem:initialize-var2-name:
20454     # var2->name = "var2"
20455     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
20456     (copy-array Heap "var2" %eax)
20457 $test-add-reg-to-mem:initialize-var2-register:
20458     # var2->register = "ecx"
20459     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
20460     (copy-array Heap "ecx" %eax)
20461 $test-add-reg-to-mem:initialize-inouts:
20462     # var inouts/esi: (payload stmt-var) = [var2]
20463     68/push 0/imm32/is-deref:false
20464     68/push 0/imm32/next
20465     68/push 0/imm32/next
20466     52/push-edx/var2
20467     68/push 0x11/imm32/alloc-id:fake
20468     68/push 0x11/imm32/alloc-id:fake:payload
20469     89/<- %esi 4/r32/esp
20470     # inouts = [var1, var2]
20471     68/push 0/imm32/is-deref:false
20472     56/push-esi/next
20473     68/push 0x11/imm32/alloc-id:fake
20474     51/push-ecx/var1
20475     68/push 0x11/imm32/alloc-id:fake
20476     68/push 0x11/imm32/alloc-id:fake:payload
20477     89/<- %esi 4/r32/esp
20478 $test-add-reg-to-mem:initialize-stmt:
20479     # var stmt/esi: (addr statement)
20480     68/push 0/imm32/next
20481     68/push 0/imm32/next
20482     68/push 0/imm32/outputs
20483     68/push 0/imm32/outputs
20484     56/push-esi/inouts
20485     68/push 0x11/imm32/alloc-id:fake
20486     68/push 0/imm32/operation
20487     68/push 0/imm32/operation
20488     68/push 1/imm32/tag:stmt1
20489     89/<- %esi 4/r32/esp
20490 $test-add-reg-to-mem:initialize-stmt-operation:
20491     # stmt->operation = "add-to"
20492     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20493     (copy-array Heap "add-to" %eax)
20494     # convert
20495     c7 0/subop/copy *Curr-block-depth 0/imm32
20496     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
20497     (flush _test-output-buffered-file)
20498 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20504     # check output
20505     (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem")
20506     # . epilogue
20507     89/<- %esp 5/r32/ebp
20508     5d/pop-to-ebp
20509     c3/return
20510 
20511 test-add-mem-to-reg:
20512     #   var1/reg <- add var2
20513     # =>
20514     #   03/add *(ebp+__) var1
20515     #
20516     # . prologue
20517     55/push-ebp
20518     89/<- %ebp 4/r32/esp
20519     # setup
20520     (clear-stream _test-output-stream)
20521     (clear-stream $_test-output-buffered-file->buffer)
20522 $test-add-mem-to-reg:initialize-type:
20523     # var type/ecx: (payload type-tree) = int
20524     68/push 0/imm32/right:null
20525     68/push 0/imm32/right:null
20526     68/push 0/imm32/left:unused
20527     68/push 1/imm32/value:int
20528     68/push 1/imm32/is-atom?:true
20529     68/push 0x11/imm32/alloc-id:fake:payload
20530     89/<- %ecx 4/r32/esp
20531 $test-add-mem-to-reg:initialize-var:
20532     # var var1/ecx: (payload var)
20533     68/push 0/imm32/register
20534     68/push 0/imm32/register
20535     68/push 0/imm32/no-stack-offset
20536     68/push 1/imm32/block-depth
20537     51/push-ecx
20538     68/push 0x11/imm32/alloc-id:fake
20539     68/push 0/imm32/name
20540     68/push 0/imm32/name
20541     68/push 0x11/imm32/alloc-id:fake:payload
20542     89/<- %ecx 4/r32/esp
20543 $test-add-mem-to-reg:initialize-var-name:
20544     # var1->name = "foo"
20545     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20546     (copy-array Heap "var1" %eax)
20547 $test-add-mem-to-reg:initialize-var-register:
20548     # var1->register = "eax"
20549     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20550     (copy-array Heap "eax" %eax)
20551 $test-add-mem-to-reg:initialize-var2:
20552     # var var2/edx: (payload var)
20553     68/push 0/imm32/register
20554     68/push 0/imm32/register
20555     68/push 8/imm32/stack-offset
20556     68/push 1/imm32/block-depth
20557     ff 6/subop/push *(ecx+0x10)
20558     68/push 0x11/imm32/alloc-id:fake
20559     68/push 0/imm32/name
20560     68/push 0/imm32/name
20561     68/push 0x11/imm32/alloc-id:fake:payload
20562     89/<- %edx 4/r32/esp
20563 $test-add-mem-to-reg:initialize-var2-name:
20564     # var2->name = "var2"
20565     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
20566     (copy-array Heap "var2" %eax)
20567 $test-add-mem-to-reg:initialize-inouts:
20568     # var inouts/esi: (payload stmt-var) = [var2]
20569     68/push 0/imm32/is-deref:false
20570     68/push 0/imm32/next
20571     68/push 0/imm32/next
20572     52/push-edx/var2
20573     68/push 0x11/imm32/alloc-id:fake
20574     68/push 0x11/imm32/alloc-id:fake:payload
20575     89/<- %esi 4/r32/esp
20576 $test-add-mem-to-reg:initialize-outputs:
20577     # var outputs/edi: (payload stmt-var) = [var1]
20578     68/push 0/imm32/is-deref:false
20579     68/push 0/imm32/next
20580     68/push 0/imm32/next
20581     51/push-ecx/var1
20582     68/push 0x11/imm32/alloc-id:fake
20583     68/push 0x11/imm32/alloc-id:fake:payload
20584     89/<- %edi 4/r32/esp
20585 $test-add-mem-to-reg:initialize-stmt:
20586     # var stmt/esi: (addr statement)
20587     68/push 0/imm32/next
20588     68/push 0/imm32/next
20589     57/push-edi/outputs
20590     68/push 0x11/imm32/alloc-id:fake
20591     56/push-esi/inouts
20592     68/push 0x11/imm32/alloc-id:fake
20593     68/push 0/imm32/operation
20594     68/push 0/imm32/operation
20595     68/push 1/imm32/tag:stmt1
20596     89/<- %esi 4/r32/esp
20597 $test-add-mem-to-reg:initialize-stmt-operation:
20598     # stmt->operation = "add"
20599     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20600     (copy-array Heap "add" %eax)
20601     # convert
20602     c7 0/subop/copy *Curr-block-depth 0/imm32
20603     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
20604     (flush _test-output-buffered-file)
20605 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20611     # check output
20612     (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg")
20613     # . epilogue
20614     89/<- %esp 5/r32/ebp
20615     5d/pop-to-ebp
20616     c3/return
20617 
20618 test-add-literal-to-eax:
20619     #   var1/eax <- add 0x34
20620     # =>
20621     #   05/add-to-eax 0x34/imm32
20622     #
20623     # . prologue
20624     55/push-ebp
20625     89/<- %ebp 4/r32/esp
20626     # setup
20627     (clear-stream _test-output-stream)
20628     (clear-stream $_test-output-buffered-file->buffer)
20629 $test-add-literal-to-eax:initialize-var-type:
20630     # var type/ecx: (payload type-tree) = int
20631     68/push 0/imm32/right:null
20632     68/push 0/imm32/right:null
20633     68/push 0/imm32/left:unused
20634     68/push 1/imm32/value:int
20635     68/push 1/imm32/is-atom?:true
20636     68/push 0x11/imm32/alloc-id:fake:payload
20637     89/<- %ecx 4/r32/esp
20638 $test-add-literal-to-eax:initialize-var:
20639     # var v/ecx: (payload var)
20640     68/push 0/imm32/register
20641     68/push 0/imm32/register
20642     68/push 0/imm32/no-stack-offset
20643     68/push 1/imm32/block-depth
20644     51/push-ecx
20645     68/push 0x11/imm32/alloc-id:fake
20646     68/push 0/imm32/name
20647     68/push 0/imm32/name
20648     68/push 0x11/imm32/alloc-id:fake:payload
20649     89/<- %ecx 4/r32/esp
20650 $test-add-literal-to-eax:initialize-var-name:
20651     # v->name = "v"
20652     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20653     (copy-array Heap "v" %eax)
20654 $test-add-literal-to-eax:initialize-var-register:
20655     # v->register = "eax"
20656     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20657     (copy-array Heap "eax" %eax)
20658 $test-add-literal-to-eax:initialize-literal-type:
20659     # var type/edx: (payload type-tree) = literal
20660     68/push 0/imm32/right:null
20661     68/push 0/imm32/right:null
20662     68/push 0/imm32/left:unused
20663     68/push 0/imm32/value:literal
20664     68/push 1/imm32/is-atom?:true
20665     68/push 0x11/imm32/alloc-id:fake:payload
20666     89/<- %edx 4/r32/esp
20667 $test-add-literal-to-eax:initialize-literal:
20668     # var l/edx: (payload var)
20669     68/push 0/imm32/register
20670     68/push 0/imm32/register
20671     68/push 0/imm32/no-stack-offset
20672     68/push 1/imm32/block-depth
20673     52/push-edx
20674     68/push 0x11/imm32/alloc-id:fake
20675     68/push 0/imm32/name
20676     68/push 0/imm32/name
20677     68/push 0x11/imm32/alloc-id:fake:payload
20678     89/<- %edx 4/r32/esp
20679 $test-add-literal-to-eax:initialize-literal-value:
20680     # l->name = "0x34"
20681     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
20682     (copy-array Heap "0x34" %eax)
20683 $test-add-literal-to-eax:initialize-inouts:
20684     # var inouts/esi: (payload stmt-var) = [l]
20685     68/push 0/imm32/is-deref:false
20686     68/push 0/imm32/next
20687     68/push 0/imm32/next
20688     52/push-edx/l
20689     68/push 0x11/imm32/alloc-id:fake
20690     68/push 0x11/imm32/alloc-id:fake:payload
20691     89/<- %esi 4/r32/esp
20692 $test-add-literal-to-eax:initialize-outputs:
20693     # var outputs/edi: (payload stmt-var) = [v]
20694     68/push 0/imm32/is-deref:false
20695     68/push 0/imm32/next
20696     68/push 0/imm32/next
20697     51/push-ecx/v
20698     68/push 0x11/imm32/alloc-id:fake
20699     68/push 0x11/imm32/alloc-id:fake:payload
20700     89/<- %edi 4/r32/esp
20701 $test-add-literal-to-eax:initialize-stmt:
20702     # var stmt/esi: (addr statement)
20703     68/push 0/imm32/next
20704     68/push 0/imm32/next
20705     57/push-edi/outputs
20706     68/push 0x11/imm32/alloc-id:fake
20707     56/push-esi/inouts
20708     68/push 0x11/imm32/alloc-id:fake
20709     68/push 0/imm32/operation
20710     68/push 0/imm32/operation
20711     68/push 1/imm32/tag:stmt1
20712     89/<- %esi 4/r32/esp
20713 $test-add-literal-to-eax:initialize-stmt-operation:
20714     # stmt->operation = "add"
20715     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20716     (copy-array Heap "add" %eax)
20717     # convert
20718     c7 0/subop/copy *Curr-block-depth 0/imm32
20719     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
20720     (flush _test-output-buffered-file)
20721 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20727     # check output
20728     (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax")
20729     # . epilogue
20730     89/<- %esp 5/r32/ebp
20731     5d/pop-to-ebp
20732     c3/return
20733 
20734 test-add-literal-to-reg:
20735     #   var1/ecx <- add 0x34
20736     # =>
20737     #   81 0/subop/add %ecx 0x34/imm32
20738     #
20739     # . prologue
20740     55/push-ebp
20741     89/<- %ebp 4/r32/esp
20742     # setup
20743     (clear-stream _test-output-stream)
20744     (clear-stream $_test-output-buffered-file->buffer)
20745 $test-add-literal-to-reg:initialize-var-type:
20746     # var type/ecx: (payload type-tree) = int
20747     68/push 0/imm32/right:null
20748     68/push 0/imm32/right:null
20749     68/push 0/imm32/left:unused
20750     68/push 1/imm32/value:int
20751     68/push 1/imm32/is-atom?:true
20752     68/push 0x11/imm32/alloc-id:fake:payload
20753     89/<- %ecx 4/r32/esp
20754 $test-add-literal-to-reg:initialize-var:
20755     # var v/ecx: (payload var)
20756     68/push 0/imm32/register
20757     68/push 0/imm32/register
20758     68/push 0/imm32/no-stack-offset
20759     68/push 1/imm32/block-depth
20760     51/push-ecx
20761     68/push 0x11/imm32/alloc-id:fake
20762     68/push 0/imm32/name
20763     68/push 0/imm32/name
20764     68/push 0x11/imm32/alloc-id:fake:payload
20765     89/<- %ecx 4/r32/esp
20766 $test-add-literal-to-reg:initialize-var-name:
20767     # v->name = "v"
20768     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20769     (copy-array Heap "v" %eax)
20770 $test-add-literal-to-reg:initialize-var-register:
20771     # v->register = "ecx"
20772     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20773     (copy-array Heap "ecx" %eax)
20774 $test-add-literal-to-reg:initialize-literal-type:
20775     # var type/edx: (payload type-tree) = literal
20776     68/push 0/imm32/right:null
20777     68/push 0/imm32/right:null
20778     68/push 0/imm32/left:unused
20779     68/push 0/imm32/value:literal
20780     68/push 1/imm32/is-atom?:true
20781     68/push 0x11/imm32/alloc-id:fake:payload
20782     89/<- %edx 4/r32/esp
20783 $test-add-literal-to-reg:initialize-literal:
20784     # var l/edx: (payload var)
20785     68/push 0/imm32/register
20786     68/push 0/imm32/register
20787     68/push 0/imm32/no-stack-offset
20788     68/push 1/imm32/block-depth
20789     52/push-edx
20790     68/push 0x11/imm32/alloc-id:fake
20791     68/push 0/imm32/name
20792     68/push 0/imm32/name
20793     68/push 0x11/imm32/alloc-id:fake:payload
20794     89/<- %edx 4/r32/esp
20795 $test-add-literal-to-reg:initialize-literal-value:
20796     # l->name = "0x34"
20797     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
20798     (copy-array Heap "0x34" %eax)
20799 $test-add-literal-to-reg:initialize-inouts:
20800     # var inouts/esi: (payload stmt-var) = [l]
20801     68/push 0/imm32/is-deref:false
20802     68/push 0/imm32/next
20803     68/push 0/imm32/next
20804     52/push-edx/l
20805     68/push 0x11/imm32/alloc-id:fake
20806     68/push 0x11/imm32/alloc-id:fake:payload
20807     89/<- %esi 4/r32/esp
20808 $test-add-literal-to-reg:initialize-outputs:
20809     # var outputs/edi: (payload stmt-var) = [v]
20810     68/push 0/imm32/is-deref:false
20811     68/push 0/imm32/next
20812     68/push 0/imm32/next
20813     51/push-ecx/v
20814     68/push 0x11/imm32/alloc-id:fake
20815     68/push 0x11/imm32/alloc-id:fake:payload
20816     89/<- %edi 4/r32/esp
20817 $test-add-literal-to-reg:initialize-stmt:
20818     # var stmt/esi: (addr statement)
20819     68/push 0/imm32/next
20820     68/push 0/imm32/next
20821     57/push-edi/outputs
20822     68/push 0x11/imm32/alloc-id:fake
20823     56/push-esi/inouts
20824     68/push 0x11/imm32/alloc-id:fake
20825     68/push 0/imm32/operation
20826     68/push 0/imm32/operation
20827     68/push 1/imm32/tag:stmt1
20828     89/<- %esi 4/r32/esp
20829 $test-add-literal-to-reg:initialize-stmt-operation:
20830     # stmt->operation = "add"
20831     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20832     (copy-array Heap "add" %eax)
20833     # convert
20834     c7 0/subop/copy *Curr-block-depth 0/imm32
20835     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
20836     (flush _test-output-buffered-file)
20837 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20843     # check output
20844     (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg")
20845     # . epilogue
20846     89/<- %esp 5/r32/ebp
20847     5d/pop-to-ebp
20848     c3/return
20849 
20850 test-add-literal-to-mem:
20851     #   add-to var1, 0x34
20852     # =>
20853     #   81 0/subop/add %eax 0x34/imm32
20854     #
20855     # . prologue
20856     55/push-ebp
20857     89/<- %ebp 4/r32/esp
20858     # setup
20859     (clear-stream _test-output-stream)
20860     (clear-stream $_test-output-buffered-file->buffer)
20861 $test-add-literal-to-mem:initialize-type:
20862     # var type/ecx: (payload type-tree) = int
20863     68/push 0/imm32/right:null
20864     68/push 0/imm32/right:null
20865     68/push 0/imm32/left:unused
20866     68/push 1/imm32/value:int
20867     68/push 1/imm32/is-atom?:true
20868     68/push 0x11/imm32/alloc-id:fake:payload
20869     89/<- %ecx 4/r32/esp
20870 $test-add-literal-to-mem:initialize-var1:
20871     # var var1/ecx: (payload var)
20872     68/push 0/imm32/register
20873     68/push 0/imm32/register
20874     68/push 8/imm32/stack-offset
20875     68/push 1/imm32/block-depth
20876     51/push-ecx
20877     68/push 0x11/imm32/alloc-id:fake
20878     68/push 0/imm32/name
20879     68/push 0/imm32/name
20880     68/push 0x11/imm32/alloc-id:fake:payload
20881     89/<- %ecx 4/r32/esp
20882 $test-add-literal-to-mem:initialize-var1-name:
20883     # var1->name = "var1"
20884     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20885     (copy-array Heap "var1" %eax)
20886 $test-add-literal-to-mem:initialize-literal-type:
20887     # var type/edx: (payload type-tree) = literal
20888     68/push 0/imm32/right:null
20889     68/push 0/imm32/right:null
20890     68/push 0/imm32/left:unused
20891     68/push 0/imm32/value:literal
20892     68/push 1/imm32/is-atom?:true
20893     68/push 0x11/imm32/alloc-id:fake:payload
20894     89/<- %edx 4/r32/esp
20895 $test-add-literal-to-mem:initialize-literal:
20896     # var l/edx: (payload var)
20897     68/push 0/imm32/register
20898     68/push 0/imm32/register
20899     68/push 0/imm32/no-stack-offset
20900     68/push 1/imm32/block-depth
20901     52/push-edx
20902     68/push 0x11/imm32/alloc-id:fake
20903     68/push 0/imm32/name
20904     68/push 0/imm32/name
20905     68/push 0x11/imm32/alloc-id:fake:payload
20906     89/<- %edx 4/r32/esp
20907 $test-add-literal-to-mem:initialize-literal-value:
20908     # l->name = "0x34"
20909     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
20910     (copy-array Heap "0x34" %eax)
20911 $test-add-literal-to-mem:initialize-inouts:
20912     # var inouts/esi: (payload stmt-var) = [l]
20913     68/push 0/imm32/is-deref:false
20914     68/push 0/imm32/next
20915     68/push 0/imm32/next
20916     52/push-edx/l
20917     68/push 0x11/imm32/alloc-id:fake
20918     68/push 0x11/imm32/alloc-id:fake:payload
20919     89/<- %esi 4/r32/esp
20920     # var inouts = (handle stmt-var) = [var1, var2]
20921     68/push 0/imm32/is-deref:false
20922     56/push-esi/next
20923     68/push 0x11/imm32/alloc-id:fake
20924     51/push-ecx/var1
20925     68/push 0x11/imm32/alloc-id:fake
20926     68/push 0x11/imm32/alloc-id:fake:payload
20927     89/<- %esi 4/r32/esp
20928 $test-add-literal-to-mem:initialize-stmt:
20929     # var stmt/esi: (addr statement)
20930     68/push 0/imm32/next
20931     68/push 0/imm32/next
20932     68/push 0/imm32/outputs
20933     68/push 0/imm32/outputs
20934     56/push-esi/inouts
20935     68/push 0x11/imm32/alloc-id:fake
20936     68/push 0/imm32/operation
20937     68/push 0/imm32/operation
20938     68/push 1/imm32/tag:stmt1
20939     89/<- %esi 4/r32/esp
20940 $test-add-literal-to-mem:initialize-stmt-operation:
20941     # stmt->operation = "add-to"
20942     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20943     (copy-array Heap "add-to" %eax)
20944     # convert
20945     c7 0/subop/copy *Curr-block-depth 0/imm32
20946     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
20947     (flush _test-output-buffered-file)
20948 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20954     # check output
20955     (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem")
20956     # . epilogue
20957     89/<- %esp 5/r32/ebp
20958     5d/pop-to-ebp
20959     c3/return
20960 
20961 test-shift-reg-by-literal:
20962     #   var1/ecx <- shift-left 2
20963     # =>
20964     #   c1/shift 4/subop/left %ecx 2/imm8
20965     #
20966     # . prologue
20967     55/push-ebp
20968     89/<- %ebp 4/r32/esp
20969     # setup
20970     (clear-stream _test-output-stream)
20971     (clear-stream $_test-output-buffered-file->buffer)
20972 $test-shift-reg-by-literal:initialize-var-type:
20973     # var type/ecx: (payload type-tree) = int
20974     68/push 0/imm32/right:null
20975     68/push 0/imm32/right:null
20976     68/push 0/imm32/left:unused
20977     68/push 1/imm32/value:int
20978     68/push 1/imm32/is-atom?:true
20979     68/push 0x11/imm32/alloc-id:fake:payload
20980     89/<- %ecx 4/r32/esp
20981 $test-shift-reg-by-literal:initialize-var:
20982     # var v/ecx: (payload var)
20983     68/push 0/imm32/register
20984     68/push 0/imm32/register
20985     68/push 0/imm32/no-stack-offset
20986     68/push 1/imm32/block-depth
20987     51/push-ecx
20988     68/push 0x11/imm32/alloc-id:fake
20989     68/push 0/imm32/name
20990     68/push 0/imm32/name
20991     68/push 0x11/imm32/alloc-id:fake:payload
20992     89/<- %ecx 4/r32/esp
20993 $test-shift-reg-by-literal:initialize-var-name:
20994     # v->name = "v"
20995     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20996     (copy-array Heap "v" %eax)
20997 $test-shift-reg-by-literal:initialize-var-register:
20998     # v->register = "ecx"
20999     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21000     (copy-array Heap "ecx" %eax)
21001 $test-shift-reg-by-literal:initialize-literal-type:
21002     # var type/edx: (payload type-tree) = literal
21003     68/push 0/imm32/right:null
21004     68/push 0/imm32/right:null
21005     68/push 0/imm32/left:unused
21006     68/push 0/imm32/value:literal
21007     68/push 1/imm32/is-atom?:true
21008     68/push 0x11/imm32/alloc-id:fake:payload
21009     89/<- %edx 4/r32/esp
21010 $test-shift-reg-by-literal:initialize-literal:
21011     # var l/edx: (payload var)
21012     68/push 0/imm32/register
21013     68/push 0/imm32/register
21014     68/push 0/imm32/no-stack-offset
21015     68/push 1/imm32/block-depth
21016     52/push-edx
21017     68/push 0x11/imm32/alloc-id:fake
21018     68/push 0/imm32/name
21019     68/push 0/imm32/name
21020     68/push 0x11/imm32/alloc-id:fake:payload
21021     89/<- %edx 4/r32/esp
21022 $test-shift-reg-by-literal:initialize-literal-value:
21023     # l->name = "2"
21024     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21025     (copy-array Heap "2" %eax)
21026 $test-shift-reg-by-literal:initialize-inouts:
21027     # var inouts/esi: (payload stmt-var) = [l]
21028     68/push 0/imm32/is-deref:false
21029     68/push 0/imm32/next
21030     68/push 0/imm32/next
21031     52/push-edx/l
21032     68/push 0x11/imm32/alloc-id:fake
21033     68/push 0x11/imm32/alloc-id:fake:payload
21034     89/<- %esi 4/r32/esp
21035 $test-shift-reg-by-literal:initialize-outputs:
21036     # var outputs/edi: (payload stmt-var) = [v]
21037     68/push 0/imm32/is-deref:false
21038     68/push 0/imm32/next
21039     68/push 0/imm32/next
21040     51/push-ecx/v
21041     68/push 0x11/imm32/alloc-id:fake
21042     68/push 0x11/imm32/alloc-id:fake:payload
21043     89/<- %edi 4/r32/esp
21044 $test-shift-reg-by-literal:initialize-stmt:
21045     # var stmt/esi: (addr statement)
21046     68/push 0/imm32/next
21047     68/push 0/imm32/next
21048     57/push-edi/outputs
21049     68/push 0x11/imm32/alloc-id:fake
21050     56/push-esi/inouts
21051     68/push 0x11/imm32/alloc-id:fake
21052     68/push 0/imm32/operation
21053     68/push 0/imm32/operation
21054     68/push 1/imm32/tag:stmt1
21055     89/<- %esi 4/r32/esp
21056 $test-shift-reg-by-literal:initialize-stmt-operation:
21057     # stmt->operation = "shift-left"
21058     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21059     (copy-array Heap "shift-left" %eax)
21060     # convert
21061     c7 0/subop/copy *Curr-block-depth 0/imm32
21062     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21063     (flush _test-output-buffered-file)
21064 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21070     # check output
21071     (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left %ecx 2/imm8" "F - test-shift-reg-by-literal")
21072     # . epilogue
21073     89/<- %esp 5/r32/ebp
21074     5d/pop-to-ebp
21075     c3/return
21076 
21077 test-shift-mem-by-literal:
21078     #   shift-left var 3
21079     # =>
21080     #   c1/shift 4/subop/left *(ebp+8) 3/imm8
21081     #
21082     # . prologue
21083     55/push-ebp
21084     89/<- %ebp 4/r32/esp
21085     # setup
21086     (clear-stream _test-output-stream)
21087     (clear-stream $_test-output-buffered-file->buffer)
21088 $test-shift-mem-by-literal:initialize-type:
21089     # var type/ecx: (payload type-tree) = int
21090     68/push 0/imm32/right:null
21091     68/push 0/imm32/right:null
21092     68/push 0/imm32/left:unused
21093     68/push 1/imm32/value:int
21094     68/push 1/imm32/is-atom?:true
21095     68/push 0x11/imm32/alloc-id:fake:payload
21096     89/<- %ecx 4/r32/esp
21097 $test-shift-mem-by-literal:initialize-var1:
21098     # var var1/ecx: (payload var)
21099     68/push 0/imm32/register
21100     68/push 0/imm32/register
21101     68/push 8/imm32/stack-offset
21102     68/push 1/imm32/block-depth
21103     51/push-ecx
21104     68/push 0x11/imm32/alloc-id:fake
21105     68/push 0/imm32/name
21106     68/push 0/imm32/name
21107     68/push 0x11/imm32/alloc-id:fake:payload
21108     89/<- %ecx 4/r32/esp
21109 $test-shift-mem-by-literal:initialize-var1-name:
21110     # var1->name = "var1"
21111     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21112     (copy-array Heap "var1" %eax)
21113 $test-shift-mem-by-literal:initialize-literal-type:
21114     # var type/edx: (payload type-tree) = literal
21115     68/push 0/imm32/right:null
21116     68/push 0/imm32/right:null
21117     68/push 0/imm32/left:unused
21118     68/push 0/imm32/value:literal
21119     68/push 1/imm32/is-atom?:true
21120     68/push 0x11/imm32/alloc-id:fake:payload
21121     89/<- %edx 4/r32/esp
21122 $test-shift-mem-by-literal:initialize-literal:
21123     # var l/edx: (payload var)
21124     68/push 0/imm32/register
21125     68/push 0/imm32/register
21126     68/push 0/imm32/no-stack-offset
21127     68/push 1/imm32/block-depth
21128     52/push-edx
21129     68/push 0x11/imm32/alloc-id:fake
21130     68/push 0/imm32/name
21131     68/push 0/imm32/name
21132     68/push 0x11/imm32/alloc-id:fake:payload
21133     89/<- %edx 4/r32/esp
21134 $test-shift-mem-by-literal:initialize-literal-value:
21135     # l->name = "3"
21136     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21137     (copy-array Heap "3" %eax)
21138 $test-shift-mem-by-literal:initialize-inouts:
21139     # var inouts/esi: (payload stmt-var) = [l]
21140     68/push 0/imm32/is-deref:false
21141     68/push 0/imm32/next
21142     68/push 0/imm32/next
21143     52/push-edx/l
21144     68/push 0x11/imm32/alloc-id:fake
21145     68/push 0x11/imm32/alloc-id:fake:payload
21146     89/<- %esi 4/r32/esp
21147     # var inouts = (handle stmt-var) = [var1, var2]
21148     68/push 0/imm32/is-deref:false
21149     56/push-esi/next
21150     68/push 0x11/imm32/alloc-id:fake
21151     51/push-ecx/var1
21152     68/push 0x11/imm32/alloc-id:fake
21153     68/push 0x11/imm32/alloc-id:fake:payload
21154     89/<- %esi 4/r32/esp
21155 $test-shift-mem-by-literal:initialize-stmt:
21156     # var stmt/esi: (addr statement)
21157     68/push 0/imm32/next
21158     68/push 0/imm32/next
21159     68/push 0/imm32/outputs
21160     68/push 0/imm32/outputs
21161     56/push-esi/inouts
21162     68/push 0x11/imm32/alloc-id:fake
21163     68/push 0/imm32/operation
21164     68/push 0/imm32/operation
21165     68/push 1/imm32/tag:stmt1
21166     89/<- %esi 4/r32/esp
21167 $test-shift-mem-by-literal:initialize-stmt-operation:
21168     # stmt->operation = "shift-left"
21169     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21170     (copy-array Heap "shift-left" %eax)
21171     # convert
21172     c7 0/subop/copy *Curr-block-depth 0/imm32
21173     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21174     (flush _test-output-buffered-file)
21175 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21181     # check output
21182     (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left *(ebp+0x00000008) 3/imm8" "F - test-shift-mem-by-literal")
21183     # . epilogue
21184     89/<- %esp 5/r32/ebp
21185     5d/pop-to-ebp
21186     c3/return
21187 
21188 test-compare-reg-with-reg:
21189     #   compare var1/ecx, var2/eax
21190     # =>
21191     #   39/compare %ecx 0/r32/eax
21192     #
21193     # . prologue
21194     55/push-ebp
21195     89/<- %ebp 4/r32/esp
21196     # setup
21197     (clear-stream _test-output-stream)
21198     (clear-stream $_test-output-buffered-file->buffer)
21199 $test-compare-reg-with-reg:initialize-type:
21200     # var type/ecx: (payload type-tree) = int
21201     68/push 0/imm32/right:null
21202     68/push 0/imm32/right:null
21203     68/push 0/imm32/left:unused
21204     68/push 1/imm32/value:int
21205     68/push 1/imm32/is-atom?:true
21206     68/push 0x11/imm32/alloc-id:fake:payload
21207     89/<- %ecx 4/r32/esp
21208 $test-compare-reg-with-reg:initialize-var1:
21209     # var var1/ecx: (payload var)
21210     68/push 0/imm32/register
21211     68/push 0/imm32/register
21212     68/push 0/imm32/no-stack-offset
21213     68/push 1/imm32/block-depth
21214     51/push-ecx
21215     68/push 0x11/imm32/alloc-id:fake
21216     68/push 0/imm32/name
21217     68/push 0/imm32/name
21218     68/push 0x11/imm32/alloc-id:fake:payload
21219     89/<- %ecx 4/r32/esp
21220 $test-compare-reg-with-reg:initialize-var1-name:
21221     # var1->name = "var1"
21222     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21223     (copy-array Heap "var1" %eax)
21224 $test-compare-reg-with-reg:initialize-var1-register:
21225     # var1->register = "ecx"
21226     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21227     (copy-array Heap "ecx" %eax)
21228 $test-compare-reg-with-reg:initialize-var2:
21229     # var var2/edx: (payload var)
21230     68/push 0/imm32/register
21231     68/push 0/imm32/register
21232     68/push 0/imm32/no-stack-offset
21233     68/push 1/imm32/block-depth
21234     ff 6/subop/push *(ecx+0x10)
21235     68/push 0x11/imm32/alloc-id:fake
21236     68/push 0/imm32/name
21237     68/push 0/imm32/name
21238     68/push 0x11/imm32/alloc-id:fake:payload
21239     89/<- %edx 4/r32/esp
21240 $test-compare-reg-with-reg:initialize-var2-name:
21241     # var2->name = "var2"
21242     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21243     (copy-array Heap "var2" %eax)
21244 $test-compare-reg-with-reg:initialize-var2-register:
21245     # var2->register = "eax"
21246     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
21247     (copy-array Heap "eax" %eax)
21248 $test-compare-reg-with-reg:initialize-inouts:
21249     # var inouts/esi: (payload stmt-var) = [var2]
21250     68/push 0/imm32/is-deref:false
21251     68/push 0/imm32/next
21252     68/push 0/imm32/next
21253     52/push-edx/var2
21254     68/push 0x11/imm32/alloc-id:fake
21255     68/push 0x11/imm32/alloc-id:fake:payload
21256     89/<- %esi 4/r32/esp
21257     # inouts = [var1, var2]
21258     68/push 0/imm32/is-deref:false
21259     56/push-esi/next
21260     68/push 0x11/imm32/alloc-id:fake
21261     51/push-ecx/var1
21262     68/push 0x11/imm32/alloc-id:fake
21263     68/push 0x11/imm32/alloc-id:fake:payload
21264     89/<- %esi 4/r32/esp
21265 $test-compare-reg-with-reg:initialize-stmt:
21266     # var stmt/esi: (addr statement)
21267     68/push 0/imm32/next
21268     68/push 0/imm32/next
21269     68/push 0/imm32/outputs
21270     68/push 0/imm32/outputs
21271     56/push-esi/inouts
21272     68/push 0x11/imm32/alloc-id:fake
21273     68/push 0/imm32/operation
21274     68/push 0/imm32/operation
21275     68/push 1/imm32/tag:stmt1
21276     89/<- %esi 4/r32/esp
21277 $test-compare-reg-with-reg:initialize-stmt-operation:
21278     # stmt->operation = "compare"
21279     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21280     (copy-array Heap "compare" %eax)
21281     # convert
21282     c7 0/subop/copy *Curr-block-depth 0/imm32
21283     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21284     (flush _test-output-buffered-file)
21285 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21291     # check output
21292     (check-next-stream-line-equal _test-output-stream "39/compare-> %ecx 0x00000000/r32" "F - test-compare-reg-with-reg")
21293     # . epilogue
21294     89/<- %esp 5/r32/ebp
21295     5d/pop-to-ebp
21296     c3/return
21297 
21298 test-compare-mem-with-reg:
21299     #   compare var1, var2/eax
21300     # =>
21301     #   39/compare *(ebp+___) 0/r32/eax
21302     #
21303     # . prologue
21304     55/push-ebp
21305     89/<- %ebp 4/r32/esp
21306     # setup
21307     (clear-stream _test-output-stream)
21308     (clear-stream $_test-output-buffered-file->buffer)
21309 $test-compare-mem-with-reg:initialize-type:
21310     # var type/ecx: (payload type-tree) = int
21311     68/push 0/imm32/right:null
21312     68/push 0/imm32/right:null
21313     68/push 0/imm32/left:unused
21314     68/push 1/imm32/value:int
21315     68/push 1/imm32/is-atom?:true
21316     68/push 0x11/imm32/alloc-id:fake:payload
21317     89/<- %ecx 4/r32/esp
21318 $test-compare-mem-with-reg:initialize-var1:
21319     # var var1/ecx: (payload var)
21320     68/push 0/imm32/register
21321     68/push 0/imm32/register
21322     68/push 8/imm32/stack-offset
21323     68/push 1/imm32/block-depth
21324     51/push-ecx
21325     68/push 0x11/imm32/alloc-id:fake
21326     68/push 0/imm32/name
21327     68/push 0/imm32/name
21328     68/push 0x11/imm32/alloc-id:fake:payload
21329     89/<- %ecx 4/r32/esp
21330 $test-compare-mem-with-reg:initialize-var1-name:
21331     # var1->name = "var1"
21332     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21333     (copy-array Heap "var1" %eax)
21334 $test-compare-mem-with-reg:initialize-var2:
21335     # var var2/edx: (payload var)
21336     68/push 0/imm32/register
21337     68/push 0/imm32/register
21338     68/push 0/imm32/no-stack-offset
21339     68/push 1/imm32/block-depth
21340     ff 6/subop/push *(ecx+0x10)
21341     68/push 0x11/imm32/alloc-id:fake
21342     68/push 0/imm32/name
21343     68/push 0/imm32/name
21344     68/push 0x11/imm32/alloc-id:fake:payload
21345     89/<- %edx 4/r32/esp
21346 $test-compare-mem-with-reg:initialize-var2-name:
21347     # var2->name = "var2"
21348     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21349     (copy-array Heap "var2" %eax)
21350 $test-compare-mem-with-reg:initialize-var2-register:
21351     # var2->register = "eax"
21352     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
21353     (copy-array Heap "eax" %eax)
21354 $test-compare-mem-with-reg:initialize-inouts:
21355     # var inouts/esi: (payload stmt-var) = [var2]
21356     68/push 0/imm32/is-deref:false
21357     68/push 0/imm32/next
21358     68/push 0/imm32/next
21359     52/push-edx/var2
21360     68/push 0x11/imm32/alloc-id:fake
21361     68/push 0x11/imm32/alloc-id:fake:payload
21362     89/<- %esi 4/r32/esp
21363     # inouts = [var1, var2]
21364     68/push 0/imm32/is-deref:false
21365     56/push-esi/next
21366     68/push 0x11/imm32/alloc-id:fake
21367     51/push-ecx/var1
21368     68/push 0x11/imm32/alloc-id:fake
21369     68/push 0x11/imm32/alloc-id:fake:payload
21370     89/<- %esi 4/r32/esp
21371 $test-compare-mem-with-reg:initialize-stmt:
21372     # var stmt/esi: (addr statement)
21373     68/push 0/imm32/next
21374     68/push 0/imm32/next
21375     68/push 0/imm32/outputs
21376     68/push 0/imm32/outputs
21377     56/push-esi/inouts
21378     68/push 0x11/imm32/alloc-id:fake
21379     68/push 0/imm32/operation
21380     68/push 0/imm32/operation
21381     68/push 1/imm32/tag:stmt1
21382     89/<- %esi 4/r32/esp
21383 $test-compare-mem-with-reg:initialize-stmt-operation:
21384     # stmt->operation = "compare"
21385     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21386     (copy-array Heap "compare" %eax)
21387     # convert
21388     c7 0/subop/copy *Curr-block-depth 0/imm32
21389     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21390     (flush _test-output-buffered-file)
21391 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21397     # check output
21398     (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg")
21399     # . epilogue
21400     89/<- %esp 5/r32/ebp
21401     5d/pop-to-ebp
21402     c3/return
21403 
21404 test-compare-reg-with-mem:
21405     #   compare var1/eax, var2
21406     # =>
21407     #   3b/compare<- *(ebp+___) 0/r32/eax
21408     #
21409     # . prologue
21410     55/push-ebp
21411     89/<- %ebp 4/r32/esp
21412     # setup
21413     (clear-stream _test-output-stream)
21414     (clear-stream $_test-output-buffered-file->buffer)
21415 $test-compare-reg-with-mem:initialize-type:
21416     # var type/ecx: (payload type-tree) = int
21417     68/push 0/imm32/right:null
21418     68/push 0/imm32/right:null
21419     68/push 0/imm32/left:unused
21420     68/push 1/imm32/value:int
21421     68/push 1/imm32/is-atom?:true
21422     68/push 0x11/imm32/alloc-id:fake:payload
21423     89/<- %ecx 4/r32/esp
21424 $test-compare-reg-with-mem:initialize-var1:
21425     # var var1/ecx: (payload var)
21426     68/push 0/imm32/register
21427     68/push 0/imm32/register
21428     68/push 0/imm32/no-stack-offset
21429     68/push 1/imm32/block-depth
21430     51/push-ecx
21431     68/push 0x11/imm32/alloc-id:fake
21432     68/push 0/imm32/name
21433     68/push 0/imm32/name
21434     68/push 0x11/imm32/alloc-id:fake:payload
21435     89/<- %ecx 4/r32/esp
21436 $test-compare-reg-with-mem:initialize-var1-name:
21437     # var1->name = "var1"
21438     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21439     (copy-array Heap "var1" %eax)
21440 $test-compare-reg-with-mem:initialize-var1-register:
21441     # var1->register = "eax"
21442     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21443     (copy-array Heap "eax" %eax)
21444 $test-compare-reg-with-mem:initialize-var2:
21445     # var var2/edx: (payload var)
21446     68/push 0/imm32/register
21447     68/push 0/imm32/register
21448     68/push 8/imm32/stack-offset
21449     68/push 1/imm32/block-depth
21450     ff 6/subop/push *(ecx+0x10)
21451     68/push 0x11/imm32/alloc-id:fake
21452     68/push 0/imm32/name
21453     68/push 0/imm32/name
21454     68/push 0x11/imm32/alloc-id:fake:payload
21455     89/<- %edx 4/r32/esp
21456 $test-compare-reg-with-mem:initialize-var2-name:
21457     # var2->name = "var2"
21458     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21459     (copy-array Heap "var2" %eax)
21460 $test-compare-reg-with-mem:initialize-inouts:
21461     # var inouts/esi: (payload stmt-var) = [var2]
21462     68/push 0/imm32/is-deref:false
21463     68/push 0/imm32/next
21464     68/push 0/imm32/next
21465     52/push-edx/var2
21466     68/push 0x11/imm32/alloc-id:fake
21467     68/push 0x11/imm32/alloc-id:fake:payload
21468     89/<- %esi 4/r32/esp
21469     # inouts = [var1, var2]
21470     68/push 0/imm32/is-deref:false
21471     56/push-esi/next
21472     68/push 0x11/imm32/alloc-id:fake
21473     51/push-ecx/var1
21474     68/push 0x11/imm32/alloc-id:fake
21475     68/push 0x11/imm32/alloc-id:fake:payload
21476     89/<- %esi 4/r32/esp
21477 $test-compare-reg-with-mem:initialize-stmt:
21478     # var stmt/esi: (addr statement)
21479     68/push 0/imm32/next
21480     68/push 0/imm32/next
21481     68/push 0/imm32/outputs
21482     68/push 0/imm32/outputs
21483     56/push-esi/inouts
21484     68/push 0x11/imm32/alloc-id:fake
21485     68/push 0/imm32/operation
21486     68/push 0/imm32/operation
21487     68/push 1/imm32/tag:stmt1
21488     89/<- %esi 4/r32/esp
21489 $test-compare-reg-with-mem:initialize-stmt-operation:
21490     # stmt->operation = "compare"
21491     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21492     (copy-array Heap "compare" %eax)
21493     # convert
21494     c7 0/subop/copy *Curr-block-depth 0/imm32
21495     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21496     (flush _test-output-buffered-file)
21497 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21503     # check output
21504     (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem")
21505     # . epilogue
21506     89/<- %esp 5/r32/ebp
21507     5d/pop-to-ebp
21508     c3/return
21509 
21510 test-compare-mem-with-literal:
21511     #   compare var1, 0x34
21512     # =>
21513     #   81 7/subop/compare *(ebp+___) 0x34/imm32
21514     #
21515     # . prologue
21516     55/push-ebp
21517     89/<- %ebp 4/r32/esp
21518     # setup
21519     (clear-stream _test-output-stream)
21520     (clear-stream $_test-output-buffered-file->buffer)
21521 $test-compare-mem-with-literal:initialize-type:
21522     # var type/ecx: (payload type-tree) = int
21523     68/push 0/imm32/right:null
21524     68/push 0/imm32/right:null
21525     68/push 0/imm32/left:unused
21526     68/push 1/imm32/value:int
21527     68/push 1/imm32/is-atom?:true
21528     68/push 0x11/imm32/alloc-id:fake:payload
21529     89/<- %ecx 4/r32/esp
21530 $test-compare-mem-with-literal:initialize-var1:
21531     # var var1/ecx: (payload var)
21532     68/push 0/imm32/register
21533     68/push 0/imm32/register
21534     68/push 8/imm32/stack-offset
21535     68/push 1/imm32/block-depth
21536     51/push-ecx
21537     68/push 0x11/imm32/alloc-id:fake
21538     68/push 0/imm32/name
21539     68/push 0/imm32/name
21540     68/push 0x11/imm32/alloc-id:fake:payload
21541     89/<- %ecx 4/r32/esp
21542 $test-compare-mem-with-literal:initialize-var1-name:
21543     # var1->name = "var1"
21544     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21545     (copy-array Heap "var1" %eax)
21546 $test-compare-mem-with-literal:initialize-literal-type:
21547     # var type/edx: (payload type-tree) = literal
21548     68/push 0/imm32/right:null
21549     68/push 0/imm32/right:null
21550     68/push 0/imm32/left:unused
21551     68/push 0/imm32/value:literal
21552     68/push 1/imm32/is-atom?:true
21553     68/push 0x11/imm32/alloc-id:fake:payload
21554     89/<- %edx 4/r32/esp
21555 $test-compare-mem-with-literal:initialize-literal:
21556     # var l/edx: (payload var)
21557     68/push 0/imm32/register
21558     68/push 0/imm32/register
21559     68/push 0/imm32/no-stack-offset
21560     68/push 1/imm32/block-depth
21561     52/push-edx
21562     68/push 0x11/imm32/alloc-id:fake
21563     68/push 0/imm32/name
21564     68/push 0/imm32/name
21565     68/push 0x11/imm32/alloc-id:fake:payload
21566     89/<- %edx 4/r32/esp
21567 $test-compare-mem-with-literal:initialize-literal-value:
21568     # l->name = "0x34"
21569     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21570     (copy-array Heap "0x34" %eax)
21571 $test-compare-mem-with-literal:initialize-inouts:
21572     # var inouts/esi: (payload stmt-var) = [l]
21573     68/push 0/imm32/is-deref:false
21574     68/push 0/imm32/next
21575     68/push 0/imm32/next
21576     52/push-edx/l
21577     68/push 0x11/imm32/alloc-id:fake
21578     68/push 0x11/imm32/alloc-id:fake:payload
21579     89/<- %esi 4/r32/esp
21580     # var inouts = (handle stmt-var) = [var1, var2]
21581     68/push 0/imm32/is-deref:false
21582     56/push-esi/next
21583     68/push 0x11/imm32/alloc-id:fake
21584     51/push-ecx/var1
21585     68/push 0x11/imm32/alloc-id:fake
21586     68/push 0x11/imm32/alloc-id:fake:payload
21587     89/<- %esi 4/r32/esp
21588 $test-compare-mem-with-literal:initialize-stmt:
21589     # var stmt/esi: (addr statement)
21590     68/push 0/imm32/next
21591     68/push 0/imm32/next
21592     68/push 0/imm32/outputs
21593     68/push 0/imm32/outputs
21594     56/push-esi/inouts
21595     68/push 0x11/imm32/alloc-id:fake
21596     68/push 0/imm32/operation
21597     68/push 0/imm32/operation
21598     68/push 1/imm32/tag:stmt1
21599     89/<- %esi 4/r32/esp
21600 $test-compare-mem-with-literal:initialize-stmt-operation:
21601     # stmt->operation = "compare"
21602     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21603     (copy-array Heap "compare" %eax)
21604     # convert
21605     c7 0/subop/copy *Curr-block-depth 0/imm32
21606     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21607     (flush _test-output-buffered-file)
21608 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21614     # check output
21615     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal")
21616     # . epilogue
21617     89/<- %esp 5/r32/ebp
21618     5d/pop-to-ebp
21619     c3/return
21620 
21621 test-compare-eax-with-literal:
21622     #   compare var1/eax 0x34
21623     # =>
21624     #   3d/compare-eax-with 0x34/imm32
21625     #
21626     # . prologue
21627     55/push-ebp
21628     89/<- %ebp 4/r32/esp
21629     # setup
21630     (clear-stream _test-output-stream)
21631     (clear-stream $_test-output-buffered-file->buffer)
21632 $test-compare-eax-with-literal:initialize-type:
21633     # var type/ecx: (payload type-tree) = int
21634     68/push 0/imm32/right:null
21635     68/push 0/imm32/right:null
21636     68/push 0/imm32/left:unused
21637     68/push 1/imm32/value:int
21638     68/push 1/imm32/is-atom?:true
21639     68/push 0x11/imm32/alloc-id:fake:payload
21640     89/<- %ecx 4/r32/esp
21641 $test-compare-eax-with-literal:initialize-var1:
21642     # var var1/ecx: (payload var)
21643     68/push 0/imm32/register
21644     68/push 0/imm32/register
21645     68/push 0/imm32/no-stack-offset
21646     68/push 1/imm32/block-depth
21647     51/push-ecx
21648     68/push 0x11/imm32/alloc-id:fake
21649     68/push 0/imm32/name
21650     68/push 0/imm32/name
21651     68/push 0x11/imm32/alloc-id:fake:payload
21652     89/<- %ecx 4/r32/esp
21653 $test-compare-eax-with-literal:initialize-var1-name:
21654     # var1->name = "var1"
21655     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21656     (copy-array Heap "var1" %eax)
21657 $test-compare-eax-with-literal:initialize-var1-register:
21658     # v->register = "eax"
21659     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21660     (copy-array Heap "eax" %eax)
21661 $test-compare-eax-with-literal:initialize-literal-type:
21662     # var type/edx: (payload type-tree) = literal
21663     68/push 0/imm32/right:null
21664     68/push 0/imm32/right:null
21665     68/push 0/imm32/left:unused
21666     68/push 0/imm32/value:literal
21667     68/push 1/imm32/is-atom?:true
21668     68/push 0x11/imm32/alloc-id:fake:payload
21669     89/<- %edx 4/r32/esp
21670 $test-compare-eax-with-literal:initialize-literal:
21671     # var l/edx: (payload var)
21672     68/push 0/imm32/register
21673     68/push 0/imm32/register
21674     68/push 0/imm32/no-stack-offset
21675     68/push 1/imm32/block-depth
21676     52/push-edx
21677     68/push 0x11/imm32/alloc-id:fake
21678     68/push 0/imm32/name
21679     68/push 0/imm32/name
21680     68/push 0x11/imm32/alloc-id:fake:payload
21681     89/<- %edx 4/r32/esp
21682 $test-compare-eax-with-literal:initialize-literal-value:
21683     # l->name = "0x34"
21684     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21685     (copy-array Heap "0x34" %eax)
21686 $test-compare-eax-with-literal:initialize-inouts:
21687     # var inouts/esi: (payload stmt-var) = [l]
21688     68/push 0/imm32/is-deref:false
21689     68/push 0/imm32/next
21690     68/push 0/imm32/next
21691     52/push-edx/l
21692     68/push 0x11/imm32/alloc-id:fake
21693     68/push 0x11/imm32/alloc-id:fake:payload
21694     89/<- %esi 4/r32/esp
21695     # var inouts = (handle stmt-var) = [var1, var2]
21696     68/push 0/imm32/is-deref:false
21697     56/push-esi/next
21698     68/push 0x11/imm32/alloc-id:fake
21699     51/push-ecx/var1
21700     68/push 0x11/imm32/alloc-id:fake
21701     68/push 0x11/imm32/alloc-id:fake:payload
21702     89/<- %esi 4/r32/esp
21703 $test-compare-eax-with-literal:initialize-stmt:
21704     # var stmt/esi: (addr statement)
21705     68/push 0/imm32/next
21706     68/push 0/imm32/next
21707     68/push 0/imm32/outputs
21708     68/push 0/imm32/outputs
21709     56/push-esi/inouts
21710     68/push 0x11/imm32/alloc-id:fake
21711     68/push 0/imm32/operation
21712     68/push 0/imm32/operation
21713     68/push 1/imm32/tag:stmt1
21714     89/<- %esi 4/r32/esp
21715 $test-compare-eax-with-literal:initialize-stmt-operation:
21716     # stmt->operation = "compare"
21717     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21718     (copy-array Heap "compare" %eax)
21719     # convert
21720     c7 0/subop/copy *Curr-block-depth 0/imm32
21721     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21722     (flush _test-output-buffered-file)
21723 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21729     # check output
21730     (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal")
21731     # . epilogue
21732     89/<- %esp 5/r32/ebp
21733     5d/pop-to-ebp
21734     c3/return
21735 
21736 test-compare-reg-with-literal:
21737     #   compare var1/ecx 0x34
21738     # =>
21739     #   81 7/subop/compare %ecx 0x34/imm32
21740     #
21741     # . prologue
21742     55/push-ebp
21743     89/<- %ebp 4/r32/esp
21744     # setup
21745     (clear-stream _test-output-stream)
21746     (clear-stream $_test-output-buffered-file->buffer)
21747 $test-compare-reg-with-literal:initialize-type:
21748     # var type/ecx: (payload type-tree) = int
21749     68/push 0/imm32/right:null
21750     68/push 0/imm32/right:null
21751     68/push 0/imm32/left:unused
21752     68/push 1/imm32/value:int
21753     68/push 1/imm32/is-atom?:true
21754     68/push 0x11/imm32/alloc-id:fake:payload
21755     89/<- %ecx 4/r32/esp
21756 $test-compare-reg-with-literal:initialize-var1:
21757     # var var1/ecx: (payload var)
21758     68/push 0/imm32/register
21759     68/push 0/imm32/register
21760     68/push 0/imm32/no-stack-offset
21761     68/push 1/imm32/block-depth
21762     51/push-ecx
21763     68/push 0x11/imm32/alloc-id:fake
21764     68/push 0/imm32/name
21765     68/push 0/imm32/name
21766     68/push 0x11/imm32/alloc-id:fake:payload
21767     89/<- %ecx 4/r32/esp
21768 $test-compare-reg-with-literal:initialize-var1-name:
21769     # var1->name = "var1"
21770     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21771     (copy-array Heap "var1" %eax)
21772 $test-compare-reg-with-literal:initialize-var1-register:
21773     # v->register = "ecx"
21774     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21775     (copy-array Heap "ecx" %eax)
21776 $test-compare-reg-with-literal:initialize-literal-type:
21777     # var type/edx: (payload type-tree) = literal
21778     68/push 0/imm32/right:null
21779     68/push 0/imm32/right:null
21780     68/push 0/imm32/left:unused
21781     68/push 0/imm32/value:literal
21782     68/push 1/imm32/is-atom?:true
21783     68/push 0x11/imm32/alloc-id:fake:payload
21784     89/<- %edx 4/r32/esp
21785 $test-compare-reg-with-literal:initialize-literal:
21786     # var l/edx: (payload var)
21787     68/push 0/imm32/register
21788     68/push 0/imm32/register
21789     68/push 0/imm32/no-stack-offset
21790     68/push 1/imm32/block-depth
21791     52/push-edx
21792     68/push 0x11/imm32/alloc-id:fake
21793     68/push 0/imm32/name
21794     68/push 0/imm32/name
21795     68/push 0x11/imm32/alloc-id:fake:payload
21796     89/<- %edx 4/r32/esp
21797 $test-compare-reg-with-literal:initialize-literal-value:
21798     # l->name = "0x34"
21799     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21800     (copy-array Heap "0x34" %eax)
21801 $test-compare-reg-with-literal:initialize-inouts:
21802     # var inouts/esi: (payload stmt-var) = [l]
21803     68/push 0/imm32/is-deref:false
21804     68/push 0/imm32/next
21805     68/push 0/imm32/next
21806     52/push-edx/l
21807     68/push 0x11/imm32/alloc-id:fake
21808     68/push 0x11/imm32/alloc-id:fake:payload
21809     89/<- %esi 4/r32/esp
21810     # var inouts = (handle stmt-var) = [var1, var2]
21811     68/push 0/imm32/is-deref:false
21812     56/push-esi/next
21813     68/push 0x11/imm32/alloc-id:fake
21814     51/push-ecx/var1
21815     68/push 0x11/imm32/alloc-id:fake
21816     68/push 0x11/imm32/alloc-id:fake:payload
21817     89/<- %esi 4/r32/esp
21818 $test-compare-reg-with-literal:initialize-stmt:
21819     # var stmt/esi: (addr statement)
21820     68/push 0/imm32/next
21821     68/push 0/imm32/next
21822     68/push 0/imm32/outputs
21823     68/push 0/imm32/outputs
21824     56/push-esi/inouts
21825     68/push 0x11/imm32/alloc-id:fake
21826     68/push 0/imm32/operation
21827     68/push 0/imm32/operation
21828     68/push 1/imm32/tag:stmt1
21829     89/<- %esi 4/r32/esp
21830 $test-compare-reg-with-literal:initialize-stmt-operation:
21831     # stmt->operation = "compare"
21832     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21833     (copy-array Heap "compare" %eax)
21834     # convert
21835     c7 0/subop/copy *Curr-block-depth 0/imm32
21836     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21837     (flush _test-output-buffered-file)
21838 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21844     # check output
21845     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal")
21846     # . epilogue
21847     89/<- %esp 5/r32/ebp
21848     5d/pop-to-ebp
21849     c3/return
21850 
21851 test-emit-subx-stmt-function-call:
21852     # Call a function on a variable on the stack.
21853     #   f foo
21854     # =>
21855     #   (f *(ebp-8))
21856     # (Changing the function name supports overloading in general, but here it
21857     # just serves to help disambiguate things.)
21858     #
21859     # There's a variable on the var stack as follows:
21860     #   name: 'foo'
21861     #   type: int
21862     #   stack-offset: -8
21863     #
21864     # There's nothing in primitives.
21865     #
21866     # We don't perform any checking here on the type of 'f'.
21867     #
21868     # . prologue
21869     55/push-ebp
21870     89/<- %ebp 4/r32/esp
21871     # setup
21872     (clear-stream _test-output-stream)
21873     (clear-stream $_test-output-buffered-file->buffer)
21874 $test-emit-subx-function-call:initialize-type:
21875     # var type/ecx: (payload type-tree) = int
21876     68/push 0/imm32/right:null
21877     68/push 0/imm32/right:null
21878     68/push 0/imm32/left:unused
21879     68/push 1/imm32/value:int
21880     68/push 1/imm32/is-atom?:true
21881     68/push 0x11/imm32/alloc-id:fake:payload
21882     89/<- %ecx 4/r32/esp
21883 $test-emit-subx-function-call:initialize-var:
21884     # var var-foo/ecx: (payload var) = var(type)
21885     68/push 0/imm32/no-register
21886     68/push 0/imm32/no-register
21887     68/push -8/imm32/stack-offset
21888     68/push 1/imm32/block-depth
21889     51/push-ecx/type
21890     68/push 0x11/imm32/alloc-id:fake
21891     68/push 0/imm32/name
21892     68/push 0/imm32/name
21893     68/push 0x11/imm32/alloc-id:fake:payload
21894     89/<- %ecx 4/r32/esp
21895 $test-emit-subx-function-call:initialize-var-name:
21896     # var-foo->name = "foo"
21897     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21898     (copy-array Heap "foo" %eax)
21899 $test-emit-subx-function-call:initialize-stmt-var:
21900     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
21901     68/push 0/imm32/is-deref:false
21902     68/push 0/imm32/next
21903     68/push 0/imm32/next
21904     51/push-ecx/var-foo
21905     68/push 0x11/imm32/alloc-id:fake
21906     68/push 0x11/imm32/alloc-id:fake:payload
21907     89/<- %ebx 4/r32/esp
21908 $test-emit-subx-function-call:initialize-stmt:
21909     # var stmt/esi: (addr statement)
21910     68/push 0/imm32/no-outputs
21911     68/push 0/imm32/no-outputs
21912     53/push-ebx/inouts
21913     68/push 0x11/imm32/alloc-id:fake
21914     68/push 0/imm32/operation
21915     68/push 0/imm32/operation
21916     68/push 1/imm32/tag
21917     89/<- %esi 4/r32/esp
21918 $test-emit-subx-function-call:initialize-stmt-operation:
21919     # stmt->operation = "f"
21920     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21921     (copy-array Heap "f" %eax)
21922     # convert
21923     c7 0/subop/copy *Curr-block-depth 0/imm32
21924     (emit-subx-stmt _test-output-buffered-file %esi 0 Stderr 0)
21925     (flush _test-output-buffered-file)
21926 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21932     # check output
21933     (check-next-stream-line-equal _test-output-stream "(f *(ebp+0xfffffff8))" "F - test-emit-subx-stmt-function-call")
21934     # . epilogue
21935     89/<- %esp 5/r32/ebp
21936     5d/pop-to-ebp
21937     c3/return
21938 
21939 test-emit-subx-stmt-function-call-with-literal-arg:
21940     # Call a function on a literal.
21941     #   f 0x34
21942     # =>
21943     #   (f2 0x34)
21944     #
21945     # . prologue
21946     55/push-ebp
21947     89/<- %ebp 4/r32/esp
21948     # setup
21949     (clear-stream _test-output-stream)
21950     (clear-stream $_test-output-buffered-file->buffer)
21951 $test-emit-subx-function-call-with-literal-arg:initialize-type:
21952     # var type/ecx: (payload type-tree) = int
21953     68/push 0/imm32/right:null
21954     68/push 0/imm32/right:null
21955     68/push 0/imm32/left:unused
21956     68/push 0/imm32/value:literal
21957     68/push 1/imm32/is-atom?:true
21958     68/push 0x11/imm32/alloc-id:fake:payload
21959     89/<- %ecx 4/r32/esp
21960 $test-emit-subx-function-call-with-literal-arg:initialize-var:
21961     # var var-foo/ecx: (payload var) = var(lit)
21962     68/push 0/imm32/no-register
21963     68/push 0/imm32/no-register
21964     68/push 0/imm32/no-stack-offset
21965     68/push 1/imm32/block-depth
21966     51/push-ecx/type
21967     68/push 0x11/imm32/alloc-id:fake
21968     68/push 0/imm32/name
21969     68/push 0/imm32/name
21970     68/push 0x11/imm32/alloc-id:fake:payload
21971     89/<- %ecx 4/r32/esp
21972 $test-emit-subx-function-call-with-literal-arg:initialize-var-name:
21973     # var-foo->name = "0x34"
21974     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21975     (copy-array Heap "0x34" %eax)
21976 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-var:
21977     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
21978     68/push 0/imm32/is-deref:false
21979     68/push 0/imm32/next
21980     68/push 0/imm32/next
21981     51/push-ecx/var-foo
21982     68/push 0x11/imm32/alloc-id:fake
21983     68/push 0x11/imm32/alloc-id:fake:payload
21984     89/<- %ebx 4/r32/esp
21985 $test-emit-subx-function-call-with-literal-arg:initialize-stmt:
21986     # var stmt/esi: (addr statement)
21987     68/push 0/imm32/no-outputs
21988     68/push 0/imm32/no-outputs
21989     53/push-ebx/inouts
21990     68/push 0x11/imm32/alloc-id:fake
21991     68/push 0/imm32/operation
21992     68/push 0/imm32/operation
21993     68/push 1/imm32/tag
21994     89/<- %esi 4/r32/esp
21995 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-operation:
21996     # stmt->operation = "f"
21997     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21998     (copy-array Heap "f" %eax)
21999     # convert
22000     c7 0/subop/copy *Curr-block-depth 0/imm32
22001     (emit-subx-stmt _test-output-buffered-file %esi 0 %ebx Stderr 0)
22002     (flush _test-output-buffered-file)
22003 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22009     # check output
22010     (check-next-stream-line-equal _test-output-stream "(f 0x34)" "F - test-emit-subx-stmt-function-call-with-literal-arg")
22011     # . epilogue
22012     89/<- %esp 5/r32/ebp
22013     5d/pop-to-ebp
22014     c3/return
22015 
22016 emit-indent:  # out: (addr buffered-file), n: int
22017     # . prologue
22018     55/push-ebp
22019     89/<- %ebp 4/r32/esp
22020     # . save registers
22021     50/push-eax
22022     # var i/eax: int = n
22023     8b/-> *(ebp+0xc) 0/r32/eax
22024     {
22025       # if (i <= 0) break
22026       3d/compare-eax-with 0/imm32
22027       7e/jump-if-<= break/disp8
22028       (write-buffered *(ebp+8) "  ")
22029       48/decrement-eax
22030       eb/jump loop/disp8
22031     }
22032 $emit-indent:end:
22033     # . restore registers
22034     58/pop-to-eax
22035     # . epilogue
22036     89/<- %esp 5/r32/ebp
22037     5d/pop-to-ebp
22038     c3/return
22039 
22040 emit-subx-prologue:  # out: (addr buffered-file)
22041     # . prologue
22042     55/push-ebp
22043     89/<- %ebp 4/r32/esp
22044     #
22045     (write-buffered *(ebp+8) "  # . prologue\n")
22046     (write-buffered *(ebp+8) "  55/push-ebp\n")
22047     (write-buffered *(ebp+8) "  89/<- %ebp 4/r32/esp\n")
22048 $emit-subx-prologue:end:
22049     # . epilogue
22050     89/<- %esp 5/r32/ebp
22051     5d/pop-to-ebp
22052     c3/return
22053 
22054 emit-subx-epilogue:  # out: (addr buffered-file)
22055     # . prologue
22056     55/push-ebp
22057     89/<- %ebp 4/r32/esp
22058     #
22059     (write-buffered *(ebp+8) "  # . epilogue\n")
22060     (write-buffered *(ebp+8) "  89/<- %esp 5/r32/ebp\n")
22061     (write-buffered *(ebp+8) "  5d/pop-to-ebp\n")
22062     (write-buffered *(ebp+8) "  c3/return\n")
22063 $emit-subx-epilogue:end:
22064     # . epilogue
22065     89/<- %esp 5/r32/ebp
22066     5d/pop-to-ebp
22067     c3/return